/* * 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.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.logger.Logger; import org.apache.cocoon.components.source.InspectableSource; import org.apache.cocoon.components.source.SourceDescriptor; import org.apache.cocoon.components.source.helpers.SourceProperty; import org.apache.excalibur.source.ModifiableTraversableSource; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceException; import org.apache.excalibur.source.SourceNotFoundException; import org.apache.excalibur.source.SourceValidity; import org.apache.excalibur.source.impl.validity.AggregatedValidity; /** * Source wrapper that enhances the wrapped sources with additional capabilities. * * <p> * Currently this Source optionally adds inspectability * through the InspectableSource interface. * </p> * * <p> * Wrapped sources must implement ModifiableTraversableSource. * </p> */ public class RepositorySource extends AbstractLogEnabled implements Source, ModifiableTraversableSource, InspectableSource { // the original source prefix final String m_prefix; // the wrapped source final ModifiableTraversableSource m_delegate; private final SourceDescriptor m_descriptor; // ---------------------------------------------------- Lifecycle public RepositorySource( final String prefix, final ModifiableTraversableSource delegate, final SourceDescriptor descriptor, final Logger logger) throws SourceException { m_prefix = prefix; m_delegate = delegate; m_descriptor = descriptor; enableLogging(logger); } // ---------------------------------------------------- InspectableSource implementation /** * Get all source properties that are defined on the wrapped source. * If the wrapped source is itself an InspectableSource the implementation * will return the aggregate set that results from combining the properties * returned from a delegate call to the wrapped source with the * properties returned by the source descriptor. */ public SourceProperty[] getSourceProperties() throws SourceException { final List properties = new ArrayList(); if (m_delegate instanceof InspectableSource) { properties.addAll(Arrays.asList(((InspectableSource) m_delegate).getSourceProperties())); } if (m_descriptor != null) { properties.addAll(Arrays.asList(m_descriptor.getSourceProperties(m_delegate))); } return (SourceProperty[]) properties.toArray(new SourceProperty[properties.size()]); } /** * Get the source property on the wrapped source. If the wrapped source implements * InspectableSource the implementation will first try to get it from there. * If it doesn't exist on the delegate it will try to find it using the source descriptor. */ public SourceProperty getSourceProperty(String uri, String name) throws SourceException { SourceProperty property = null; if (m_delegate instanceof InspectableSource) { property = ((InspectableSource) m_delegate).getSourceProperty(uri,name); } if (property == null && m_descriptor != null) { property = m_descriptor.getSourceProperty(m_delegate,uri,name); } return property; } /** * Remove the source property on the wrapped source. If the wrapped source implements * InspectableSource the implementation will try to remove the property on both * the wrapped source directly and on the source descriptor. */ public void removeSourceProperty(String uri, String name) throws SourceException { if (m_delegate instanceof InspectableSource) { ((InspectableSource) m_delegate).removeSourceProperty(uri,name); } if (m_descriptor != null) { m_descriptor.removeSourceProperty(m_delegate,uri,name); } } /** * Set the source property on the wrapped source. If the wrapped source implements * InspectableSource set the property directly on the wrapped source. Otherwise * set it on the SourceDescriptor. */ public void setSourceProperty(SourceProperty property) throws SourceException { if (m_delegate instanceof InspectableSource) { ((InspectableSource) m_delegate).setSourceProperty(property); } else if (m_descriptor != null) { m_descriptor.setSourceProperty(m_delegate, property); } } // ---------------------------------------------------- Source implementation public boolean exists() { return m_delegate.exists(); } public long getContentLength() { return m_delegate.getContentLength(); } public InputStream getInputStream() throws IOException, SourceNotFoundException { return m_delegate.getInputStream(); } public long getLastModified() { return m_delegate.getLastModified(); } public String getMimeType() { return m_delegate.getMimeType(); } public String getScheme() { return m_prefix; } public String getURI() { return m_prefix + ":" + m_delegate.getURI(); } /** * Return a SourceValidity object describing * the validity of this Source. * <p> * If the SourceDescriptor service is present, the resulting * validity is an aggregated validity object containing both * the validity describing the source itself _and_ one describing * the validity of the SourceProperties managed by the SourceDescriptor. * </p> */ public SourceValidity getValidity() { SourceValidity val1; val1 = m_delegate.getValidity(); if (val1 != null && m_descriptor != null) { SourceValidity val2 = m_descriptor.getValidity(m_delegate); if (val2 != null) { AggregatedValidity result = new AggregatedValidity(); result.add(val1); result.add(val2); return result; } } return val1; } public void refresh() { m_delegate.refresh(); } // ---------------------------------------------------- ModifiableTraversableSource public Source getChild(String name) throws SourceException { if (!m_delegate.isCollection()) return null; ModifiableTraversableSource child = (ModifiableTraversableSource) m_delegate.getChild(name); if (child == null) return null; return new RepositorySource( m_prefix, child, m_descriptor, getLogger() ); } public Collection getChildren() throws SourceException { if (!m_delegate.isCollection()) return null; Collection result = new ArrayList(); Iterator iter = m_delegate.getChildren().iterator(); while(iter.hasNext()) { ModifiableTraversableSource child = (ModifiableTraversableSource) iter.next(); result.add( new RepositorySource( m_prefix, child, m_descriptor, getLogger() ) ); } return result; } public String getName() { return m_delegate.getName(); } public Source getParent() throws SourceException { return new RepositorySource( m_prefix, (ModifiableTraversableSource) m_delegate.getParent(), m_descriptor, getLogger() ); } public boolean isCollection() { return m_delegate.isCollection(); } public void makeCollection() throws SourceException { m_delegate.makeCollection(); } public boolean canCancel(OutputStream out) { return m_delegate.canCancel(out); } public void cancel(OutputStream out) throws IOException { m_delegate.cancel(out); } public void delete() throws SourceException { m_delegate.delete(); } public OutputStream getOutputStream() throws IOException { return m_delegate.getOutputStream(); } }