001: /*
002: Copyright (c) 2003 eInnovation Inc. All rights reserved
003:
004: This library is free software; you can redistribute it and/or modify it under the terms
005: of the GNU Lesser General Public License as published by the Free Software Foundation;
006: either version 2.1 of the License, or (at your option) any later version.
007:
008: This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
009: without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: See the GNU Lesser General Public License for more details.
011: */
012:
013: package com.openedit.webui.tree;
014:
015: import java.io.File;
016: import java.util.ArrayList;
017: import java.util.Collections;
018: import java.util.HashSet;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Set;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.openedit.repository.ContentItem;
026: import org.openedit.repository.Repository;
027: import org.openedit.repository.RepositoryException;
028: import org.openedit.repository.filesystem.FileItem;
029:
030: import com.openedit.OpenEditException;
031: import com.openedit.OpenEditRuntimeException;
032: import com.openedit.page.Page;
033: import com.openedit.page.PageSettings;
034: import com.openedit.page.manage.PageManager;
035: import com.openedit.util.PathUtilities;
036:
037: /**
038: * This class represents a node in a {@link RepositoryTreeModel}.
039: *
040: * @author Matt Avery, mavery@einnovation.com
041: */
042: public class RepositoryTreeNode extends DefaultWebTreeNode implements
043: Comparable {
044: //public static final DefaultWebTreeNode ERROR_NODE = new DefaultWebTreeNode( "Error accessing tree node." );
045: protected Repository fieldRepository;
046: protected ContentItem fieldContentItem;
047: protected PageManager fieldPageManager;
048: protected boolean fieldVirtual;
049: protected String fieldUrl;
050:
051: private static final Log log = LogFactory
052: .getLog(RepositoryTreeNode.class);
053:
054: /**
055: * Create a new <code>PageTreeNode</code>.
056: *
057: * @param inFile The file that this node represents
058: * @param inPath The path to the file, relative to the site context root
059: * @throws RepositoryException
060: */
061: public RepositoryTreeNode(Repository inRepository,
062: ContentItem inContentItem) {
063: super (extractName(inContentItem));
064: fieldRepository = inRepository;
065: fieldContentItem = inContentItem;
066: setLeaf(!getContentItem().isFolder());
067: }
068:
069: private static String extractName(ContentItem inItem) {
070: String path = inItem.getPath();
071: if ("/".equals(path)) {
072: return path;
073: }
074: int lastSlashIndex = path.lastIndexOf('/');
075: if (lastSlashIndex < 0) {
076: return path;
077: }
078: return path.substring(lastSlashIndex + 1);
079: }
080:
081: /**
082: * Get the first child of this node with the given name.
083: *
084: * @param inName The node name
085: *
086: * @return The node, or <code>null</code> if no such child could be found
087: */
088: public RepositoryTreeNode getChild(String inName) {
089: for (Iterator iter = getChildren().iterator(); iter.hasNext();) {
090: RepositoryTreeNode child = (RepositoryTreeNode) iter.next();
091:
092: if ((child.getName() != null)
093: && child.getName().equals(inName)) {
094: return child;
095: }
096: }
097:
098: return null;
099: }
100:
101: /* (non-Javadoc)
102: * @see DefaultWebTreeNode#getChildren()
103: */
104: public List getChildren() {
105: if (fieldChildren == null) {
106: fieldChildren = new ArrayList();
107: reloadChildren();
108: }
109:
110: return fieldChildren;
111: }
112:
113: /* (non-Javadoc)
114: * @see java.lang.Comparable#compareTo(Object)
115: */
116: public int compareTo(Object o) {
117: if (o == null) {
118: return 1;
119: }
120:
121: if (o instanceof RepositoryTreeNode) {
122: RepositoryTreeNode node = (RepositoryTreeNode) o;
123:
124: return getContentItem().getPath().toLowerCase().compareTo(
125: node.getContentItem().getPath().toLowerCase());
126: } else {
127: return 0;
128: }
129: }
130:
131: /**
132: * Find the descendant of this node with the given path.
133: *
134: * @param inPath The path to find
135: *
136: * @return The node at the given path, or <code>null</code> if it could not be found
137: */
138: public RepositoryTreeNode findNode(String inPath) {
139: // Quick initial checks...
140: if (!inPath.startsWith("/")) {
141: inPath = "/" + inPath;
142: }
143:
144: if (inPath.equals("") || inPath.equals("/")) {
145: return this ;
146: }
147:
148: int beforeSlashIndex = 0;
149:
150: if (inPath.startsWith("/")) {
151: beforeSlashIndex = 1;
152: }
153:
154: int nextSlashIndex = inPath.indexOf('/', beforeSlashIndex);
155:
156: if (nextSlashIndex < 0) {
157: nextSlashIndex = inPath.length();
158: }
159:
160: String childName = inPath.substring(beforeSlashIndex,
161: nextSlashIndex);
162:
163: RepositoryTreeNode child = getChild(childName);
164:
165: if (child == null) {
166: return null;
167: } else {
168: return child.findNode(inPath.substring(nextSlashIndex));
169: }
170: }
171:
172: /**
173: * Reload the children of this page tree node.
174: */
175: public void reloadChildren() {
176: getChildren().clear();
177:
178: List directories = new ArrayList();
179: List files = new ArrayList();
180:
181: if (getContentItem().isFolder()) {
182: List childItems = getChildItems();
183: ContentItem childItem = null;
184: for (Iterator iterator = childItems.iterator(); iterator
185: .hasNext();) {
186: Object obj = iterator.next();
187: if (!(obj instanceof ContentItem)) {
188: throw new OpenEditRuntimeException("Must be type "
189: + ContentItem.class + " " + obj.getClass());
190: }
191: childItem = (ContentItem) obj;
192:
193: String npath = childItem.getPath();
194:
195: boolean okToAdd = true;
196: if (getFilter() != null) {
197: okToAdd = getFilter().passes(npath);
198: }
199:
200: if (okToAdd) {
201:
202: RepositoryTreeNode child = createNode(childItem);
203: child.setParent(this );
204:
205: if (childItem.isFolder()) {
206: directories.add(child);
207: } else {
208: files.add(child);
209: }
210: }
211: }
212: //Check fallback location
213: //TODO: Clean up this class with an archive class or some other class
214: Page this dir = null;
215: try {
216: String this dirpath = getContentItem().getPath();
217: if (!this dirpath.endsWith("/")) {
218: this dirpath = this dirpath + "/";
219: }
220: this dir = getPageManager().getPage(this dirpath);
221: //Not needed since the permission check with clear the cache getPageManager().clearCache(thisdirpath);
222: PageSettings fallback = this dir.getPageSettings()
223: .getFallback();
224: if (fallback != null) {
225: Set existingDirNames = new HashSet();
226: for (Iterator iterator = directories.iterator(); iterator
227: .hasNext();) {
228: RepositoryTreeNode item = (RepositoryTreeNode) iterator
229: .next();
230: existingDirNames.add(item.getName());
231: }
232: Set existingFileNames = new HashSet();
233: for (Iterator iterator = files.iterator(); iterator
234: .hasNext();) {
235: RepositoryTreeNode item = (RepositoryTreeNode) iterator
236: .next();
237: existingFileNames.add(item.getName());
238: }
239: String dirparent = PathUtilities
240: .extractDirectoryPath(fallback.getPath());
241: ContentItem basedir = getPageManager()
242: .getRepository().get(dirparent);
243: RepositoryTreeNode child = createNode(basedir);
244: for (Iterator iterator = child.getChildItems()
245: .iterator(); iterator.hasNext();) {
246: ContentItem basechildItem = (ContentItem) iterator
247: .next();
248: boolean okToAdd = true;
249: if (getFilter() != null) {
250: okToAdd = getFilter().passes(
251: basechildItem.getPath());
252: }
253:
254: if (!okToAdd) {
255: continue;
256: }
257:
258: RepositoryTreeNode node = createNode(basechildItem);
259: node.setParent(this );
260:
261: if (node.isLeaf()) {
262: files.add(node);
263: node.setVirtual(true);
264: //If on list already then set the full path. Kind of annoying but otherwise can't click on the virtual one
265: if (existingFileNames
266: .contains(node.fieldName)) {
267: node.setUrl(basechildItem.getPath());
268: }
269: } else {
270: if (!existingDirNames
271: .contains(node.fieldName)) {
272: directories.add(node);
273: }
274: node.setVirtual(true);
275: }
276: }
277: }
278:
279: } catch (OpenEditException e) {
280: // TODO Auto-generated catch block
281: e.printStackTrace();
282: }
283:
284: // Make sure the files appear in lexicographically increasing
285: // order, with all the directories appearing before all the files.
286: Collections.sort(directories);
287: Collections.sort(files);
288: getChildren().addAll(directories);
289: getChildren().addAll(files);
290: }
291: }
292:
293: protected List getChildItems() {
294: List items = new ArrayList();
295: if (getContentItem().isFolder()) {
296: if (getContentItem() instanceof FileItem) {
297: try {
298: FileItem item = (FileItem) getContentItem();
299: File[] files = item.getFile().listFiles();
300: String between = "/";
301: if (getContentItem().getPath().endsWith("/")) {
302: between = "";
303: }
304: for (int i = 0; i < files.length; i++) {
305:
306: items.add(getRepository().get(
307: getContentItem().getPath() + between
308: + files[i].getName()));
309: }
310: } catch (Exception e) {
311: log.error(e);
312: throw new OpenEditRuntimeException(e);
313: }
314: } else {
315: throw new OpenEditRuntimeException(
316: "Tree only works with FileItem class");
317: }
318: // /*yuck! this fails with spaces */
319: // ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
320: // InputStream inputStream = getContentItem().getInputStream();
321: // OutputFiller filler = new OutputFiller();
322: // filler.fill( inputStream, outputStream );
323: // String listing = outputStream.toString();
324: // StringTokenizer st = new StringTokenizer( listing );
325: // while( st.hasMoreTokens() )
326: // {
327: // items.add( getRepository().get( getContentItem().getPath() + "/" + st.nextToken() ) );
328: // }
329: // }
330: }
331: return items;
332: }
333:
334: /**
335: * Method createPageTreeNode.
336: *
337: * @param childFile
338: * @param path
339: *
340: * @return PageTreeNode
341: */
342: protected RepositoryTreeNode createNode(ContentItem childItem) {
343: RepositoryTreeNode node = new RepositoryTreeNode(
344: getRepository(), childItem);
345: node.setFilter(getFilter());
346: node.setPageManager(getPageManager());
347: return node;
348: }
349:
350: public ContentItem getContentItem() {
351: return fieldContentItem;
352: }
353:
354: public void setContentItem(ContentItem contentItem) {
355: fieldContentItem = contentItem;
356: }
357:
358: public Repository getRepository() {
359: return fieldRepository;
360: }
361:
362: public void setRepository(Repository repository) {
363: fieldRepository = repository;
364: }
365:
366: public PageManager getPageManager() {
367: return fieldPageManager;
368: }
369:
370: public void setPageManager(PageManager inPageManager) {
371: fieldPageManager = inPageManager;
372: }
373:
374: public String getURL() {
375: if (fieldUrl != null) {
376: return fieldUrl;
377: }
378: if (getParent() != null) {
379: String p = getParent().getURL();
380: if (p.endsWith("/")) {
381: return p + fieldName;
382: } else {
383: return p + "/" + fieldName;
384: }
385: } else {
386: return fieldName; //the root does not need a special URL since it is part of the base path
387: }
388: }
389:
390: protected void setUrl(String inPath) {
391: fieldUrl = inPath;
392: }
393:
394: public void setVirtual(boolean inVirtual) {
395: fieldVirtual = inVirtual;
396: }
397:
398: public String getIconSet() {
399: if (isVirtual()) {
400: return "linked";
401: }
402: return super .getIconSet();
403: }
404:
405: public boolean isVirtual() {
406: if (fieldVirtual) {
407: return true;
408: }
409: if (getParent() != null) {
410: return ((RepositoryTreeNode) getParent()).isVirtual();
411: }
412: return fieldVirtual;
413: }
414:
415: }
|