/* * 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; import org.apache.avalon.framework.component.ComponentException; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.logger.Logger; import org.apache.excalibur.source.SourceException; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.Processor; import org.apache.cocoon.components.CocoonComponentManager; import org.apache.cocoon.components.pipeline.ProcessingPipeline; import org.apache.cocoon.components.sax.XMLDeserializer; import org.apache.cocoon.components.sax.XMLSerializer; import org.apache.cocoon.environment.Environment; import org.apache.cocoon.environment.ModifiableSource; import org.apache.cocoon.environment.wrapper.EnvironmentWrapper; import org.apache.cocoon.xml.AbstractXMLConsumer; import org.apache.cocoon.xml.ContentHandlerWrapper; import org.apache.cocoon.xml.XMLConsumer; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; /** * Description of a source which is defined by a pipeline. * * @deprecated by the Avalon Excalibur Source Resolving * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a> * @version CVS $Id$ */ public final class SitemapSource extends AbstractXMLConsumer implements ModifiableSource { /** The last modification date or 0 */ private long lastModificationDate; /** The system id */ private String systemId; /** The uri */ private String uri; /** The current ComponentManager */ private ComponentManager manager; /** The processor */ private Processor processor; /** The pipeline processor */ private Processor pipelineProcessor; /** The environment */ private EnvironmentWrapper environment; /** The prefix for the processing */ private String prefix; /** The <code>ProcessingPipeline</code> */ private ProcessingPipeline processingPipeline; /** The redirect <code>Source</code> */ private org.apache.excalibur.source.Source redirectSource; /** The <code>SAXException</code> if unable to get resource */ private SAXException exception; /** Do I need a refresh ? */ private boolean needsRefresh; /** The unique key for this processing */ private Object processKey; /** * Construct a new object */ public SitemapSource(ComponentManager manager, String uri, Logger logger) throws IOException, ProcessingException { Environment env = CocoonComponentManager.getCurrentEnvironment(); if ( env == null ) { throw new MalformedURLException("The cocoon protocol can not be used outside an environment."); } this.manager = manager; this.enableLogging(logger); boolean rawMode = false; // remove the protocol int position = uri.indexOf(':') + 1; if (position != 0) { // check for subprotocol if (uri.startsWith("raw:", position)) { position += 4; rawMode = true; } } // does the uri point to this sitemap or to the root sitemap? if (uri.startsWith("//", position)) { position += 2; try { this.processor = (Processor)this.manager.lookup(Processor.ROLE); } catch (ComponentException e) { throw new ProcessingException("Cannot get Processor instance", e); } this.prefix = ""; // start at the root } else if (uri.startsWith("/", position)) { position ++; this.prefix = null; this.processor = CocoonComponentManager.getActiveProcessor(env); } else { throw new ProcessingException("Malformed cocoon URI."); } // create the queryString (if available) String queryString = null; int queryStringPos = uri.indexOf('?', position); if (queryStringPos != -1) { queryString = uri.substring(queryStringPos + 1); uri = uri.substring(position, queryStringPos); } else if (position > 0) { uri = uri.substring(position); } // build the request uri which is relative to the context String requestURI = (this.prefix == null ? env.getURIPrefix() + uri : uri); // create system ID this.systemId = queryString == null ? "cocoon://" + requestURI : "cocoon://" + requestURI + "?" + queryString; this.environment = new EnvironmentWrapper(env, requestURI, queryString, logger, manager, rawMode); this.uri = uri; this.refresh(); } /** * Get the last modification date of the source or 0 if it * is not possible to determine the date. */ public long getLastModified() { if (this.needsRefresh) { this.refresh(); } return this.lastModificationDate; } /** * Get the content length of the source or -1 if it * is not possible to determine the length. */ public long getContentLength() { return -1; } /** * Return an <code>InputStream</code> object to read from the source. */ public InputStream getInputStream() throws ProcessingException, IOException { if (this.needsRefresh) { this.refresh(); } // VG: Why exception is not thrown in constructor? if (this.exception != null) { throw new ProcessingException(this.exception); } if (this.redirectSource != null) { try { return this.redirectSource.getInputStream(); } catch (SourceException se) { throw SourceUtil.handle(se); } } try { ByteArrayOutputStream os = new ByteArrayOutputStream(); this.environment.setOutputStream(os); CocoonComponentManager.enterEnvironment(this.environment, this.manager, this.pipelineProcessor); try { this.processingPipeline.process(this.environment); } finally { CocoonComponentManager.leaveEnvironment(); } return new ByteArrayInputStream(os.toByteArray()); } catch (ProcessingException e) { throw e; } catch (Exception e) { throw new ProcessingException("Exception during processing of " + this.systemId, e); } finally { // Unhide wrapped environment output stream this.environment.setOutputStream(null); reset(); } } /** * Return the unique identifer for this source */ public String getSystemId() { return this.systemId; } /** * Refresh this object and update the last modified date * and content length. */ public void refresh() { reset(); try { this.processKey = CocoonComponentManager.startProcessing(this.environment); this.environment.setURI(this.prefix, this.uri); this.processingPipeline = this.processor.buildPipeline(this.environment); this.pipelineProcessor = CocoonComponentManager.getActiveProcessor(this.environment); String redirectURL = this.environment.getRedirectURL(); if (redirectURL != null) { if (redirectURL.indexOf(":") == -1) { redirectURL = "cocoon:/" + redirectURL; } this.redirectSource = this.environment.resolveURI(redirectURL); this.lastModificationDate = this.redirectSource.getLastModified(); } } catch (SAXException e) { reset(); this.exception = e; } catch (Exception e) { reset(); this.exception = new SAXException("Could not get sitemap source " + this.systemId, e); } this.needsRefresh = false; } /** * Return a new <code>InputSource</code> object */ public InputSource getInputSource() throws ProcessingException, IOException { InputSource newObject = new InputSource(this.getInputStream()); newObject.setSystemId(this.systemId); return newObject; } /** * Stream content to the content handler */ public void toSAX(ContentHandler contentHandler) throws SAXException { if (this.needsRefresh) { this.refresh(); } if (this.exception != null) { throw this.exception; } try { XMLConsumer consumer; if (contentHandler instanceof XMLConsumer) { consumer = (XMLConsumer)contentHandler; } else if (contentHandler instanceof LexicalHandler) { consumer = new ContentHandlerWrapper(contentHandler, (LexicalHandler)contentHandler); } else { consumer = new ContentHandlerWrapper(contentHandler); } if (this.redirectSource != null) { SourceUtil.parse(this.manager, this.redirectSource, consumer); } else { // We have to buffer the result in order to get // clean environment stack handling. XMLSerializer xmls = (XMLSerializer) this.manager.lookup(XMLSerializer.ROLE); Object fragment; CocoonComponentManager.enterEnvironment(this.environment, this.manager, this.pipelineProcessor); try { this.processingPipeline.process(this.environment, xmls); fragment = xmls.getSAXFragment(); } finally { this.manager.release(xmls); CocoonComponentManager.leaveEnvironment(); } XMLDeserializer xmld = (XMLDeserializer) this.manager.lookup(XMLDeserializer.ROLE); try { xmld.setConsumer(consumer); xmld.deserialize(fragment); } finally { this.manager.release(xmld); } } } catch (SAXException e) { // Preserve original exception throw e; } catch (Exception e) { throw new SAXException("Exception during processing of " + this.systemId, e); } finally { reset(); } } private void reset() { if (this.processingPipeline != null) this.processingPipeline.release(); if (this.processKey != null) { CocoonComponentManager.endProcessing(this.environment, this.processKey); this.processKey = null; } this.processingPipeline = null; this.lastModificationDate = 0; this.environment.release(this.redirectSource); this.environment.reset(); this.redirectSource = null; this.exception = null; this.needsRefresh = true; this.pipelineProcessor = null; } public void recycle() { reset(); } }