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.components.treeprocessor.sitemap;
018:
019: import java.util.HashMap;
020: import java.util.HashSet;
021: import java.util.Map;
022: import java.util.Set;
023: import java.util.StringTokenizer;
024:
025: import org.apache.avalon.framework.CascadingRuntimeException;
026: import org.apache.avalon.framework.component.ComponentException;
027: import org.apache.avalon.framework.configuration.Configuration;
028: import org.apache.avalon.framework.configuration.ConfigurationException;
029: import org.apache.avalon.framework.configuration.DefaultConfiguration;
030: import org.apache.cocoon.acting.Action;
031: import org.apache.cocoon.components.ExtendedComponentSelector;
032: import org.apache.cocoon.components.ComponentLocator;
033: import org.apache.cocoon.components.pipeline.OutputComponentSelector;
034: import org.apache.cocoon.components.pipeline.ProcessingPipeline;
035: import org.apache.cocoon.generation.Generator;
036: import org.apache.cocoon.matching.Matcher;
037: import org.apache.cocoon.reading.Reader;
038: import org.apache.cocoon.selection.Selector;
039: import org.apache.cocoon.serialization.Serializer;
040: import org.apache.cocoon.sitemap.SitemapComponentSelector;
041: import org.apache.cocoon.transformation.Transformer;
042:
043: /**
044: * Component selector for sitemap components.
045: *
046: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
047: * @author <a href="mailto:uv@upaya.co.uk">Upayavira</a>
048: * @version CVS $Id: ComponentsSelector.java 433543 2006-08-22 06:22:54Z crossley $
049: */
050:
051: public class ComponentsSelector extends ExtendedComponentSelector
052: implements OutputComponentSelector, SitemapComponentSelector {
053:
054: public static final int UNKNOWN = -1;
055: public static final int GENERATOR = 0;
056: public static final int TRANSFORMER = 1;
057: public static final int SERIALIZER = 2;
058: public static final int READER = 3;
059: public static final int MATCHER = 4;
060: public static final int SELECTOR = 5;
061: public static final int ACTION = 6;
062: public static final int PIPELINE = 7;
063:
064: public static final String[] SELECTOR_ROLES = {
065: Generator.ROLE + "Selector", Transformer.ROLE + "Selector",
066: Serializer.ROLE + "Selector", Reader.ROLE + "Selector",
067: Matcher.ROLE + "Selector", Selector.ROLE + "Selector",
068: Action.ROLE + "Selector",
069: ProcessingPipeline.ROLE + "Selector" };
070:
071: public static final String[] COMPONENT_NAMES = { "generator",
072: "transformer", "serializer", "reader", "matcher",
073: "selector", "action", "pipe" };
074:
075: /** The role as an integer */
076: private int roleId;
077:
078: /** The mime-type for hints */
079: private Map hintMimeTypes;
080:
081: /** The labels for hints */
082: private Map hintLabels;
083:
084: /** The pipeline-hint Map */
085: private Map pipelineHints;
086:
087: /** The set of known hints, used to add standard components (see ensureExists) */
088: private Set knownHints = new HashSet();
089:
090: /** The parent selector, if it's of the current class */
091: private SitemapComponentSelector parentSitemapSelector;
092:
093: /* (non-Javadoc)
094: * @see org.apache.cocoon.components.ParentAware#setParentInformation(org.apache.avalon.framework.component.ComponentManager, java.lang.String)
095: */
096: public void setParentLocator(ComponentLocator locator)
097: throws ComponentException {
098: super .setParentLocator(locator);
099:
100: if (super .parentSelector instanceof SitemapComponentSelector) {
101: this .parentSitemapSelector = (SitemapComponentSelector) super .parentSelector;
102: }
103: }
104:
105: /**
106: * Return the component instance name according to the selector role
107: * (e.g. "action" for "org.apache.cocoon.acting.Action").
108: */
109: protected String getComponentInstanceName() {
110: return (this .roleId == UNKNOWN) ? null
111: : COMPONENT_NAMES[this .roleId];
112: }
113:
114: /**
115: * Get the attribute for class names. This is "src" for known roles, and
116: * "class" (the default) for other roles.
117: */
118: protected String getClassAttributeName() {
119: return (this .roleId == UNKNOWN) ? "class" : "src";
120: }
121:
122: public void configure(Configuration config)
123: throws ConfigurationException {
124:
125: // Who are we ?
126: String role = getRoleName(config);
127: this .roleId = UNKNOWN; // unknown
128: for (int i = 0; i < SELECTOR_ROLES.length; i++) {
129: if (SELECTOR_ROLES[i].equals(role)) {
130: this .roleId = i;
131: break;
132: }
133: }
134:
135: if (getLogger().isDebugEnabled()) {
136: getLogger().debug(
137: "Setting up sitemap component selector for " + role
138: + " (role id = " + this .roleId + ")");
139: }
140:
141: // Only matchers and serializers can have a MIME type
142: if (this .roleId == SERIALIZER || this .roleId == READER) {
143: this .hintMimeTypes = new HashMap();
144: }
145:
146: this .hintLabels = new HashMap();
147: this .pipelineHints = new HashMap();
148:
149: super .configure(config);
150: }
151:
152: /**
153: * Add a component in this selector. If needed, also register it's MIME type.
154: */
155: public void addComponent(Object hint, Class clazz,
156: Configuration config) throws ComponentException {
157:
158: super .addComponent(hint, clazz, config);
159:
160: // Add to known hints
161: this .knownHints.add(hint);
162:
163: if (this .roleId == SERIALIZER || this .roleId == READER) {
164: // Get mime-type
165: String mimeType = config.getAttribute("mime-type", null);
166: if (mimeType != null) {
167: this .hintMimeTypes.put(hint, mimeType);
168: }
169: }
170:
171: String label = config.getAttribute("label", null);
172: if (label != null) {
173: // Empty '' attribute will result in empty array,
174: // overriding all labels on the component declared in the parent.
175: StringTokenizer st = new StringTokenizer(label, " ,", false);
176: String[] labels = new String[st.countTokens()];
177: for (int i = 0; i < labels.length; i++) {
178: labels[i] = st.nextToken();
179: }
180: this .hintLabels.put(hint, labels);
181: }
182:
183: String pipelineHint = config.getAttribute("hint", null);
184: this .pipelineHints.put(hint, pipelineHint);
185: }
186:
187: /**
188: * Ensure system-defined components exist (e.g. <aggregator>) and initialize
189: * the selector.
190: */
191: public void initialize() /*throws Exception*/{
192:
193: // FIXME : need to catch exceptions since ECS doesn't propagate the throws clause of Initializable
194: try {
195:
196: DefaultConfiguration config = null;
197:
198: // Ensure all system-defined hints exist.
199: // NOTE : checking this here means they can be user-defined in the sitemap
200: switch (this .roleId) {
201: case GENERATOR:
202:
203: config = new DefaultConfiguration(
204: COMPONENT_NAMES[GENERATOR], "autogenerated");
205: config.setAttribute("name", "<notifier>");
206: ensureExists(
207: "<notifier>",
208: org.apache.cocoon.sitemap.NotifyingGenerator.class,
209: config);
210:
211: config = new DefaultConfiguration(
212: COMPONENT_NAMES[GENERATOR], "autogenerated");
213: config.setAttribute("name", "<aggregator>");
214: ensureExists(
215: "<aggregator>",
216: org.apache.cocoon.sitemap.ContentAggregator.class,
217: config);
218: break;
219:
220: case TRANSFORMER:
221: config = new DefaultConfiguration(
222: COMPONENT_NAMES[TRANSFORMER], "autogenerated");
223: config.setAttribute("name", "<translator>");
224: ensureExists("<translator>",
225: org.apache.cocoon.sitemap.LinkTranslator.class,
226: config);
227:
228: config = new DefaultConfiguration(
229: COMPONENT_NAMES[TRANSFORMER], "autogenerated");
230: config.setAttribute("name", "<gatherer>");
231: ensureExists("<gatherer>",
232: org.apache.cocoon.sitemap.LinkGatherer.class,
233: config);
234: break;
235: }
236:
237: super .initialize();
238:
239: // Don't keep known hints (they're no more needed)
240: this .knownHints = null;
241:
242: } catch (Exception e) {
243: throw new CascadingRuntimeException(
244: "Cannot setup default components", e);
245: }
246:
247: }
248:
249: /**
250: * Ensure a component exists or add it otherwhise. We cannot simply call hasComponent()
251: * since it requires to be initialized, and we want to add components, and this must
252: * be done before initialization.
253: */
254: private void ensureExists(Object hint, Class clazz,
255: Configuration config) throws ComponentException {
256:
257: if (!this .knownHints.contains(hint)) {
258: this .addComponent(hint, clazz, config);
259: }
260: }
261:
262: /**
263: * Get the MIME type for a given hint.
264: */
265: public String getMimeTypeForHint(Object hint) {
266:
267: if (this .hintMimeTypes == null) {
268: // Not a component that has mime types
269: return null;
270:
271: } else {
272: if (this .hasDeclaredComponent(hint)) {
273: return (String) this .hintMimeTypes.get(hint);
274:
275: } else if (this .parentSitemapSelector != null) {
276: return this .parentSitemapSelector
277: .getMimeTypeForHint(hint);
278:
279: } else {
280: return null;
281: }
282: }
283: }
284:
285: public boolean hasLabel(Object hint, String label) {
286: String[] labels = this .getLabels(hint);
287: if (labels != null) {
288: for (int i = 0; i < labels.length; i++) {
289: if (labels[i].equals(label))
290: return true;
291: }
292: }
293: return false;
294: }
295:
296: public String[] getLabels(Object hint) {
297: // If this hint is declared locally, use its labels (if any), otherwise inherit
298: // those of the parent.
299: if (this .hasDeclaredComponent(hint)) {
300: return (String[]) this .hintLabels.get(hint);
301:
302: } else if (this .parentSitemapSelector != null) {
303: return parentSitemapSelector.getLabels(hint);
304:
305: } else {
306: return null;
307: }
308: }
309:
310: public String getPipelineHint(Object hint) {
311: // If this hint is declared locally, use its hints (if any), otherwise inherit
312: // those of the parent.
313: if (this .hasDeclaredComponent(hint)) {
314: return (String) this .pipelineHints.get(hint);
315: } else if (this .parentSitemapSelector != null) {
316: return this .parentSitemapSelector.getPipelineHint(hint);
317: } else {
318: return null;
319: }
320: }
321:
322: public void dispose() {
323: super.dispose();
324: this.parentSitemapSelector = null;
325: }
326: }
|