| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.components.source.impl; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| |
| import org.apache.excalibur.source.Source; |
| import org.apache.excalibur.source.SourceException; |
| import org.apache.excalibur.source.TraversableSource; |
| |
| /** |
| * Traversable version of {@link org.apache.cocoon.components.source.impl.CachingSource}. |
| */ |
| public class TraversableCachingSource extends CachingSource implements TraversableSource { |
| |
| private CachingSourceFactory factory; |
| |
| public TraversableCachingSource(final CachingSourceFactory factory, |
| final String protocol, |
| final String uri, |
| final String sourceUri, |
| TraversableSource source, |
| int expires, |
| String cacheName, |
| boolean async, |
| boolean eventAware) { |
| super(protocol, uri, sourceUri, source, expires, cacheName, async, eventAware); |
| this.factory = factory; |
| } |
| |
| private TraversableSource getTraversableSource() { |
| return (TraversableSource) super.source; |
| } |
| |
| private TraversableSourceMeta getTraversableResponseMeta() throws IOException { |
| return (TraversableSourceMeta) getResponseMeta(); |
| } |
| |
| // ---------------------------------------------------- TraversableSource implementation |
| |
| public String getName() { |
| try { |
| return getTraversableResponseMeta().getName(); |
| } catch (IOException e) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("Failure initializing traversable response", e); |
| } |
| return null; |
| } |
| } |
| |
| public boolean isCollection() { |
| try { |
| return getTraversableResponseMeta().isCollection(); |
| } catch (IOException e) { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("Failure initializing traversable response", e); |
| } |
| return false; |
| } |
| } |
| |
| public Source getChild(String name) throws SourceException { |
| if (!isCollection()) { |
| throw new SourceException("Source is not a collection"); |
| } |
| |
| Source child; |
| try { |
| getResponseMeta(); |
| child = getTraversableSource().getChild(name); |
| } catch (SourceException e) { |
| throw e; |
| } catch (IOException e) { |
| throw new SourceException("Failure getting child", e); |
| } |
| |
| boolean isCollection = false; |
| if (child instanceof TraversableSource) { |
| isCollection = ((TraversableSource) child).isCollection(); |
| } |
| |
| return createSource(getChildURI(super.uri, isCollection, name), getChildURI(super.sourceUri, isCollection, name), child); |
| } |
| |
| public Collection getChildren() throws SourceException { |
| final TraversableSourceMeta meta; |
| try { |
| meta = getTraversableResponseMeta(); |
| } catch (SourceException e) { |
| throw e; |
| } catch (IOException e) { |
| throw new SourceException("Failure getting child", e); |
| } |
| |
| if (!isCollection()) { |
| throw new SourceException("Source is not a collection"); |
| } |
| |
| final Collection result = new ArrayList(); |
| final String[] children = meta.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| Source child; |
| try { |
| child = getTraversableSource().getChild(children[i]); |
| } catch (IOException e) { |
| throw new SourceException("Failure getting child", e); |
| } |
| |
| boolean isCollection = false; |
| if (child instanceof TraversableSource) { |
| isCollection = ((TraversableSource) child).isCollection(); |
| } |
| |
| result.add(createSource(getChildURI(super.uri, isCollection, children[i]), getChildURI(super.sourceUri, isCollection, children[i]), child)); |
| } |
| |
| return result; |
| } |
| |
| public Source getParent() throws SourceException { |
| Source parent; |
| try { |
| getResponseMeta(); |
| parent = getTraversableSource().getParent(); |
| } catch (SourceException e) { |
| throw e; |
| } catch (IOException e) { |
| throw new SourceException("Failure getting parent", e); |
| } |
| |
| return createSource(getParentURI(super.uri), getParentURI(super.sourceUri), parent); |
| } |
| |
| |
| // ---------------------------------------------------- helper methods |
| |
| protected final TraversableCachingSource createSource(String uri, String wrappedUri, Source wrapped) |
| throws SourceException { |
| return (TraversableCachingSource) this.factory.createCachingSource(uri, wrappedUri, wrapped, expires, cacheName); |
| } |
| |
| protected SourceMeta readMeta(Source source) throws SourceException { |
| return new TraversableSourceMeta(source); |
| } |
| |
| /** |
| * Calculate the cached child URI based on a parent URI |
| * and a child name. |
| */ |
| private static String getChildURI(String parentURI, boolean isCollection, String childName) { |
| // separate query string from rest of parentURI |
| String rest, qs; |
| int index = parentURI.indexOf('?'); |
| if (index != -1) { |
| rest = parentURI.substring(0,index); |
| qs = parentURI.substring(index); |
| } else { |
| rest = parentURI; |
| qs = ""; |
| } |
| |
| // calculate child uri |
| StringBuffer childURI = new StringBuffer(rest); |
| if (rest.charAt(rest.length()-1) != '/') { |
| childURI.append('/'); |
| } |
| childURI.append(childName); |
| if (isCollection) { |
| childURI.append('/'); |
| } |
| childURI.append(qs); |
| return childURI.toString(); |
| } |
| |
| /** |
| * Calculate the cached parent URI based on a child URI. |
| */ |
| private static String getParentURI(String childURI) { |
| // separate query string from rest of uri |
| String rest, qs; |
| int index = childURI.indexOf('?'); |
| if (index != -1) { |
| rest = childURI.substring(0, index); |
| qs = childURI.substring(index); |
| } else { |
| rest = childURI; |
| qs = ""; |
| } |
| |
| // calculate qs-less parent uri |
| String parentUri; |
| index = rest.lastIndexOf('/', rest.length() - 2); |
| if (index != -1) { |
| parentUri = rest.substring(0, index + 1); |
| } else { |
| parentUri = rest; |
| } |
| |
| return parentUri + qs; |
| } |
| |
| protected static class TraversableSourceMeta extends SourceMeta { |
| private String m_name; |
| private boolean m_isCollection; |
| private String[] m_children; |
| |
| public TraversableSourceMeta() { |
| super(); |
| } |
| |
| public TraversableSourceMeta(Source source) throws SourceException { |
| super(source); |
| |
| final TraversableSource tsource = (TraversableSource) source; |
| |
| setName(tsource.getName()); |
| setIsCollection(tsource.isCollection()); |
| |
| if (isCollection()) { |
| final Collection children = tsource.getChildren(); |
| if (children != null) { |
| final String[] names = new String[children.size()]; |
| final Iterator iter = children.iterator(); |
| int count = 0; |
| while(iter.hasNext()) { |
| TraversableSource child = (TraversableSource) iter.next(); |
| names[count] = child.getName(); |
| count++; |
| } |
| setChildren(names); |
| } |
| } |
| } |
| |
| protected String getName() { |
| return m_name; |
| } |
| |
| protected void setName(String name) { |
| m_name = name; |
| } |
| |
| protected boolean isCollection() { |
| return m_isCollection; |
| } |
| |
| protected void setIsCollection(boolean isCollection) { |
| m_isCollection = isCollection; |
| } |
| |
| protected String[] getChildren() { |
| return m_children; |
| } |
| |
| protected void setChildren(String[] children) { |
| m_children = children; |
| } |
| } |
| |
| } |