blob: 8d7ea4c140653931e5141231df2ac033e50baae9 [file] [log] [blame]
/*
* 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;
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: SitemapSource.java,v 1.6 2004/03/05 13:02:40 bdelacretaz Exp $
*/
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.getCurrentProcessor();
} 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.getLastProcessor(this.environment);
this.environment.changeToLastContext();
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();
}
}