/* * 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.generation; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.Map; 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.parameters.ParameterException; 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.ServiceSelector; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.caching.CacheableProcessingComponent; import org.apache.cocoon.caching.validity.Event; import org.apache.cocoon.caching.validity.EventFactory; import org.apache.cocoon.caching.validity.EventValidity; import org.apache.cocoon.caching.validity.NameValueEventFactory; import org.apache.cocoon.caching.validity.NamedEventFactory; import org.apache.cocoon.environment.SourceResolver; import org.apache.cocoon.xml.XMLConsumer; import org.apache.excalibur.source.SourceUtil; import org.apache.excalibur.source.SourceValidity; import org.xml.sax.SAXException; /** * Generator wrapper that forwards generation to * to its delegate but overides its caching strategy * by replacing it with an event-cache aware implementation. * * <p> * Sitemap configuration is as follows:<br> * <map:generator name="event-cache" src="org.apache.cocoon.generation.EventCacheGenerator" ><br> *   <factory name="my-event" value="com.my.EventFactoryImpl" /><br> *   <factory name="my-other-event" value="com.myother.EventFactoryImpl" /><br> * </map:generator><br> * </p> * * Two event types are preconfigured: NamedEvent (name="named") and NameValueEvent * (name="name-value"). * * <p> * Pipeline usage is as follows:<br> * <map:generate type="event-cache" src="delegate-src"><br> *   <map:parameter name="delegate" value="delegate-type" /><br> *   <map:parameter name="event-type" value="my-event" /><br> *   <!-- my event parameters --><br> *   <map:parameter name="event-name" value="some name" /><br> *   <map:parameter name="event-value" value="some value" /><br> * </map:generate> * </p> * * The two preconfigured event types take the following parameters:<br> * - event-type 'named': parameter 'event-name'<br> * - event-type 'name-value': parameter 'event-name' and parameter 'event-value'<br> * * <p> * The src attribute and all parameters are passed as is to delegate generator. * </p> * * TODO: share common code with EventCacheTransformer * @author Unico Hommes */ public class EventCacheGenerator extends ServiceableGenerator implements Configurable, CacheableProcessingComponent { // ---------------------------------------------------- constants public static final String NAME_VALUE_EVENT_TYPE = "name-value"; public static final String EVENT_TYPE_DEFAULT = "named"; public static final String NAMED_EVENT_TYPE = EVENT_TYPE_DEFAULT; public static final String FACTORY_CONF = "factory"; public static final String FACTORY_NAME_CONF = "name"; public static final String FACTORY_NAME_TYPE = "src"; public static final String DELEGATE_PARAM = "delegate"; public static final String EVENT_TYPE_PARAM = "event-type"; // ---------------------------------------------------- member variables private ServiceSelector m_generatorSelector; private Generator m_delegate; private Serializable m_key; private Event m_event; private Map m_types = new HashMap(); /* (non-Javadoc) * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) */ public void service(ServiceManager manager) throws ServiceException { super.service(manager); m_generatorSelector = (ServiceSelector) manager.lookup(Generator.ROLE + "Selector"); } /* (non-Javadoc) * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration) */ public void configure(Configuration configuration) throws ConfigurationException { Configuration[] factories = configuration.getChildren(FACTORY_CONF); for (int i = 0; i < factories.length; i++) { Configuration child = factories[i]; String name = child.getAttribute(FACTORY_NAME_CONF); String src = child.getAttribute(FACTORY_NAME_TYPE); try { EventFactory factory = (EventFactory) Class.forName(src).newInstance(); m_types.put(name,factory); } catch (Exception e) { final String message = "Unable to create EventFactory of type " + src; throw new ConfigurationException(message, e); } } if (!m_types.containsKey(NAMED_EVENT_TYPE)) { m_types.put(NAMED_EVENT_TYPE,new NamedEventFactory()); } if (!m_types.containsKey(NAME_VALUE_EVENT_TYPE)) { m_types.put(NAME_VALUE_EVENT_TYPE,new NameValueEventFactory()); } } /* (non-Javadoc) * @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 { // delegate String delegate = par.getParameter(DELEGATE_PARAM, null); if (delegate == null) { String message = "Required parameter 'delegate' is missing"; throw new ProcessingException(message); } try { m_delegate = (Generator) m_generatorSelector.select(delegate); } catch (ServiceException e) { final String message = "Generator '" + delegate + "' could not be found."; throw new ProcessingException(message); } m_delegate.setup(resolver, objectModel, src, par); // event String eventType = par.getParameter(EVENT_TYPE_PARAM, EVENT_TYPE_DEFAULT); EventFactory factory = (EventFactory) m_types.get(eventType); if (factory == null) { throw new ProcessingException("No such type of event: " + eventType); } try { m_event = factory.createEvent(par); } catch (ParameterException e) { final String message = "Failure creating Event"; throw new ProcessingException(message,e); } // key - TODO: use delegates key? m_key = SourceUtil.appendParameters(src,par); } /* (non-Javadoc) * @see org.apache.cocoon.xml.XMLProducer#setConsumer(org.apache.cocoon.xml.XMLConsumer) */ public void setConsumer(XMLConsumer consumer) { m_delegate.setConsumer(consumer); } /* (non-Javadoc) * @see org.apache.cocoon.generation.Generator#generate() */ public void generate() throws IOException, SAXException, ProcessingException { m_delegate.generate(); } /* (non-Javadoc) * @see org.apache.avalon.excalibur.pool.Recyclable#recycle() */ public void recycle() { if ( m_delegate != null ) { m_generatorSelector.release(m_delegate); } m_delegate = null; m_key = null; m_event = null; super.recycle(); } /* (non-Javadoc) * @see org.apache.cocoon.caching.CacheableProcessingComponent#getKey() */ public Serializable getKey() { return m_key; } /* (non-Javadoc) * @see org.apache.cocoon.caching.CacheableProcessingComponent#getValidity() */ public SourceValidity getValidity() { return new EventValidity(m_event); } /* (non-Javadoc) * @see org.apache.avalon.framework.activity.Disposable#dispose() */ public void dispose() { if ( this.manager != null ) { this.manager.release(m_generatorSelector); m_generatorSelector = null; } super.dispose(); } }