blob: 6a4cca94e9653f7b234c7f0c5dbfa125a95274c8 [file] [log] [blame]
/*
* 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;
}
}
}