/* Copyright (c) 2003 eInnovation Inc. All rights reserved This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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. */ package com.openedit.webui.tree; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openedit.repository.ContentItem; import org.openedit.repository.Repository; import org.openedit.repository.RepositoryException; import com.openedit.OpenEditRuntimeException; import com.openedit.page.Page; import com.openedit.page.PageSettings; import com.openedit.page.manage.PageManager; import com.openedit.util.PathUtilities; /** * This class represents a node in a {@link RepositoryTreeModel}. * * @author Matt Avery, mavery@einnovation.com */ public class RepositoryTreeNode extends DefaultWebTreeNode implements Comparable { //public static final DefaultWebTreeNode ERROR_NODE = new DefaultWebTreeNode( "Error accessing tree node." ); protected Repository fieldRepository; protected ContentItem fieldContentItem; protected PageManager fieldPageManager; protected boolean fieldVirtual; protected String fieldUrl; private static final Log log = LogFactory.getLog(RepositoryTreeNode.class); /** * Create a new <code>PageTreeNode</code>. * * @param inFile The file that this node represents * @param inPath The path to the file, relative to the site context root * @throws RepositoryException */ public RepositoryTreeNode( Repository inRepository, ContentItem inContentItem, String inUserPath ) { super( extractName( inContentItem ) ); // String id = PathUtilities.makeId(inUserPath); // id = id.replace('/', '_'); setId( inUserPath ); fieldRepository = inRepository; fieldContentItem = inContentItem; setLeaf(!getContentItem().isFolder()); } private static String extractName( ContentItem inItem ) { String path = inItem.getPath(); if ( "/".equals( path ) ) { return "Root"; } String name = PathUtilities.extractFileName(path); return name; } /** * Get the first child of this node with the given name. * * @param inName The node name * * @return The node, or <code>null</code> if no such child could be found */ public RepositoryTreeNode getChild(String inName) { for (Iterator iter = getChildren().iterator(); iter.hasNext();) { RepositoryTreeNode child = (RepositoryTreeNode) iter.next(); if ((child.getName() != null) && child.getName().equals(inName)) { return child; } } return null; } /* (non-Javadoc) * @see DefaultWebTreeNode#getChildren() */ public List getChildren() { if (fieldChildren == null) { fieldChildren = new ArrayList(); reloadChildren(); } return fieldChildren; } /* (non-Javadoc) * @see java.lang.Comparable#compareTo(Object) */ public int compareTo(Object o) { if (o == null) { return 1; } if (o instanceof RepositoryTreeNode) { RepositoryTreeNode node = (RepositoryTreeNode) o; return getContentItem().getPath().toLowerCase().compareTo(node.getContentItem().getPath().toLowerCase()); } else { return 0; } } /** * Find the descendant of this node with the given path. * * @param inPath The path to find * * @return The node at the given path, or <code>null</code> if it could not be found */ public RepositoryTreeNode findNode(String inPath) { // Quick initial checks... if (!inPath.startsWith("/")) { inPath = "/" + inPath; } if (inPath.equals("") || inPath.equals("/")) { return this; } int beforeSlashIndex = 0; if (inPath.startsWith("/")) { beforeSlashIndex = 1; } int nextSlashIndex = inPath.indexOf('/', beforeSlashIndex); if (nextSlashIndex < 0) { nextSlashIndex = inPath.length(); } String childName = inPath.substring(beforeSlashIndex, nextSlashIndex); RepositoryTreeNode child = getChild(childName); if (child == null) { return null; } else { return child.findNode(inPath.substring(nextSlashIndex)); } } /** * Reload the children of this page tree node. */ public void reloadChildren() { getChildren().clear(); List directories = new ArrayList(); List files = new ArrayList(); if (getContentItem().isFolder()) { Collection childItems = getChildPaths(); //TODO: Clean up this class with an archive class or some other class Page thisdir = null; String thisdirpath = getContentItem().getPath(); if( !thisdirpath.endsWith("/")) { thisdirpath = thisdirpath + "/"; } thisdir = getPageManager().getPage(thisdirpath); boolean checkpermissions = Boolean.parseBoolean( thisdir.getProperty("oecheckfilepermissions") ); boolean loadfallback = true; String load = thisdir.getProperty("oeshowfallbackfiles"); if( load != null ) { loadfallback = Boolean.parseBoolean(load); } for ( Iterator iterator = childItems.iterator(); iterator.hasNext(); ) { // Object obj = iterator.next(); // if ( !(obj instanceof ContentItem)) // { // throw new OpenEditRuntimeException("Must be type " + ContentItem.class + " " + obj.getClass()); // } // childItem = (ContentItem) obj; String npath = (String)iterator.next(); RepositoryTreeNode child = createNode( npath ); child.getName(); child.toString(); child.getURL(); boolean okToAdd = true; if( getFilter() != null && (checkpermissions || !child.isLeaf() ) ) { okToAdd = getFilter().passes(npath); } if (okToAdd) { child.setParent(this); if (child.isLeaf()) { files.add(child); } else { directories.add(child); } } } if( loadfallback) { //clear cache not needed since the permission check has clear the cache getPageManager().clearCache(thisdirpath); PageSettings fallback = thisdir.getPageSettings().getFallback(); if( fallback != null) { Set existingDirNames = new HashSet(); for (Iterator iterator = directories.iterator(); iterator.hasNext();) { RepositoryTreeNode item = (RepositoryTreeNode) iterator.next(); existingDirNames.add(item.getName()); } Set existingFileNames = new HashSet(); for (Iterator iterator = files.iterator(); iterator.hasNext();) { RepositoryTreeNode item = (RepositoryTreeNode) iterator.next(); existingFileNames.add(item.getName()); } String dirparent = PathUtilities.extractDirectoryPath(fallback.getPath()); //ContentItem basedir = getPageManager().getRepository().get(dirparent); RepositoryTreeNode child = createNode( dirparent ); for (Iterator iterator = child.getChildPaths().iterator(); iterator.hasNext();) { String inbasepath = (String)iterator.next(); //ContentItem basechildItem = (ContentItem) iterator.next(); boolean okToAdd = true; if( getFilter() != null ) { okToAdd = getFilter().passes(inbasepath); } if (!okToAdd) { continue; } RepositoryTreeNode node = createNode( inbasepath ); node.setParent(this); if( node.isLeaf()) { files.add(node); node.setVirtual(true); //If on list already then set the full path. Kind of annoying but otherwise can't click on the virtual one if( existingFileNames.contains(node.getName())) { node.setUrl(inbasepath); } } else { if( !existingDirNames.contains(node.getName())) { directories.add(node); //Only add if not already in there } node.setVirtual(true); } } } } // Make sure the files appear in lexicographically increasing // order, with all the directories appearing before all the files. Collections.sort(directories); Collections.sort(files); getChildren().addAll(directories); getChildren().addAll(files); } } protected Collection getChildPaths() { if ( getContentItem().isFolder() ) { Collection paths = getPageManager().getChildrenPaths(getContentItem().getPath()); return paths; // if ( getContentItem() instanceof FileItem) // { // try // { // FileItem item = (FileItem)getContentItem(); // File[] files = item.getFile().listFiles(); // String between = "/"; // if( getContentItem().getPath().endsWith("/")) // { // between = ""; // } // for (int i = 0; i < files.length; i++) // { // items.add( getRepository().get( getContentItem().getPath() + between + files[i].getName() ) ); // } // } // else // { // throw new OpenEditRuntimeException("Tree only works with FileItem class"); } return Collections.EMPTY_LIST; } /** * Method createPageTreeNode. * * @param childFile * @param path * * @return PageTreeNode */ protected RepositoryTreeNode createNode(String inPath) { //inPath may be the name of the fallback file. Rebuild the path String path = null; if( getParent() == null) { path = "/" + PathUtilities.extractFileName(inPath); } else { path = getURL() + "/" + PathUtilities.extractFileName(inPath); } ContentItem childItem = null; try { if( inPath.endsWith("/") ) { childItem = getRepository().getStub(path + "/"); } else { childItem = getRepository().getStub(path); } } catch (RepositoryException e) { throw new OpenEditRuntimeException(e); } if( childItem.getActualPath() != null && !path.equals(childItem.getActualPath())) { path = path + "_" + childItem.getActualPath(); //To make sure it is unique use virtual path + actual path on disk drive } String id = PathUtilities.makeId(path); id = id.replace('/', '_'); RepositoryTreeNode node = new RepositoryTreeNode( getRepository(), childItem, id); node.setFilter(getFilter()); //node.setParent(this); node.setPageManager(getPageManager()); return node; } public ContentItem getContentItem() { return fieldContentItem; } public void setContentItem( ContentItem contentItem ) { fieldContentItem = contentItem; } public Repository getRepository() { return fieldRepository; } public void setRepository( Repository repository ) { fieldRepository = repository; } public PageManager getPageManager() { return fieldPageManager; } public void setPageManager(PageManager inPageManager) { fieldPageManager = inPageManager; } //This is really the path public String getURL() { if( fieldUrl != null) { return fieldUrl; } if ( getParent() != null) { String p =getParent().getURL(); if ( p.endsWith("/")) { return p + getName(); } else { return p + "/" + getName(); } } else { return getName(); //the root does not need a special URL since it is part of the base path } } public void setParent(DefaultWebTreeNode inParent) { super.setParent(inParent); setUrl( getURL() ); } protected void setUrl(String inPath) { fieldUrl = inPath; } public void setVirtual(boolean inVirtual) { fieldVirtual = inVirtual; } public String getIconSet() { if( isVirtual()) { return "linked"; } return super.getIconSet(); } public boolean isVirtual() { if( fieldVirtual) { return true; } if( getParent() != null ) { return ((RepositoryTreeNode)getParent()).isVirtual(); } return fieldVirtual; } public String toString() { return getURL(); } }