001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.generation;
018:
019: import java.io.IOException;
020: import java.io.Serializable;
021: import java.util.HashMap;
022: import java.util.Map;
023:
024: import org.apache.avalon.framework.configuration.Configurable;
025: import org.apache.avalon.framework.configuration.Configuration;
026: import org.apache.avalon.framework.configuration.ConfigurationException;
027: import org.apache.avalon.framework.parameters.ParameterException;
028: import org.apache.avalon.framework.parameters.Parameters;
029: import org.apache.avalon.framework.service.ServiceException;
030: import org.apache.avalon.framework.service.ServiceManager;
031: import org.apache.avalon.framework.service.ServiceSelector;
032: import org.apache.cocoon.ProcessingException;
033: import org.apache.cocoon.caching.CacheableProcessingComponent;
034: import org.apache.cocoon.caching.validity.Event;
035: import org.apache.cocoon.caching.validity.EventFactory;
036: import org.apache.cocoon.caching.validity.EventValidity;
037: import org.apache.cocoon.caching.validity.NameValueEventFactory;
038: import org.apache.cocoon.caching.validity.NamedEventFactory;
039: import org.apache.cocoon.environment.SourceResolver;
040: import org.apache.cocoon.xml.XMLConsumer;
041: import org.apache.excalibur.source.SourceUtil;
042: import org.apache.excalibur.source.SourceValidity;
043: import org.xml.sax.SAXException;
044:
045: /**
046: * Generator wrapper that forwards generation to
047: * to its delegate but overides its caching strategy
048: * by replacing it with an event-cache aware implementation.
049: *
050: * <p>
051: * Sitemap configuration is as follows:<br>
052: * <map:generator name="event-cache" src="org.apache.cocoon.generation.EventCacheGenerator" ><br>
053: * <factory name="my-event" value="com.my.EventFactoryImpl" /><br>
054: * <factory name="my-other-event" value="com.myother.EventFactoryImpl" /><br>
055: * </map:generator><br>
056: * </p>
057: *
058: * Two event types are preconfigured: NamedEvent (name="named") and NameValueEvent
059: * (name="name-value").
060: *
061: * <p>
062: * Pipeline usage is as follows:<br>
063: * <map:generate type="event-cache" src="delegate-src"><br>
064: * <map:parameter name="delegate" value="delegate-type" /><br>
065: * <map:parameter name="event-type" value="my-event" /><br>
066: * <!-- my event parameters --><br>
067: * <map:parameter name="event-name" value="some name" /><br>
068: * <map:parameter name="event-value" value="some value" /><br>
069: * </map:generate>
070: * </p>
071: *
072: * The two preconfigured event types take the following parameters:<br>
073: * - event-type 'named': parameter 'event-name'<br>
074: * - event-type 'name-value': parameter 'event-name' and parameter 'event-value'<br>
075: *
076: * <p>
077: * The src attribute and all parameters are passed as is to delegate generator.
078: * </p>
079: *
080: * TODO: share common code with EventCacheTransformer
081: * @author Unico Hommes
082: */
083: public class EventCacheGenerator extends ServiceableGenerator implements
084: Configurable, CacheableProcessingComponent {
085:
086: // ---------------------------------------------------- constants
087:
088: public static final String NAME_VALUE_EVENT_TYPE = "name-value";
089: public static final String EVENT_TYPE_DEFAULT = "named";
090: public static final String NAMED_EVENT_TYPE = EVENT_TYPE_DEFAULT;
091:
092: public static final String FACTORY_CONF = "factory";
093: public static final String FACTORY_NAME_CONF = "name";
094: public static final String FACTORY_NAME_TYPE = "src";
095:
096: public static final String DELEGATE_PARAM = "delegate";
097: public static final String EVENT_TYPE_PARAM = "event-type";
098:
099: // ---------------------------------------------------- member variables
100:
101: private ServiceSelector m_generatorSelector;
102: private Generator m_delegate;
103: private Serializable m_key;
104: private Event m_event;
105:
106: private Map m_types = new HashMap();
107:
108: /* (non-Javadoc)
109: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
110: */
111: public void service(ServiceManager manager) throws ServiceException {
112: super .service(manager);
113: m_generatorSelector = (ServiceSelector) manager
114: .lookup(Generator.ROLE + "Selector");
115: }
116:
117: /* (non-Javadoc)
118: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
119: */
120: public void configure(Configuration configuration)
121: throws ConfigurationException {
122: Configuration[] factories = configuration
123: .getChildren(FACTORY_CONF);
124: for (int i = 0; i < factories.length; i++) {
125: Configuration child = factories[i];
126: String name = child.getAttribute(FACTORY_NAME_CONF);
127: String src = child.getAttribute(FACTORY_NAME_TYPE);
128: try {
129: EventFactory factory = (EventFactory) Class
130: .forName(src).newInstance();
131: m_types.put(name, factory);
132: } catch (Exception e) {
133: final String message = "Unable to create EventFactory of type "
134: + src;
135: throw new ConfigurationException(message, e);
136: }
137: }
138: if (!m_types.containsKey(NAMED_EVENT_TYPE)) {
139: m_types.put(NAMED_EVENT_TYPE, new NamedEventFactory());
140: }
141: if (!m_types.containsKey(NAME_VALUE_EVENT_TYPE)) {
142: m_types.put(NAME_VALUE_EVENT_TYPE,
143: new NameValueEventFactory());
144: }
145: }
146:
147: /* (non-Javadoc)
148: * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
149: */
150: public void setup(SourceResolver resolver, Map objectModel,
151: String src, Parameters par) throws ProcessingException,
152: SAXException, IOException {
153:
154: // delegate
155: String delegate = par.getParameter(DELEGATE_PARAM, null);
156: if (delegate == null) {
157: String message = "Required parameter 'delegate' is missing";
158: throw new ProcessingException(message);
159: }
160: try {
161: m_delegate = (Generator) m_generatorSelector
162: .select(delegate);
163: } catch (ServiceException e) {
164: final String message = "Generator '" + delegate
165: + "' could not be found.";
166: throw new ProcessingException(message);
167: }
168: m_delegate.setup(resolver, objectModel, src, par);
169:
170: // event
171: String eventType = par.getParameter(EVENT_TYPE_PARAM,
172: EVENT_TYPE_DEFAULT);
173: EventFactory factory = (EventFactory) m_types.get(eventType);
174: if (factory == null) {
175: throw new ProcessingException("No such type of event: "
176: + eventType);
177: }
178: try {
179: m_event = factory.createEvent(par);
180: } catch (ParameterException e) {
181: final String message = "Failure creating Event";
182: throw new ProcessingException(message, e);
183: }
184:
185: // key - TODO: use delegates key?
186: m_key = SourceUtil.appendParameters(src, par);
187: }
188:
189: /* (non-Javadoc)
190: * @see org.apache.cocoon.xml.XMLProducer#setConsumer(org.apache.cocoon.xml.XMLConsumer)
191: */
192: public void setConsumer(XMLConsumer consumer) {
193: m_delegate.setConsumer(consumer);
194: }
195:
196: /* (non-Javadoc)
197: * @see org.apache.cocoon.generation.Generator#generate()
198: */
199: public void generate() throws IOException, SAXException,
200: ProcessingException {
201: m_delegate.generate();
202: }
203:
204: /* (non-Javadoc)
205: * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
206: */
207: public void recycle() {
208: if (m_delegate != null) {
209: m_generatorSelector.release(m_delegate);
210: }
211: m_delegate = null;
212: m_key = null;
213: m_event = null;
214: super .recycle();
215: }
216:
217: /* (non-Javadoc)
218: * @see org.apache.cocoon.caching.CacheableProcessingComponent#getKey()
219: */
220: public Serializable getKey() {
221: return m_key;
222: }
223:
224: /* (non-Javadoc)
225: * @see org.apache.cocoon.caching.CacheableProcessingComponent#getValidity()
226: */
227: public SourceValidity getValidity() {
228: return new EventValidity(m_event);
229: }
230:
231: /* (non-Javadoc)
232: * @see org.apache.avalon.framework.activity.Disposable#dispose()
233: */
234: public void dispose() {
235: if (this.manager != null) {
236: this.manager.release(m_generatorSelector);
237: m_generatorSelector = null;
238: }
239: super.dispose();
240: }
241: }
|