blob: c88cd52ff843e8c5070f344cc969e3f38ebd05bb [file] [log] [blame]
/*
* 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.transformation;
import net.sourceforge.chaperon.model.extended.ExtendedGrammar;
import net.sourceforge.chaperon.process.extended.ExtendedDirectParserProcessor;
import org.apache.avalon.excalibur.pool.Recyclable;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameterizable;
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.ProcessingException;
import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.xml.XMLConsumer;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.store.Store;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.UnmarshalHandler;
import org.exolab.castor.xml.Unmarshaller;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
/**
* @author <a href="mailto:stephan@apache.org">Stephan Michels </a>
* @version CVS $Id$
*/
public class ExtendedParserTransformer extends ExtendedDirectParserProcessor
implements Transformer, LogEnabled, Serviceable, Parameterizable,
Recyclable, Disposable, CacheableProcessingComponent
{
private String grammar = null;
private Source grammarSource = null;
private Logger logger = null;
private ServiceManager manager = null;
private SourceResolver resolver = null;
/**
* Provide component with a logger.
*
* @param logger the logger
*/
public void enableLogging(Logger logger)
{
this.logger = logger;
// TODO: check if the loglevel is correct LogKitLogger -> Logger
//setLog(new AvalonLogger(logger));
}
/**
* Pass the ServiceManager to the object. The Serviceable implementation
* should use the specified ServiceManager to acquire the services it needs
* for execution.
*
* @param manager The ServiceManager which this Serviceable uses.
*/
public void service(ServiceManager manager)
{
this.manager = manager;
}
/**
* Provide component with parameters.
*
* @param parameters the parameters
*
* @throws ParameterException if parameters are invalid
*/
public void parameterize(Parameters parameters) throws ParameterException
{
//setRecovery(parameters.getParameterAsBoolean("recovery", false));
}
/**
* Set the <code>XMLConsumer</code> that will receive XML data.
*
* @param consumer
*/
public void setConsumer(XMLConsumer consumer)
{
setContentHandler(consumer);
setLexicalHandler(consumer);
}
/**
* Set the SourceResolver, objectModel Map, the source and sitemap Parameters used to process the
* request.
*
* @param resolver Source resolver
* @param objectmodel Object model
* @param src Source
* @param parameters Parameters
*
* @throws IOException
* @throws ProcessingException
* @throws SAXException
*/
public void setup(SourceResolver resolver, Map objectmodel, String src, Parameters parameters)
throws ProcessingException, SAXException, IOException
{
this.resolver = resolver;
Store store = null;
try
{
this.grammar = src;
this.grammarSource = resolver.resolveURI(this.grammar);
// Retrieve the parser automaton from the transient store
store = (Store)this.manager.lookup(Store.TRANSIENT_STORE);
GrammarEntry entry = (GrammarEntry)store.get(this.grammarSource.getURI());
// If the parser automaton has changed, rebuild the parser automaton
if ((entry==null) || (entry.getValidity()==null) ||
((entry.getValidity().isValid(this.grammarSource.getValidity()))<=0))
{
this.logger.info("(Re)building the grammar from '"+this.grammarSource.getURI()+"'");
if (this.grammarSource.getInputStream()==null)
throw new ProcessingException("Source '"+this.grammarSource.getURI()+"' not found");
Mapping mapping = new Mapping();
mapping.loadMapping(new InputSource(ExtendedGrammar.class.getResource("mapping.xml")
.openStream()));
Unmarshaller unmarshaller = new Unmarshaller(ExtendedGrammar.class);
unmarshaller.setMapping(mapping);
UnmarshalHandler unmarshalHandler = unmarshaller.createHandler();
SourceUtil.toSAX(this.manager, this.grammarSource, null,
Unmarshaller.getContentHandler(unmarshalHandler));
ExtendedGrammar grammar = (ExtendedGrammar)unmarshalHandler.getObject();
if (grammar==null)
throw new ProcessingException("Error while reading the grammar from "+src);
setExtendedGrammar(grammar);
this.logger.info("Store grammar into store for '"+this.grammarSource.getURI()+"'");
store.store(this.grammarSource.getURI(),
new GrammarEntry(grammar, this.grammarSource.getValidity()));
}
else
{
this.logger.info("Getting grammar from store for '"+this.grammarSource.getURI()+"'");
setExtendedGrammar(entry.getExtendedGrammar());
}
}
catch (MappingException me)
{
throw new ProcessingException("Error while reading the grammar", me);
}
catch (SourceException se)
{
throw new ProcessingException("Error during resolving of '"+src+"'.", se);
}
catch (ServiceException se)
{
throw new ProcessingException("Could not lookup for service", se);
}
finally
{
if (store!=null)
this.manager.release(store);
}
}
/**
* Generate the unique key. This key must be unique inside the space of this component.
*
* @return The generated key hashes the src
*/
public Serializable getKey()
{
return this.grammarSource.getURI();
}
/**
* Generate the validity object.
*
* @return The generated validity object or <code>null</code> if the component is currently not
* cacheable.
*/
public SourceValidity getValidity()
{
return this.grammarSource.getValidity();
}
/**
* Recycle this component. All instance variables are set to <code>null</code>.
*/
public void recycle()
{
if ((this.resolver!=null) && (this.grammarSource!=null))
{
this.resolver.release(this.grammarSource);
this.grammarSource = null;
}
}
/**
* The dispose operation is called at the end of a components lifecycle.
*/
public void dispose()
{
if ((this.resolver!=null) && (this.grammarSource!=null))
{
this.resolver.release(this.grammarSource);
this.grammarSource = null;
}
this.manager = null;
}
/**
* This class represent a entry in a store to cache the parser automaton.
*/
public static class GrammarEntry implements Serializable {
private SourceValidity validity = null;
private ExtendedGrammar grammar = null;
/**
* Create a new entry.
*
* @param grammar Extended grammar
* @param validity Validity for the grammar file.
*/
public GrammarEntry(ExtendedGrammar grammar, SourceValidity validity)
{
this.grammar = grammar;
this.validity = validity;
}
/**
* Return the validity of the grammar file.
*
* @return Validity of the grammar file.
*/
public SourceValidity getValidity()
{
return this.validity;
}
/**
* Return the parser automaton.
*
* @return Parser automaton.
*/
public ExtendedGrammar getExtendedGrammar()
{
return this.grammar;
}
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
{
out.writeObject(validity);
out.writeObject(grammar);
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
{
validity = (SourceValidity)in.readObject();
grammar = (ExtendedGrammar)in.readObject();
}
}
}