/* * 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.components.treeprocessor.sitemap; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.apache.avalon.framework.CascadingRuntimeException; import org.apache.avalon.framework.component.ComponentException; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.configuration.DefaultConfiguration; import org.apache.cocoon.acting.Action; import org.apache.cocoon.components.ExtendedComponentSelector; import org.apache.cocoon.components.ComponentLocator; import org.apache.cocoon.components.pipeline.OutputComponentSelector; import org.apache.cocoon.components.pipeline.ProcessingPipeline; import org.apache.cocoon.generation.Generator; import org.apache.cocoon.matching.Matcher; import org.apache.cocoon.reading.Reader; import org.apache.cocoon.selection.Selector; import org.apache.cocoon.serialization.Serializer; import org.apache.cocoon.sitemap.SitemapComponentSelector; import org.apache.cocoon.transformation.Transformer; /** * Component selector for sitemap components. * * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a> * @author <a href="mailto:uv@upaya.co.uk">Upayavira</a> * @version CVS $Id$ */ public class ComponentsSelector extends ExtendedComponentSelector implements OutputComponentSelector, SitemapComponentSelector { public static final int UNKNOWN = -1; public static final int GENERATOR = 0; public static final int TRANSFORMER = 1; public static final int SERIALIZER = 2; public static final int READER = 3; public static final int MATCHER = 4; public static final int SELECTOR = 5; public static final int ACTION = 6; public static final int PIPELINE = 7; public static final String[] SELECTOR_ROLES = { Generator.ROLE + "Selector", Transformer.ROLE + "Selector", Serializer.ROLE + "Selector", Reader.ROLE + "Selector", Matcher.ROLE + "Selector", Selector.ROLE + "Selector", Action.ROLE + "Selector", ProcessingPipeline.ROLE + "Selector" }; public static final String[] COMPONENT_NAMES = { "generator", "transformer", "serializer", "reader", "matcher", "selector", "action", "pipe" }; /** The role as an integer */ private int roleId; /** The mime-type for hints */ private Map hintMimeTypes; /** The labels for hints */ private Map hintLabels; /** The pipeline-hint Map */ private Map pipelineHints; /** The set of known hints, used to add standard components (see ensureExists) */ private Set knownHints = new HashSet(); /** The parent selector, if it's of the current class */ private SitemapComponentSelector parentSitemapSelector; /* (non-Javadoc) * @see org.apache.cocoon.components.ParentAware#setParentInformation(org.apache.avalon.framework.component.ComponentManager, java.lang.String) */ public void setParentLocator(ComponentLocator locator) throws ComponentException { super.setParentLocator(locator); if (super.parentSelector instanceof SitemapComponentSelector) { this.parentSitemapSelector = (SitemapComponentSelector)super.parentSelector; } } /** * Return the component instance name according to the selector role * (e.g. "action" for "org.apache.cocoon.acting.Action"). */ protected String getComponentInstanceName() { return (this.roleId == UNKNOWN) ? null : COMPONENT_NAMES[this.roleId]; } /** * Get the attribute for class names. This is "src" for known roles, and * "class" (the default) for other roles. */ protected String getClassAttributeName() { return (this.roleId == UNKNOWN) ? "class" : "src"; } public void configure(Configuration config) throws ConfigurationException { // Who are we ? String role = getRoleName(config); this.roleId = UNKNOWN; // unknown for (int i = 0; i < SELECTOR_ROLES.length; i++) { if (SELECTOR_ROLES[i].equals(role)) { this.roleId = i; break; } } if (getLogger().isDebugEnabled()) { getLogger().debug("Setting up sitemap component selector for " + role + " (role id = " + this.roleId + ")"); } // Only matchers and serializers can have a MIME type if (this.roleId == SERIALIZER || this.roleId == READER) { this.hintMimeTypes = new HashMap(); } this.hintLabels = new HashMap(); this.pipelineHints = new HashMap(); super.configure(config); } /** * Add a component in this selector. If needed, also register it's MIME type. */ public void addComponent(Object hint, Class clazz, Configuration config) throws ComponentException { super.addComponent(hint, clazz, config); // Add to known hints this.knownHints.add(hint); if (this.roleId == SERIALIZER || this.roleId == READER) { // Get mime-type String mimeType = config.getAttribute("mime-type", null); if (mimeType != null) { this.hintMimeTypes.put(hint, mimeType); } } String label = config.getAttribute("label", null); if (label != null) { // Empty '' attribute will result in empty array, // overriding all labels on the component declared in the parent. StringTokenizer st = new StringTokenizer(label, " ,", false); String[] labels = new String[st.countTokens()]; for (int i = 0; i < labels.length; i++) { labels[i] = st.nextToken(); } this.hintLabels.put(hint, labels); } String pipelineHint = config.getAttribute("hint", null); this.pipelineHints.put(hint, pipelineHint); } /** * Ensure system-defined components exist (e.g. <aggregator>) and initialize * the selector. */ public void initialize() /*throws Exception*/ { // FIXME : need to catch exceptions since ECS doesn't propagate the throws clause of Initializable try { DefaultConfiguration config = null; // Ensure all system-defined hints exist. // NOTE : checking this here means they can be user-defined in the sitemap switch(this.roleId) { case GENERATOR : config = new DefaultConfiguration(COMPONENT_NAMES[GENERATOR], "autogenerated"); config.setAttribute("name", "<notifier>"); ensureExists("<notifier>", org.apache.cocoon.sitemap.NotifyingGenerator.class, config); config = new DefaultConfiguration(COMPONENT_NAMES[GENERATOR], "autogenerated"); config.setAttribute("name", "<aggregator>"); ensureExists("<aggregator>", org.apache.cocoon.sitemap.ContentAggregator.class, config); break; case TRANSFORMER : config = new DefaultConfiguration(COMPONENT_NAMES[TRANSFORMER], "autogenerated"); config.setAttribute("name", "<translator>"); ensureExists("<translator>", org.apache.cocoon.sitemap.LinkTranslator.class, config); config = new DefaultConfiguration(COMPONENT_NAMES[TRANSFORMER], "autogenerated"); config.setAttribute("name", "<gatherer>"); ensureExists("<gatherer>", org.apache.cocoon.sitemap.LinkGatherer.class, config); break; } super.initialize(); // Don't keep known hints (they're no more needed) this.knownHints = null; } catch(Exception e) { throw new CascadingRuntimeException("Cannot setup default components", e); } } /** * Ensure a component exists or add it otherwhise. We cannot simply call hasComponent() * since it requires to be initialized, and we want to add components, and this must * be done before initialization. */ private void ensureExists(Object hint, Class clazz, Configuration config) throws ComponentException { if (! this.knownHints.contains(hint)) { this.addComponent(hint, clazz, config); } } /** * Get the MIME type for a given hint. */ public String getMimeTypeForHint(Object hint) { if (this.hintMimeTypes == null) { // Not a component that has mime types return null; } else { if (this.hasDeclaredComponent(hint)) { return (String)this.hintMimeTypes.get(hint); } else if (this.parentSitemapSelector != null) { return this.parentSitemapSelector.getMimeTypeForHint(hint); } else { return null; } } } public boolean hasLabel(Object hint, String label) { String[] labels = this.getLabels(hint); if (labels != null) { for (int i = 0; i < labels.length; i++) { if (labels[i].equals(label)) return true; } } return false; } public String[] getLabels(Object hint) { // If this hint is declared locally, use its labels (if any), otherwise inherit // those of the parent. if (this.hasDeclaredComponent(hint)) { return (String[])this.hintLabels.get(hint); } else if (this.parentSitemapSelector != null) { return parentSitemapSelector.getLabels(hint); } else { return null; } } public String getPipelineHint(Object hint) { // If this hint is declared locally, use its hints (if any), otherwise inherit // those of the parent. if (this.hasDeclaredComponent(hint)) { return (String)this.pipelineHints.get(hint); } else if (this.parentSitemapSelector != null) { return this.parentSitemapSelector.getPipelineHint(hint); } else { return null; } } public void dispose() { super.dispose(); this.parentSitemapSelector = null; } }