| /* |
| * Copyright 1999-2004 The Apache Software Foundation. |
| * |
| * Licensed 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.InputStream; |
| import java.io.IOException; |
| import java.io.ByteArrayInputStream; |
| import java.net.MalformedURLException; |
| import java.util.Map; |
| |
| import org.apache.avalon.framework.configuration.ConfigurationException; |
| import org.apache.avalon.framework.logger.Logger; |
| import org.apache.avalon.framework.service.ServiceException; |
| import org.apache.avalon.framework.service.ServiceManager; |
| import org.apache.avalon.framework.service.ServiceSelector; |
| |
| import org.apache.excalibur.source.Source; |
| import org.apache.excalibur.source.SourceException; |
| import org.apache.excalibur.source.impl.AbstractSource; |
| |
| import org.apache.cocoon.components.modules.input.InputModule; |
| |
| import org.apache.commons.jxpath.JXPathContext; |
| |
| |
| /** |
| * A <code>Source</code> that takes its content from a |
| * module. |
| * <p>The URI syntax is |
| * "module:<input-module>:<attribute-name>[#XPath]", |
| * where : |
| * <ul> |
| * <li>an input-module name is used for finding an input-module for reading data from</li>, |
| * <li>"attribute-name" is the name of the attribute found in the module</li>, |
| * <li>"XPath" is an XPath that is aplied on the object in the |
| * attribute, by using JXPath.</li> |
| * </ul> |
| * </p> |
| * |
| */ |
| public class ModuleSource |
| extends AbstractSource { |
| |
| private final static String SCHEME = "module"; |
| private String attributeType; |
| private String attributeName; |
| private String xPath; |
| private ServiceManager manager; |
| private Map objectModel; |
| private Logger logger; |
| |
| /** |
| * Create a module source from a 'module:' uri and a the object model. |
| * <p>The uri is of the form "module:attribute-type:attribute-name#xpath</p> |
| */ |
| public ModuleSource( Map objectModel, String uri, |
| ServiceManager manager, Logger logger ) |
| throws MalformedURLException { |
| |
| this.objectModel = objectModel; |
| this.manager = manager; |
| this.logger = logger; |
| |
| setSystemId( uri ); |
| |
| // Scheme |
| int start = 0; |
| int end = uri.indexOf( ':' ); |
| if ( end == -1 ) |
| throw new MalformedURLException("Malformed uri for module source (cannot find scheme) : " + uri); |
| |
| String scheme = uri.substring( start, end ); |
| if ( !SCHEME.equals( scheme ) ) |
| throw new MalformedURLException("Malformed uri for a module source : " + uri); |
| |
| setScheme( scheme ); |
| |
| // Attribute type |
| start = end + 1; |
| end = uri.indexOf( ':', start ); |
| if ( end == -1 ) { |
| throw new MalformedURLException("Malformed uri for module source (cannot find attribute type) : " + uri); |
| } |
| this.attributeType = uri.substring( start, end ); |
| |
| // Attribute name |
| start = end + 1; |
| end = uri.indexOf( '#', start ); |
| |
| if ( end == -1 ) |
| end = uri.length(); |
| |
| if ( end == start ) |
| throw new MalformedURLException("Malformed uri for module source (cannot find attribute name) : " + uri); |
| |
| this.attributeName = uri.substring( start, end ); |
| |
| // xpath |
| start = end + 1; |
| this.xPath = start < uri.length() ? uri.substring( start ) : ""; |
| } |
| |
| /** |
| * Return an <code>InputStream</code> object to read from the source. |
| * |
| * @throws IOException if I/O error occured. |
| */ |
| public InputStream getInputStream() throws IOException, SourceException { |
| if ( this.logger.isDebugEnabled() ) { |
| this.logger.debug( "Getting InputStream for " + getURI() ); |
| } |
| |
| Object obj = getInputAttribute( this.attributeType, this.attributeName ); |
| if ( obj == null ) |
| throw new SourceException( " The attribute: " + this.attributeName + |
| " is empty" ); |
| |
| if ( !(this.xPath.length() == 0 || this.xPath.equals( "/" )) ) { |
| JXPathContext context = JXPathContext.newContext( obj ); |
| obj = context.getValue( this.xPath ); |
| |
| if ( obj == null ) |
| throw new SourceException( "the xpath: " + this.xPath + |
| " applied on the attribute: " + |
| this.attributeName + |
| " returns null"); |
| } |
| |
| if ( obj instanceof InputStream ) { |
| return (InputStream)obj; |
| } else if ( obj instanceof Source ) { |
| return ((Source)obj).getInputStream(); |
| } else if ( obj instanceof String ) { |
| return new ByteArrayInputStream( ((String)obj).getBytes() ); |
| } else if (obj instanceof byte[]) { |
| return new ByteArrayInputStream((byte[]) obj); |
| } else { |
| throw new SourceException( "The object type: " + obj.getClass() + |
| " could not be serialized as a InputStream " + obj ); |
| } |
| } |
| |
| /** |
| * Does this source actually exist ? |
| * |
| * @return true if the resource exists. |
| * |
| */ |
| public boolean exists() { |
| boolean exists = false; |
| try { |
| exists = getInputAttribute( this.attributeType, this.attributeName ) != null; |
| } catch ( SourceException e ) { |
| exists = false; |
| } |
| return exists; |
| } |
| |
| private Object getInputAttribute( String inputModuleName, String attributeName ) |
| throws SourceException { |
| Object obj; |
| ServiceSelector selector = null; |
| InputModule inputModule = null; |
| try { |
| selector = (ServiceSelector) this.manager.lookup( InputModule.ROLE + "Selector" ); |
| inputModule = (InputModule) selector.select( inputModuleName ); |
| obj = inputModule.getAttribute( attributeName, null, this.objectModel ); |
| |
| } catch ( ServiceException e ) { |
| throw new SourceException( "Could not find an InputModule of the type " + |
| inputModuleName , e ); |
| } catch ( ConfigurationException e ) { |
| throw new SourceException( "Could not find an attribute: " + attributeName + |
| " from the InputModule " + inputModuleName, e ); |
| } finally { |
| if ( inputModule != null ) selector.release( inputModule ); |
| this.manager.release( selector ); |
| } |
| |
| return obj; |
| } |
| } |