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.components.source.impl;
018:
019: import java.io.IOException;
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.Iterator;
023:
024: import org.apache.excalibur.source.Source;
025: import org.apache.excalibur.source.SourceException;
026: import org.apache.excalibur.source.TraversableSource;
027:
028: /**
029: * Traversable version of {@link org.apache.cocoon.components.source.impl.CachingSource}.
030: */
031: public class TraversableCachingSource extends CachingSource implements
032: TraversableSource {
033:
034: private CachingSourceFactory factory;
035:
036: public TraversableCachingSource(final CachingSourceFactory factory,
037: final String protocol, final String uri,
038: final String sourceUri, TraversableSource source,
039: int expires, String cacheName, boolean async,
040: boolean eventAware) {
041: super (protocol, uri, sourceUri, source, expires, cacheName,
042: async, eventAware);
043: this .factory = factory;
044: }
045:
046: private TraversableSource getTraversableSource() {
047: return (TraversableSource) super .source;
048: }
049:
050: private TraversableSourceMeta getTraversableResponseMeta()
051: throws IOException {
052: return (TraversableSourceMeta) getResponseMeta();
053: }
054:
055: // ---------------------------------------------------- TraversableSource implementation
056:
057: public String getName() {
058: try {
059: return getTraversableResponseMeta().getName();
060: } catch (IOException e) {
061: if (getLogger().isDebugEnabled()) {
062: getLogger().debug(
063: "Failure initializing traversable response", e);
064: }
065: return null;
066: }
067: }
068:
069: public boolean isCollection() {
070: try {
071: return getTraversableResponseMeta().isCollection();
072: } catch (IOException e) {
073: if (getLogger().isDebugEnabled()) {
074: getLogger().debug(
075: "Failure initializing traversable response", e);
076: }
077: return false;
078: }
079: }
080:
081: public Source getChild(String name) throws SourceException {
082: if (!isCollection()) {
083: throw new SourceException("Source is not a collection");
084: }
085:
086: Source child;
087: try {
088: getResponseMeta();
089: child = getTraversableSource().getChild(name);
090: } catch (SourceException e) {
091: throw e;
092: } catch (IOException e) {
093: throw new SourceException("Failure getting child", e);
094: }
095:
096: boolean isCollection = false;
097: if (child instanceof TraversableSource) {
098: isCollection = ((TraversableSource) child).isCollection();
099: }
100:
101: return createSource(getChildURI(super .uri, isCollection, name),
102: getChildURI(super .sourceUri, isCollection, name), child);
103: }
104:
105: public Collection getChildren() throws SourceException {
106: final TraversableSourceMeta meta;
107: try {
108: meta = getTraversableResponseMeta();
109: } catch (SourceException e) {
110: throw e;
111: } catch (IOException e) {
112: throw new SourceException("Failure getting child", e);
113: }
114:
115: if (!isCollection()) {
116: throw new SourceException("Source is not a collection");
117: }
118:
119: final Collection result = new ArrayList();
120: final String[] children = meta.getChildren();
121: for (int i = 0; i < children.length; i++) {
122: Source child;
123: try {
124: child = getTraversableSource().getChild(children[i]);
125: } catch (IOException e) {
126: throw new SourceException("Failure getting child", e);
127: }
128:
129: boolean isCollection = false;
130: if (child instanceof TraversableSource) {
131: isCollection = ((TraversableSource) child)
132: .isCollection();
133: }
134:
135: result
136: .add(createSource(getChildURI(super .uri,
137: isCollection, children[i]),
138: getChildURI(super .sourceUri, isCollection,
139: children[i]), child));
140: }
141:
142: return result;
143: }
144:
145: public Source getParent() throws SourceException {
146: Source parent;
147: try {
148: getResponseMeta();
149: parent = getTraversableSource().getParent();
150: } catch (SourceException e) {
151: throw e;
152: } catch (IOException e) {
153: throw new SourceException("Failure getting parent", e);
154: }
155:
156: return createSource(getParentURI(super .uri),
157: getParentURI(super .sourceUri), parent);
158: }
159:
160: // ---------------------------------------------------- helper methods
161:
162: protected final TraversableCachingSource createSource(String uri,
163: String wrappedUri, Source wrapped) throws SourceException {
164: return (TraversableCachingSource) this .factory
165: .createCachingSource(uri, wrappedUri, wrapped, expires,
166: cacheName);
167: }
168:
169: protected SourceMeta readMeta(Source source) throws SourceException {
170: return new TraversableSourceMeta(source);
171: }
172:
173: /**
174: * Calculate the cached child URI based on a parent URI
175: * and a child name.
176: */
177: private static String getChildURI(String parentURI,
178: boolean isCollection, String childName) {
179: // separate query string from rest of parentURI
180: String rest, qs;
181: int index = parentURI.indexOf('?');
182: if (index != -1) {
183: rest = parentURI.substring(0, index);
184: qs = parentURI.substring(index);
185: } else {
186: rest = parentURI;
187: qs = "";
188: }
189:
190: // calculate child uri
191: StringBuffer childURI = new StringBuffer(rest);
192: if (rest.charAt(rest.length() - 1) != '/') {
193: childURI.append('/');
194: }
195: childURI.append(childName);
196: if (isCollection) {
197: childURI.append('/');
198: }
199: childURI.append(qs);
200: return childURI.toString();
201: }
202:
203: /**
204: * Calculate the cached parent URI based on a child URI.
205: */
206: private static String getParentURI(String childURI) {
207: // separate query string from rest of uri
208: String rest, qs;
209: int index = childURI.indexOf('?');
210: if (index != -1) {
211: rest = childURI.substring(0, index);
212: qs = childURI.substring(index);
213: } else {
214: rest = childURI;
215: qs = "";
216: }
217:
218: // calculate qs-less parent uri
219: String parentUri;
220: index = rest.lastIndexOf('/', rest.length() - 2);
221: if (index != -1) {
222: parentUri = rest.substring(0, index + 1);
223: } else {
224: parentUri = rest;
225: }
226:
227: return parentUri + qs;
228: }
229:
230: protected static class TraversableSourceMeta extends SourceMeta {
231: private String m_name;
232: private boolean m_isCollection;
233: private String[] m_children;
234:
235: public TraversableSourceMeta() {
236: super ();
237: }
238:
239: public TraversableSourceMeta(Source source)
240: throws SourceException {
241: super (source);
242:
243: final TraversableSource tsource = (TraversableSource) source;
244:
245: setName(tsource.getName());
246: setIsCollection(tsource.isCollection());
247:
248: if (isCollection()) {
249: final Collection children = tsource.getChildren();
250: if (children != null) {
251: final String[] names = new String[children.size()];
252: final Iterator iter = children.iterator();
253: int count = 0;
254: while (iter.hasNext()) {
255: TraversableSource child = (TraversableSource) iter
256: .next();
257: names[count] = child.getName();
258: count++;
259: }
260: setChildren(names);
261: }
262: }
263: }
264:
265: protected String getName() {
266: return m_name;
267: }
268:
269: protected void setName(String name) {
270: m_name = name;
271: }
272:
273: protected boolean isCollection() {
274: return m_isCollection;
275: }
276:
277: protected void setIsCollection(boolean isCollection) {
278: m_isCollection = isCollection;
279: }
280:
281: protected String[] getChildren() {
282: return m_children;
283: }
284:
285: protected void setChildren(String[] children) {
286: m_children = children;
287: }
288: }
289:
290: }
|