/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* 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;
import java.util.ArrayList;
import java.util.List;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.xml.XMLHandler;
import org.w3c.dom.Node;
/**
* This class defines the location of a transformation, job or schema in the repository. That means that it's just an
* extra parameter for recognizing a transformation, job or schema. It allows for sub-directories by linking back to
* itself.
*
* TODO: This class is referenced in a large amount of Interfaces. We should convert it into an interface.
*
* @author Matt
* @since 09-nov-2004
*
*/
public class RepositoryDirectory implements RepositoryDirectoryInterface {
public static final String DIRECTORY_SEPARATOR = "/";
private RepositoryDirectoryInterface parent;
private List<RepositoryDirectoryInterface> children;
private List<RepositoryElementMetaInterface> repositoryObjects;
private String directoryname;
private ObjectId id;
/**
* True to show this directory in UIs. Not necessarily persisted. Each repo impl decides whether to mark each dir as
* visible.
*/
private boolean visible = true;
/**
* Create a new sub-directory in a certain other directory.
*
* @param parent
* The directory to create the sub-directory in
* @param directoryname
* The name of the new directory.
*/
public RepositoryDirectory( RepositoryDirectoryInterface parent, String directoryname ) {
this.parent = parent;
this.directoryname = directoryname;
this.children = new ArrayList<RepositoryDirectoryInterface>(); // default: no subdirectories...
this.id = null; // The root directory!
}
/**
* Create an empty repository directory. With the name and parent set to empty, this is the root directory.
*
*/
public RepositoryDirectory() {
this( null, (String) null );
}
@Override
public List<RepositoryDirectoryInterface> getChildren() {
return children;
}
@Override
public void setChildren( List<RepositoryDirectoryInterface> children ) {
this.children = children;
}
@Override
public List<RepositoryElementMetaInterface> getRepositoryObjects() {
return repositoryObjects;
}
@Override
public void setRepositoryObjects( List<RepositoryElementMetaInterface> repositoryObjects ) {
this.repositoryObjects = repositoryObjects;
}
@Override
public void clear() {
this.parent = null;
this.directoryname = null;
this.children = new ArrayList<RepositoryDirectoryInterface>(); // default: no subdirectories...
}
/**
* Get the database ID in the repository for this object.
*
* @return the database ID in the repository for this object.
*/
@Override
public ObjectId getObjectId() {
return id;
}
/**
* Set the database ID for this object in the repository.
*
* @param id
* the database ID for this object in the repository.
*/
@Override
public void setObjectId( ObjectId id ) {
this.id = id;
}
/**
* Change the parent of this directory. (move directory)
*
* @param parent
* The new parent of this directory.
*/
@Override
public void setParent( RepositoryDirectoryInterface parent ) {
this.parent = parent;
}
/**
* get the parent directory for this directory.
*
* @return The parent directory of null if this is the root directory.
*/
@Override
public RepositoryDirectoryInterface getParent() {
return this.parent;
}
/**
* Set the directory name (rename)
*
* @param directoryname
* The new directory name
*/
@Override
public void setName( String directoryname ) {
this.directoryname = directoryname;
}
/**
* Get the name of this directory...
*
* @return the name of this directory
*/
@Override
public String getName() {
if ( directoryname == null ) {
return DIRECTORY_SEPARATOR;
}
return directoryname;
}
/**
* Check whether or not this is the root of the directory trees. (default)
*
* @return true if this is the root directory node. False if it is not.
*/
@Override
public boolean isRoot() {
return parent == null && directoryname == null;
}
/**
* Describe the complete path to ( and including) this directory, separated by the
* RepositoryDirectory.DIRECTORY_SEPARATOR property (slash).
*
* @return The complete path to this directory.
*/
@Override
public String getPath() {
// Root!
if ( getParent() == null ) {
return DIRECTORY_SEPARATOR;
} else {
if ( getParent().getParent() == null ) {
return DIRECTORY_SEPARATOR + getName();
} else {
return getParent().getPath() + DIRECTORY_SEPARATOR + getName();
}
}
}
/**
* Describe the complete path to ( and including) this directory, as an array of strings.
*
* @return The complete path to this directory.
*/
@Override
public String[] getPathArray() {
// First determine the depth of the tree...
int depth = 1;
RepositoryDirectoryInterface follow = getParent();
if ( follow != null ) {
depth++;
follow = follow.getParent();
}
// Then put something in it...
String[] retval = new String[depth];
int level = depth - 1;
retval[level] = getName();
follow = getParent();
if ( follow != null ) {
level--;
retval[level] = follow.getName();
follow = follow.getParent();
}
return retval;
}
/**
* Add a subdirectory to this directory.
*
* @param subdir
* The subdirectory to add.
*/
@Override
public void addSubdirectory( RepositoryDirectoryInterface subdir ) {
subdir.setParent( this );
children.add( subdir );
}
/**
* Counts the number of subdirectories in this directory.
*
* @return The number of subdirectories
*/
@Override
public int getNrSubdirectories() {
return children.size();
}
/**
* Get a subdirectory on a certain position.
*
* @param i
* The subdirectory position
* @return The subdirectory with on a certain position
*/
@Override
public RepositoryDirectory getSubdirectory( int i ) {
if ( children == null ) {
return null;
}
return (RepositoryDirectory) children.get( i );
}
/**
* Find the directory by following the path of strings
*
* @param path
* The path to the directory we're looking for.
* @return The directory if one can be found, null if no directory was found.
*/
@Override
public RepositoryDirectory findDirectory( String[] path ) {
// Is it root itself?
if ( isRoot() && path.length == 1 && path[0].equalsIgnoreCase( DIRECTORY_SEPARATOR ) ) {
return this;
}
if ( path.length < 1 ) {
return this;
}
String[] directoryPath;
// Skip the root directory, it doesn't really exist as such.
if ( path.length > 0 && path[0].equalsIgnoreCase( DIRECTORY_SEPARATOR ) ) {
// Copy the path exception the highest level, we go down one...
directoryPath = new String[path.length - 1];
for ( int x = 0; x < directoryPath.length; x++ ) {
directoryPath[x] = path[x + 1];
}
} else {
directoryPath = path;
}
// The root directory?
if ( isRoot() && directoryPath.length == 1 && directoryPath[0].equalsIgnoreCase( DIRECTORY_SEPARATOR ) ) {
return this;
} else if ( directoryPath.length == 1 && directoryPath[0].equalsIgnoreCase( getName() ) ) {
// This directory?
return this;
} else if ( directoryPath.length >= 1 ) {
// A direct subdirectory?
RepositoryDirectory follow = this;
for ( int i = 0; i < directoryPath.length; i++ ) {
RepositoryDirectory directory = follow.findChild( directoryPath[i] );
if ( directory == null ) {
return null;
}
follow = directory;
}
return follow;
/*
* for (int i=0;i<getNrSubdirectories();i++) { RepositoryDirectory subdir = getSubdirectory(i); if
* (subdir.getDirectoryName().equalsIgnoreCase(directoryPath[0])) { if (directoryPath.length==1) return subdir; //
* we arrived at the destination...
*
* // Copy the path exception the highest level, we go down one... String subpath[] = new
* String[directoryPath.length-1]; for (int x=0;x<subpath.length;x++) subpath[x]=directoryPath[x+1];
*
* // Perhaps the rest of the path is the same too? RepositoryDirectory look = subdir.findDirectory(subpath); if
* (look!=null) return look; } }
*/
}
return null;
}
/**
* Find a directory using the path to the directory with file.separator between the dir-names.
*
* @param path
* The path to the directory
* @return The directory if one was found, null if nothing was found.
*/
@Override
public RepositoryDirectory findDirectory( String path ) {
String[] newPath = Const.splitPath( path, DIRECTORY_SEPARATOR );
String[] p = null;
if ( parent == null ) {
// This doesn't include the root:
p = new String[newPath.length + 1];
p[0] = DIRECTORY_SEPARATOR;
for ( int i = 0; i < newPath.length; i++ ) {
p[i + 1] = newPath[i];
}
} else {
p = newPath;
}
return findDirectory( p );
}
@Override
public RepositoryDirectory findChild( String name ) {
for ( RepositoryDirectoryInterface child : children ) {
if ( child.getName().equalsIgnoreCase( name ) ) {
return (RepositoryDirectory) child;
}
}
return null;
}
/**
* Find the sub-directory with a certain ID
*
* @param id_directory
* the directory ID to look for.
* @return The RepositoryDirectory if the ID was found, null if nothing could be found.
*/
@Override
public RepositoryDirectory findDirectory( ObjectId id_directory ) {
// Check for the root directory...
//
if ( getObjectId() == null && id_directory == null ) {
return this;
}
if ( getObjectId() != null && getObjectId().equals( id_directory ) ) {
return this;
}
for ( int i = 0; i < getNrSubdirectories(); i++ ) {
RepositoryDirectory rd = getSubdirectory( i ).findDirectory( id_directory );
if ( rd != null ) {
return rd;
}
}
return null;
}
/**
* Return the description of this directory & the subdirectories in XML.
*
* @return The XML describing this directory.
*/
public String getXML() {
return getXML( 0 );
}
public String getXML( int level ) {
String spaces = Const.rightPad( " ", level );
StringBuilder retval = new StringBuilder( 200 );
retval.append( spaces ).append( "<repdir>" ).append( Const.CR );
retval.append( spaces ).append( " " ).append( XMLHandler.addTagValue( "name", getName() ) );
if ( getNrSubdirectories() > 0 ) {
retval.append( spaces ).append( " <subdirs>" ).append( Const.CR );
for ( int i = 0; i < getNrSubdirectories(); i++ ) {
RepositoryDirectory subdir = getSubdirectory( i );
retval.append( subdir.getXML( level + 1 ) );
}
retval.append( spaces ).append( " </subdirs>" ).append( Const.CR );
}
retval.append( spaces ).append( "</repdir>" ).append( Const.CR );
return retval.toString();
}
/**
* Load the directory & subdirectories from XML
*
* @param repdirnode
* The node in which the Repository directory information resides.
* @return True if all went well, false if an error occured.
*/
public boolean loadXML( Node repdirnode ) {
try {
clear();
directoryname = XMLHandler.getTagValue( repdirnode, "name" );
Node subdirsnode = XMLHandler.getSubNode( repdirnode, "subdirs" );
if ( subdirsnode != null ) {
int n = XMLHandler.countNodes( subdirsnode, "repdir" );
for ( int i = 0; i < n; i++ ) {
Node subdirnode = XMLHandler.getSubNodeByNr( subdirsnode, "repdir", i );
RepositoryDirectory subdir = new RepositoryDirectory();
if ( subdir.loadXML( subdirnode ) ) {
subdir.setParent( this );
addSubdirectory( subdir );
} else {
return false;
}
}
}
return true;
} catch ( Exception e ) {
return false;
}
}
/**
* Get all the directory-id in this directory and the subdirectories.
*
* @return an array of all the directory id's (this directory & subdirectories)
*/
@Override
public ObjectId[] getDirectoryIDs() {
List<ObjectId> ids = new ArrayList<ObjectId>();
getDirectoryIDs( ids );
return ids.toArray( new ObjectId[ids.size()] );
}
/**
* Fill an arraylist with all the ID_DIRECTORY values in the tree below and including this directory.
*
* @param ids
* The arraylist that will contain the directory IDs.
*/
private void getDirectoryIDs( List<ObjectId> ids ) {
if ( getObjectId() != null ) {
ids.add( getObjectId() );
}
for ( int i = 0; i < getNrSubdirectories(); i++ ) {
getSubdirectory( i ).getDirectoryIDs( ids );
}
}
/**
* Find the root of the directory tree starting from this directory.
*
* @return the root of the directory tree
*/
@Override
public RepositoryDirectoryInterface findRoot() {
if ( isRoot() ) {
return this;
}
return getParent().findRoot();
}
@Override
public String toString() {
return getPath();
}
@Override
public String getPathObjectCombination( String transName ) {
if ( isRoot() ) {
return getPath() + transName;
} else {
return getPath() + RepositoryDirectory.DIRECTORY_SEPARATOR + transName;
}
}
@Override
public boolean isVisible() {
return visible;
}
public void setVisible( boolean visible ) {
this.visible = visible;
}
}