blob: 541af0b4c5e826d9c547bed6e6fe72711f6fd795 [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.sitemap.impl;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.context.DefaultContext;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.cocoon.components.source.impl.SitemapSourceInfo;
import org.apache.cocoon.components.pipeline.VirtualProcessingPipeline;
import org.apache.cocoon.components.treeprocessor.InvokeContext;
import org.apache.cocoon.components.treeprocessor.ProcessingNode;
import org.apache.cocoon.components.treeprocessor.sitemap.VPCNode;
import org.apache.cocoon.environment.Environment;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.internal.EnvironmentHelper;
import org.apache.cocoon.environment.wrapper.EnvironmentWrapper;
import org.apache.cocoon.sitemap.SitemapModelComponent;
import org.apache.cocoon.xml.AbstractXMLPipe;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.xml.sax.XMLizable;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* TODO List:
* <ul>
* <li>Refactor ProcessingPipelines implementations
* <li>Implement caching
* </ul>
*/
public abstract class AbstractVirtualSitemapComponent extends AbstractXMLPipe
implements SitemapModelComponent, Serviceable, Contextualizable, Configurable {
private ProcessingNode node;
private String sourceMapName;
private Map sourceMap = new HashMap();
private Set sources;
private VirtualProcessingPipeline pipeline;
// An environment containing a map with the souces from the calling environment
private EnvironmentWrapper mappedSourceEnvironment;
// An environment with the URI and URI prefix of the sitemap where the VPC is defined
private EnvironmentWrapper vpcEnvironment;
protected DefaultContext context;
protected SourceResolver resolver;
protected ServiceManager manager;
private class MyInvokeContext extends InvokeContext {
public MyInvokeContext(Logger logger) throws Exception {
super(true);
super.processingPipeline = new VirtualProcessingPipeline(AbstractVirtualSitemapComponent.this.context);
((VirtualProcessingPipeline)super.processingPipeline).enableLogging(logger);
}
}
abstract protected String getTypeName();
/**
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(Context context) throws ContextException {
this.context = (DefaultContext)context;
}
/**
* @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
*/
public void service(ServiceManager manager) throws ServiceException {
this.manager = manager;
}
/**
* Release all resources.
*/
public void recycle() {
// FIXME
// These are allready disposed, why?
//Iterator sources = this.sourceMap.values().iterator();
//while (sources.hasNext()) {
// Source source = (Source)sources.next();
// this.resolver.release(source);
//}
this.sourceMap.clear();
super.recycle();
}
/**
* @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
public void configure(Configuration configuration) throws ConfigurationException {
String name = configuration.getAttribute("name");
this.sourceMapName =
Constants.CONTEXT_ENV_PREFIX + "-" + getTypeName() + "-source-map-" + name;
try {
this.node = (ProcessingNode)this.context.get(Constants.CONTEXT_VPC_PREFIX +
getTypeName() + "-" + name);
this.sources = ((VPCNode)node).getSources();
} catch (Exception e) {
throw new ConfigurationException("Can not find VirtualPipelineComponent '" +
name + "' configuration");
}
}
/**
* @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
*/
public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
throws ProcessingException, SAXException, IOException {
this.resolver = resolver;
Environment env = EnvironmentHelper.getCurrentEnvironment();
// Hack to get an info object with the right uri for the
// current sitemap, there is no vpc protocol.
SitemapSourceInfo mappedSourceEnvironmentInfo =
SitemapSourceInfo.parseURI(env, "vpc:/");
this.mappedSourceEnvironment =
new EnvironmentWrapper(env, mappedSourceEnvironmentInfo, getLogger());
// place for resolved sources
this.mappedSourceEnvironment.setAttribute(this.sourceMapName, this.sourceMap);
MyInvokeContext invoker = null;
try {
// resolve the sources in the parameter map before switching context
Map resolvedParams = resolveParams(par, src);
// set up info object for VPC environment wrapper, would
// better be done in a constructor for the info.
SitemapSourceInfo vpcEnvironmentInfo = new SitemapSourceInfo();
vpcEnvironmentInfo.prefix = (String) this.context.get(Constants.CONTEXT_ENV_PREFIX);
vpcEnvironmentInfo.uri = (String) this.context.get(Constants.CONTEXT_ENV_URI);
vpcEnvironmentInfo.requestURI = vpcEnvironmentInfo.prefix + vpcEnvironmentInfo.uri;
vpcEnvironmentInfo.rawMode = false;
// set up the vpc environment
this.vpcEnvironment =
new EnvironmentWrapper(this.mappedSourceEnvironment,
vpcEnvironmentInfo, getLogger());
EnvironmentHelper.enterEnvironment(this.vpcEnvironment);
// set up invoker with sitemap params
invoker = new MyInvokeContext(getLogger());
invoker.enableLogging(getLogger());
invoker.service(this.manager);
invoker.pushMap(null, resolvedParams);
this.node.invoke(this.vpcEnvironment, invoker);
this.pipeline = (VirtualProcessingPipeline)invoker.getProcessingPipeline();
} catch (Exception e) {
throw new ProcessingException("Oops", e);
} finally {
if (invoker != null) {
invoker.popMap();
invoker.dispose();
}
// Restore context
EnvironmentHelper.leaveEnvironment();
}
}
protected VirtualProcessingPipeline getPipeline() {
return this.pipeline;
}
// An environment containing a map with the souces from the calling environment
protected EnvironmentWrapper getMappedSourceEnvironment() {
return this.mappedSourceEnvironment;
}
// An environment with the URI and URI prefix of the sitemap where the VPC is defined
protected EnvironmentWrapper getVPCEnvironment() {
return this.vpcEnvironment;
}
private Map resolveParams(Parameters par, String src)
throws ProcessingException, IOException {
HashMap map = new HashMap();
// resolve and map params
String[] names = par.getNames();
for(int i=0; i<names.length; i++) {
String name = names[i];
String value = par.getParameter(name, null);
if (this.sources.contains(name)) {
value = resolveAndMapSourceURI(name, value);
}
map.put(name, value);
}
// resolve and map src
if (src != null) {
map.put("src", resolveAndMapSourceURI("src", src));
}
return map;
}
private String resolveAndMapSourceURI(String name, String uri)
throws ProcessingException, IOException {
// Resolve the URI
Source src = null;
try {
src = this.resolver.resolveURI(uri);
} catch (SourceException se) {
throw SourceUtil.handle("Error during resolving of " + uri, se);
}
// Save the source
this.sourceMap.put(name, src);
// Create a new URI that refers to the source in the context
String mappedURI;
if (src instanceof XMLizable) {
mappedURI = "xmodule:environment-attr:" + this.sourceMapName + "#" + name;
} else {
mappedURI = "module:environment-attr:" + this.sourceMapName + "#" + name;
}
return mappedURI;
}
}