/*! * Copyright 2016 Pentaho Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.pentaho.di.repository.pur; import org.apache.commons.lang.StringUtils; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.repository.ObjectId; import org.pentaho.di.repository.RepositoryDirectory; import org.pentaho.di.repository.RepositoryDirectoryInterface; import org.pentaho.di.repository.RepositoryElementMetaInterface; import org.pentaho.di.repository.RepositoryObjectType; import org.pentaho.di.repository.StringObjectId; import org.pentaho.di.repository.pur.model.EERepositoryObject; import org.pentaho.di.repository.pur.model.RepositoryLock; import org.pentaho.di.ui.repository.pur.services.ILockService; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.api.repository2.unified.RepositoryFileTree; import org.pentaho.platform.api.repository2.unified.RepositoryRequest; import org.pentaho.platform.repository2.ClientRepositoryPaths; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * A version of RepositoryDirectoryInterface which only loads from the underlying repository as needed (Lazy) * <p/> * Created by nbaker on 12/22/15. * <p/> * Note the only reason we're extending RepositoryDirectory instead of implementing RepositoryDirectoryInterface is due * to some interface methods returning RepositoryDirectory!! */ public class LazyUnifiedRepositoryDirectory extends RepositoryDirectory { private RepositoryFile self; private IUnifiedRepository repository; private RepositoryServiceRegistry registry; private List<RepositoryDirectoryInterface> subdirectories; private List<RepositoryElementMetaInterface> fileChildren; private RepositoryDirectoryInterface parent; private Logger logger = LoggerFactory.getLogger( getClass() ); public LazyUnifiedRepositoryDirectory( RepositoryFile self, RepositoryDirectoryInterface parent, IUnifiedRepository repository, RepositoryServiceRegistry registry ) { this.self = self; this.parent = parent; this.repository = repository; this.registry = registry; } private String getParentPath( String absolutePath ) { int parentEndIndex; if ( absolutePath.endsWith( RepositoryDirectory.DIRECTORY_SEPARATOR ) ) { parentEndIndex = absolutePath.lastIndexOf( RepositoryDirectory.DIRECTORY_SEPARATOR, absolutePath.length() - 2 ); } else { parentEndIndex = absolutePath.lastIndexOf( RepositoryDirectory.DIRECTORY_SEPARATOR ); } if ( parentEndIndex < 0 ) { return null; } return absolutePath.substring( 0, parentEndIndex ); } @Override public RepositoryDirectory findDirectory( String path ) { if ( StringUtils.isEmpty( path ) ) { return null; } String absolutePath; if ( path.startsWith( RepositoryDirectory.DIRECTORY_SEPARATOR ) ) { if ( self.getPath().endsWith( RepositoryDirectory.DIRECTORY_SEPARATOR ) ) { absolutePath = self.getPath() + path.substring( 1 ); } else { absolutePath = self.getPath() + path; } } else { if ( self.getPath().endsWith( RepositoryDirectory.DIRECTORY_SEPARATOR ) ) { absolutePath = self.getPath() + path; } else { absolutePath = self.getPath() + RepositoryDirectory.DIRECTORY_SEPARATOR + path; } } RepositoryFile file = repository.getFile( absolutePath ); if ( file == null || !file.isFolder() ) { return null; } if ( isRoot() && RepositoryDirectory.DIRECTORY_SEPARATOR.equals( absolutePath ) ) { return this; } // Verifies if this is the parent directory of file and if so passes this as parent argument String parentPath = getParentPath( absolutePath ); if ( self.getPath().endsWith( RepositoryDirectory.DIRECTORY_SEPARATOR ) ) { if ( parentPath.equals( self.getPath().substring( 0, self.getPath().length() - 1 ) ) ) { return new LazyUnifiedRepositoryDirectory( file, this, repository, registry ); } } else { if ( parentPath.equals( self.getPath() ) ) { return new LazyUnifiedRepositoryDirectory( file, this, repository, registry ); } } return new LazyUnifiedRepositoryDirectory( file, findDirectory( parentPath ), repository, registry ); } @Override public RepositoryDirectory findChild( String name ) { return findDirectory( name ); } @Override public RepositoryDirectory findDirectory( String[] path ) { return findDirectory( StringUtils.join( path, "/" ) ); } @Override public List<RepositoryDirectoryInterface> getChildren() { if ( subdirectories == null ) { subdirectories = new ArrayList<>(); synchronized ( subdirectories ) { List<RepositoryFile> children = getAllURChildrenFiles(); for ( RepositoryFile child : children ) { LazyUnifiedRepositoryDirectory dir = new LazyUnifiedRepositoryDirectory( child, this, repository, registry ); dir.setObjectId( new StringObjectId( child.getId().toString() ) ); this.addSubdirectory( dir ); } } } return subdirectories; } @Override public List<RepositoryElementMetaInterface> getRepositoryObjects() { if ( fileChildren == null ) { fileChildren = new ArrayList<RepositoryElementMetaInterface>(); synchronized ( fileChildren ) { UnifiedRepositoryLockService lockService = (UnifiedRepositoryLockService) registry.getService( ILockService.class ); RepositoryFileTree tree = repository.getTree( new RepositoryRequest( this.self.getPath(), true, 1, null ) ); for ( RepositoryFileTree tchild : tree.getChildren() ) { RepositoryFile child = tchild.getFile(); if ( !child.isFolder() ) { RepositoryLock lock = null; try { lock = lockService.getLock( child ); RepositoryObjectType objectType = PurRepository.getObjectType( child.getName() ); EERepositoryObject repositoryObject = new EERepositoryObject( child, this, null, objectType, null, lock, false ); repositoryObject.setVersioningEnabled( tchild.getVersioningEnabled() ); repositoryObject.setVersionCommentEnabled( tchild.getVersionCommentEnabled() ); fileChildren.add( repositoryObject ); } catch ( KettleException e ) { logger.error( "Error converting Unified Repository file to PDI RepositoryObject: " + child.getPath() + ". File will be skipped", e ); } } } } } return fileChildren; } @Override public void setRepositoryObjects( List<RepositoryElementMetaInterface> list ) { synchronized ( fileChildren ) { fileChildren.clear(); fileChildren.addAll( list ); } } @Override public boolean isVisible() { return !isRoot() && !self.isHidden(); } @Override public int getNrSubdirectories() { List<RepositoryFile> childrenFiles = getAllURChildrenFiles(); return childrenFiles.size(); } @Override public RepositoryDirectory getSubdirectory( int i ) { if ( subdirectories == null ) { getChildren(); } if ( i >= subdirectories.size() || i < 0 ) { return null; } RepositoryDirectoryInterface directoryInterface = subdirectories.get( i ); // Have to cast due to bad interface if ( directoryInterface instanceof RepositoryDirectory ) { return (RepositoryDirectory) directoryInterface; } throw new IllegalStateException( "Bad Repository interface expects RepositoryDirectoryInterface to be an instance of" + " RepositoryDirectory. This class is not: " + directoryInterface.getClass().getName() ); } private List<RepositoryFile> getAllURChildrenFiles() { RepositoryRequest repositoryRequest = new RepositoryRequest(); repositoryRequest.setShowHidden( true ); repositoryRequest.setTypes( RepositoryRequest.FILES_TYPE_FILTER.FOLDERS ); repositoryRequest.setPath( this.self.getId().toString() ); List<RepositoryFile> children = repository.getChildren( repositoryRequest ); // Special case: /etc should not be returned from a directory listing. RepositoryFile etcFile = null; if ( this.isRoot() ) { etcFile = repository.getFile( ClientRepositoryPaths.getEtcFolderPath() ); } // Filter for Folders only doesn't appear to work Iterator<RepositoryFile> iterator = children.iterator(); while ( iterator.hasNext() ) { RepositoryFile next = iterator.next(); if ( !next.isFolder() ) { iterator.remove(); } // Special case: /etc should not be returned from a directory listing. if ( this.isRoot() && next.equals( etcFile ) ) { iterator.remove(); } } return children; } @Override public void clear() { if ( this.fileChildren != null ) { synchronized ( fileChildren ) { this.fileChildren.clear(); } } if ( this.subdirectories != null ) { synchronized ( subdirectories ) { this.subdirectories.clear(); } } } @Override public void addSubdirectory( RepositoryDirectoryInterface repositoryDirectoryInterface ) { if ( subdirectories == null ) { subdirectories = new ArrayList<>(); } synchronized ( subdirectories ) { this.subdirectories.add( repositoryDirectoryInterface ); } } @Override public String getName() { return self.getName(); } @Override public String getPath() { return self.getPath(); } @Override public ObjectId getObjectId() { return new StringObjectId( self.getId().toString() ); } @Override public void setChildren( List<RepositoryDirectoryInterface> list ) { if ( subdirectories == null ) { subdirectories = new ArrayList<>(); } if ( !subdirectories.equals( list ) ) { synchronized ( subdirectories ) { subdirectories.clear(); subdirectories.addAll( list ); } } } @Override public String[] getPathArray() { return getPath().split( RepositoryDirectory.DIRECTORY_SEPARATOR ); } @Override public ObjectId[] getDirectoryIDs() { List<RepositoryFile> children = this.getAllURChildrenFiles(); ObjectId[] objectIds = new ObjectId[ children.size() ]; for ( int i = 0; i < children.size(); i++ ) { objectIds[ i ] = new StringObjectId( children.get( i ).getId().toString() ); } return objectIds; } @Override public boolean isRoot() { return parent == null; } @Override public RepositoryDirectoryInterface findRoot() { RepositoryDirectoryInterface current = this; RepositoryDirectoryInterface parent = null; while ( ( parent = current.getParent() ) != null ) { current = parent; } return current; } @Override public void setParent( RepositoryDirectoryInterface repositoryDirectoryInterface ) { this.parent = repositoryDirectoryInterface; } @Override public RepositoryDirectoryInterface getParent() { return parent; } @Override public void setObjectId( ObjectId objectId ) { // ignore } @Override public void setName( String s ) { // ignore } @Override public String getPathObjectCombination( String transName ) { if ( isRoot() ) { return getPath() + transName; } else { return getPath() + RepositoryDirectory.DIRECTORY_SEPARATOR + transName; } } }