001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.forms.formmodel.tree;
018:
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.Iterator;
022: import java.util.List;
023:
024: import org.apache.avalon.framework.CascadingRuntimeException;
025: import org.apache.cocoon.util.WildcardMatcherHelper;
026: import org.apache.excalibur.source.SourceException;
027: import org.apache.excalibur.source.SourceResolver;
028: import org.apache.excalibur.source.TraversableSource;
029:
030: /**
031: * A {@link TreeModel} that builds a hierarchy of <code>TraversableSource</code>s.
032: *
033: * @version $Id: SourceTreeModel.java 551088 2007-06-27 08:10:00Z jreijn $
034: */
035: public class SourceTreeModel implements TreeModel {
036:
037: private TreeModelHelper helper = new TreeModelHelper(this );
038:
039: private List fileIncludePatterns;
040: private List fileExcludePatterns;
041: private List dirIncludePatterns;
042: private List dirExcludePatterns;
043:
044: /** optimization hint: don't filter child collections if there are no patterns */
045: private boolean hasPatterns = false;
046:
047: private TraversableSource rootSource;
048:
049: private String rootURL;
050: private SourceResolver resolver;
051:
052: public SourceTreeModel(SourceResolver resolver, String rootURL) {
053: this .resolver = resolver;
054: this .rootURL = rootURL;
055: }
056:
057: public SourceTreeModel(SourceTreeModelDefinition definition) {
058: this .rootURL = definition.getRootURL();
059: this .resolver = definition.getResolver();
060: this .fileIncludePatterns = definition.getFileIncludePatterns();
061: this .fileExcludePatterns = definition.getFileExcludePatterns();
062: this .dirIncludePatterns = definition
063: .getDirectoryIncludePatterns();
064: this .dirExcludePatterns = definition
065: .getDirectoryExcludePatterns();
066:
067: this .hasPatterns = this .fileIncludePatterns != null
068: || this .fileExcludePatterns != null
069: || this .dirIncludePatterns != null
070: || this .dirExcludePatterns != null;
071: }
072:
073: public Object getRoot() {
074: if (this .rootSource == null) {
075: try {
076: this .rootSource = (TraversableSource) this .resolver
077: .resolveURI(this .rootURL);
078: } catch (Exception e) {
079: throw new CascadingRuntimeException("Cannot resolve "
080: + this .rootURL, e);
081: }
082: }
083: return this .rootSource;
084: }
085:
086: public Collection getChildren(Object parent) {
087: if (parent instanceof TraversableSource) {
088: TraversableSource dir = (TraversableSource) parent;
089: try {
090: // Return children if it's a collection, null otherwise
091: return dir.isCollection() ? filterChildren(dir
092: .getChildren()) : null;
093: } catch (SourceException e) {
094: throw new CascadingRuntimeException("getChildren", e);
095: }
096: } else {
097: return null;
098: }
099: }
100:
101: private Collection filterChildren(Collection coll) {
102: if (!this .hasPatterns) {
103: return coll;
104: }
105:
106: ArrayList result = new ArrayList();
107: Iterator iter = coll.iterator();
108: while (iter.hasNext()) {
109: TraversableSource src = (TraversableSource) iter.next();
110:
111: // Does it match the patterns?
112: boolean matches = true;
113: if (src.isCollection()) {
114: matches = matches(src, this .dirIncludePatterns,
115: this .dirExcludePatterns);
116: } else {
117: matches = matches(src, this .fileIncludePatterns,
118: this .fileExcludePatterns);
119: }
120:
121: if (matches) {
122: result.add(src);
123: }
124: }
125:
126: return result;
127: }
128:
129: private boolean matches(TraversableSource src, List includes,
130: List excludes) {
131: boolean matches = true;
132: final String name = src.getName();
133:
134: // check include patterns
135: if (includes != null && includes.size() > 0) {
136: matches = false;
137: check: for (int i = 0; i < includes.size(); i++) {
138: if (WildcardMatcherHelper.match((String) includes
139: .get(i), name) != null) {
140: matches = true;
141: break check;
142: }
143: }
144: }
145:
146: // check exclude patterns
147: if (matches && excludes != null && excludes.size() > 0) {
148: check: for (int i = 0; i < excludes.size(); i++) {
149: if (WildcardMatcherHelper.match((String) excludes
150: .get(i), name) != null) {
151: matches = false;
152: break check;
153: }
154: }
155: }
156: return matches;
157: }
158:
159: public boolean isLeaf(Object obj) {
160: return !(obj instanceof TraversableSource)
161: || !((TraversableSource) obj).isCollection();
162: }
163:
164: public String getChildKey(Object parent, Object child) {
165: return ((TraversableSource) child).getName();
166: }
167:
168: public Object getChild(Object parent, String key) {
169: try {
170: return ((TraversableSource) parent).getChild(key);
171: } catch (SourceException e) {
172: throw new CascadingRuntimeException("getChild", e);
173: }
174: }
175:
176: public void setRootURL(String url) {
177: if (this .rootSource != null) {
178: this .resolver.release(this .rootSource);
179: this .rootSource = null;
180: }
181: this .rootURL = url;
182: helper.fireTreeStructureChanged(TreePath.ROOT_PATH);
183: }
184:
185: public void setRootSource(TraversableSource src) {
186: this .rootSource = src;
187: helper.fireTreeStructureChanged(TreePath.ROOT_PATH);
188: }
189:
190: public void addTreeModelListener(TreeModelListener l) {
191: helper.addTreeModelListener(l);
192: }
193:
194: public void removeTreeModelListener(TreeModelListener l) {
195: helper.removeTreeModelListener(l);
196: }
197:
198: public Object getNode(TreePath path) {
199: // FIXME: can be heavily optimized by building a new URL from the path elements.
200: return helper.getNode(path);
201: }
202: }
|