/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * * Copyright 2006 - 2016 Pentaho Corporation. All rights reserved. */ package org.pentaho.platform.repository.solution.dbbased; import org.pentaho.platform.api.engine.IAclSolutionFile; import org.pentaho.platform.api.engine.IFileFilter; import org.pentaho.platform.api.engine.IPentahoAclEntry; import org.pentaho.platform.api.engine.IPentahoAclObjectIdentity; import org.pentaho.platform.api.engine.ISolutionFile; import org.pentaho.platform.api.repository.ISearchable; import org.pentaho.platform.repository.messages.Messages; import org.pentaho.platform.util.UUIDUtil; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; @SuppressWarnings( "deprecation" ) public class RepositoryFile implements ISearchable, Comparable, IPentahoAclObjectIdentity, IAclSolutionFile, ISolutionFile { public static final char EXTENSION_CHAR = '.'; private static final long serialVersionUID = -4129429077568560627L; private static final String EMPTY_STRING = ""; //$NON-NLS-1$ private static final String[] SearchableColumns = { Messages.getInstance().getString( "SolutionRepository.QUERY_COLUMN_NAME" ), //$NON-NLS-1$ Messages.getInstance().getString( "SolutionRepository.QUERY_COLUMN_PATH" ), //$NON-NLS-1$ Messages.getInstance().getString( "SolutionRepository.QUERY_COLUMN_PARENT" ) //$NON-NLS-1$ }; private static final String SearchableTable = "org.pentaho.platform.repository.solution.dbbased.RepositoryFile"; //$NON-NLS-1$ private static final String SearchablePhraseNamedQuery = "org.pentaho.platform.repository.solution.dbbased.RepositoryFile.folderSearcher"; //$NON-NLS-1$ protected int revision; protected String fileId; protected RepositoryFile parent; protected String fileName; protected String fullPath; protected long lastModified; protected boolean directory = true; private byte[] data = null; private Set childrenFiles = new TreeSet(); private List<IPentahoAclEntry> accessControls = new ArrayList<IPentahoAclEntry>(); public RepositoryFile() { super(); } public RepositoryFile( final String fileName, final RepositoryFile parent, final byte[] data ) { this( fileName, parent, data, System.currentTimeMillis() ); } public RepositoryFile( final String fileName, final RepositoryFile parent, final byte[] data, final long lastModified ) { this(); this.fileId = UUIDUtil.getUUIDAsString(); this.fileName = fileName; if ( parent != null ) { parent.addChildFile( this ); } setParent( parent ); setData( data ); setLastModified( lastModified ); directory = data == null; } @Override public int hashCode() { return fileId.hashCode(); } @Override public boolean equals( final Object other ) { if ( this == other ) { return true; } if ( !( other instanceof RepositoryFile ) ) { return false; } final RepositoryFile that = (RepositoryFile) other; return getFileId().equals( that.getFileId() ); } protected void resolvePath() { StringBuffer buffer = new StringBuffer( RepositoryFile.EMPTY_STRING ); if ( parent != null ) { buffer.append( parent.getFullPath() ); } buffer.append( org.pentaho.platform.api.repository2.unified.RepositoryFile.SEPARATOR ); buffer.append( fileName ); setFullPath( buffer.toString() ); } public List<IPentahoAclEntry> getAccessControls() { return this.accessControls; } /** * This method's purpose is to allow Hibernate to initialize the ACLs from the data-store. Application clients * should likely use resetAccessControls. */ public void setAccessControls( final List<IPentahoAclEntry> acls ) { this.accessControls = acls; } public void resetAccessControls( final List<IPentahoAclEntry> acls ) { if ( this.accessControls != null ) { this.accessControls.clear(); this.accessControls.addAll( acls ); } } public int getRevision() { return revision; } protected void setRevision( final int revision ) { this.revision = revision; } public String getFileId() { return fileId; } protected void setFileId( final String fileId ) { this.fileId = fileId; } public String getSolution() { return getTopFolder().getFileName(); } public String getSolutionPath() { ArrayList pathList = new ArrayList(); ISolutionFile folder = parent; while ( !folder.isRoot() && folder.retrieveParent() != null ) { pathList.add( folder.getFileName() ); folder = folder.retrieveParent(); } StringBuffer buffer = new StringBuffer( RepositoryFile.EMPTY_STRING ); for ( int i = pathList.size() - 1; i >= 0; i-- ) { buffer.append( org.pentaho.platform.api.repository2.unified.RepositoryFile.SEPARATOR ); buffer.append( pathList.get( i ).toString() ); } return buffer.toString(); } public String getFileName() { return fileName; } protected void setFileName( final String fileName ) { this.fileName = fileName; resolvePath(); } public String getFullPath() { return fullPath; } protected void setFullPath( final String fullPath ) { this.fullPath = fullPath; } public void setParent( final RepositoryFile parent ) { this.parent = parent; resolvePath(); } public RepositoryFile getParent() { return parent; } public ISolutionFile retrieveParent() { return parent; } protected RepositoryFile getTopFolder() { RepositoryFile topFolder = parent; if ( topFolder == null ) { return this; } while ( !topFolder.isRoot() ) { topFolder = (RepositoryFile) topFolder.retrieveParent(); } return topFolder; } /* * (non-Javadoc) * * @see org.pentaho.repository.ISearchable#getSearchableColumns() */ public String[] getSearchableColumns() { return RepositoryFile.SearchableColumns; } /* * (non-Javadoc) * * @see org.pentaho.repository.ISearchable#getSearchableTable() */ public String getSearchableTable() { return RepositoryFile.SearchableTable; } /* * (non-Javadoc) * * @see org.pentaho.repository.ISearchable#getPhraseSearchQueryName() */ public String getPhraseSearchQueryName() { return RepositoryFile.SearchablePhraseNamedQuery; } protected void setDirectory( final boolean directory ) { this.directory = directory; } protected boolean getDirectory() { return directory; } public boolean isDirectory() { return getDirectory(); } /** * @return Returns the childrenResources. */ public Set getChildrenFiles() { return childrenFiles; } /** * @param childrenFiles * The childrenResources to set. */ public void setChildrenFiles( final Set childrenFiles ) { this.childrenFiles = childrenFiles; } public void addChildFile( final RepositoryFile file ) { getChildrenFiles().add( file ); } public void removeChildFile( final RepositoryFile file ) { getChildrenFiles().remove( file ); file.setParent( null ); // as of now this file has no parent. } /** * @return Returns the data. */ public byte[] getData() { return data; } /** * @param data * The data to set. */ public void setData( final byte[] data ) { this.data = data; } public ISolutionFile[] listFiles( final IFileFilter filter ) { List matchedFiles = new ArrayList(); Object[] objArray = getChildrenFiles().toArray(); for ( Object element : objArray ) { if ( filter.accept( (ISolutionFile) element ) ) { matchedFiles.add( element ); } } return (ISolutionFile[]) matchedFiles.toArray( new ISolutionFile[] {} ); } public ISolutionFile[] listFiles() { Set<ISolutionFile> files = getChildrenFiles(); return files.toArray( new ISolutionFile[] {} ); } public RepositoryFile[] listRepositoryFiles() { RepositoryFile[] files = new RepositoryFile[getChildrenFiles().size()]; Iterator iter = getChildrenFiles().iterator(); int i = 0; while ( iter.hasNext() ) { files[i] = (RepositoryFile) iter.next(); i++; } return files; } public int compareTo( final Object o ) { if ( o == null ) { return 1; } else if ( o instanceof RepositoryFile ) { RepositoryFile that = (RepositoryFile) o; if ( ( this.getFullPath() == null ) && ( that.getFullPath() == null ) ) { return 0; } else if ( ( this.getFullPath() == null ) && ( that.getFullPath() != null ) ) { return -1; } else if ( ( this.getFullPath() != null ) && ( that.getFullPath() == null ) ) { return 1; } else { return this.getFullPath().compareTo( ( (RepositoryFile) o ).getFullPath() ); } } else { return this.getFullPath().compareTo( o.toString() ); } } /** * @return Returns the modDate. */ public long getLastModified() { return lastModified; } /** * @param modDate * The modDate to set. */ public void setLastModified( final long modDate ) { this.lastModified = modDate; } public boolean containsActions() { boolean hasActions = false; if ( this.isDirectory() ) { Set children = getChildrenFiles(); Iterator iter = children.iterator(); while ( iter.hasNext() && !hasActions ) { RepositoryFile file = (RepositoryFile) iter.next(); hasActions = file.getFileName().toLowerCase().endsWith( ".xaction" ); //$NON-NLS-1$ } } return hasActions; } public boolean isRoot() { return retrieveParent() == null; } /** * @return a boolean indicating if this file has an extension */ public boolean hasExtension() { return fileName.lastIndexOf( RepositoryFile.EXTENSION_CHAR ) != -1; } /** * @return the extension (including the . seperator) of this file */ public String getExtension() { return hasExtension() ? fileName.substring( fileName.lastIndexOf( RepositoryFile.EXTENSION_CHAR ) ) : ""; //$NON-NLS-1$ } public boolean exists() { return true; } /** * Chains up to find the access controls that are in force on this object. Could end up chaining all the way to * the root. * * <p> * Note that (1) defining no access control entries of your own and (2) removing all of your access control * entries is indistiguishable in the current design. In #1, we chain up because we inherit. But in #2, it might * be expected that by explicitly removing all access control entries, the chaining up ends. That is not the case * in the current design. * </p> */ public List<IPentahoAclEntry> getEffectiveAccessControls() { List acls = this.getAccessControls(); if ( acls.size() == 0 ) { RepositoryFile chain = this; while ( !chain.isRoot() && ( acls.size() == 0 ) ) { chain = (RepositoryFile) chain.retrieveParent(); acls = chain.getAccessControls(); } } return acls; } }