/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.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 Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.platform.api.repository2.unified;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A struct for a {@link RepositoryFile} and its immediate children.* The immediate children is a list of this type
* (which can have children and so on). This class is immutable.
*
* <p>
* * This is necessary since a {@code RepositoryFile} does not (by design) have a reference to its children. A
* {@code RepositoryFile} is meant to be a lightweight object representing metadata about a file in isolation. It
* does not have references to other {@code RepositoryFile} instances. The potential for misuse of a children field
* on {@code RepositoryFile} was great enough to warrant the creation of {@code RepositoryFileTree}. This
* separation of single file vs. tree is seen as a cleaner API with less confusion about when children is
* populated.
* </p>
*
* @author mlowery
*/
public class RepositoryFileTree implements Comparable<RepositoryFileTree>, Serializable {
// ~ Static fields/initializers
// ======================================================================================
// ~ Instance fields
// =================================================================================================
private static final long serialVersionUID = 6282939978216638770L;
private final RepositoryFile file;
private final List<RepositoryFileTree> children;
private Boolean versioningEnabled; //Is versioning enabled for this object
private Boolean versionCommentEnabled; //Are comments for versions enabled for this object
// ~ Constructors
// ====================================================================================================
public RepositoryFileTree( final RepositoryFile file, final List<RepositoryFileTree> children ) {
super();
notNull( file );
this.file = file;
// defensive copy
this.children = children != null ? new ArrayList<RepositoryFileTree>( children ) : null;
}
// ~ Methods
// =========================================================================================================
private void notNull( final Object obj ) {
if ( obj == null ) {
throw new IllegalArgumentException();
}
}
public RepositoryFile getFile() {
return file;
}
/**
* Children can have one of three values:
* <ul>
* <li>null: children were not fetched; used for operations that support depth</li>
* <li>empty list: there are no children for this file (i.e. file is not a folder or folder has no children)</li>
* <li>non-empty list: this file is a folder and it has children</li>
* </ul>
*
* @return
*/
public List<RepositoryFileTree> getChildren() {
return children != null ? Collections.unmodifiableList( children ) : null;
}
/**
* Compare is based on the root file.
*/
public int compareTo( final RepositoryFileTree other ) {
return file.compareTo( other.file );
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( file == null ) ? 0 : file.hashCode() );
return result;
}
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
RepositoryFileTree other = (RepositoryFileTree) obj;
if ( file == null ) {
if ( other.file != null ) {
return false;
}
} else if ( !file.equals( other.file ) ) {
return false;
}
return true;
}
@Override
public String toString() {
return toString( 0 );
}
protected String toString( final int depth ) {
final String SPACER = " "; //$NON-NLS-1$
final String NL = "\n"; //$NON-NLS-1$
final String SLASH = "/"; //$NON-NLS-1$
StringBuilder buf = new StringBuilder();
for ( int i = 0; i < depth; i++ ) {
buf.append( SPACER );
}
buf.append( file.getName() );
if ( file.isFolder() ) {
buf.append( SLASH );
}
buf.append( NL );
if ( children != null ) {
for ( RepositoryFileTree subtree : children ) {
buf.append( subtree.toString( depth + 1 ) );
}
}
return buf.toString();
}
// ~ Inner classes
// ===================================================================================================
public static class Builder {
private List<Builder> children;
private RepositoryFile file;
public Builder( final RepositoryFile file, final List<Builder> children ) {
this.file = file;
this.children = children;
}
/**
* Creates a builder with an empty list as children.
*/
public Builder( final RepositoryFile file ) {
this( file, new ArrayList<Builder>() );
}
public Builder( final RepositoryFileTree other ) {
this( other.file, toBuilderChildren( other.children ) );
}
public RepositoryFileTree build() {
return new RepositoryFileTree( file, toTreeChildren( children ) );
}
public Builder child( final Builder child ) {
this.children.add( child );
return this;
}
private static List<RepositoryFileTree> toTreeChildren( final List<Builder> children ) {
if ( null == children ) {
return null;
}
List<RepositoryFileTree> converted = new ArrayList<RepositoryFileTree>( children.size() );
for ( Builder child : children ) {
converted.add( child.build() );
}
return converted;
}
private static List<Builder> toBuilderChildren( final List<RepositoryFileTree> children ) {
if ( null == children ) {
return null;
}
List<Builder> converted = new ArrayList<Builder>( children.size() );
for ( RepositoryFileTree child : children ) {
converted.add( new Builder( child ) );
}
return converted;
}
/*
* Allow code that is building the tree to see current children.
*/
public List<Builder> getChildren() {
return Collections.unmodifiableList( children );
}
/*
* Allow code that is building the tree to see file.
*/
public RepositoryFile getFile() {
return file;
}
}
public Boolean getVersioningEnabled() {
return versioningEnabled;
}
public void setVersioningEnabled( Boolean versioningEnabled ) {
this.versioningEnabled = versioningEnabled;
}
public Boolean getVersionCommentEnabled() {
return versionCommentEnabled;
}
public void setVersionCommentEnabled( Boolean versionCommentEnabled ) {
this.versionCommentEnabled = versionCommentEnabled;
}
}