| /* |
| * 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.modules.input; |
| |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.apache.avalon.framework.component.ComponentException; |
| import org.apache.avalon.framework.component.ComponentManager; |
| import org.apache.avalon.framework.component.ComponentSelector; |
| import org.apache.avalon.framework.component.Composable; |
| import org.apache.avalon.framework.configuration.Configuration; |
| import org.apache.avalon.framework.configuration.ConfigurationException; |
| import org.apache.avalon.framework.thread.ThreadSafe; |
| |
| /** |
| * AbstractMetaModule gives you the infrastructure for easily |
| * deploying more "meta" InputModules i.e. InputModules that are |
| * composed of other InputModules. In order to get at the Logger, use |
| * getLogger(). |
| * |
| * @author <a href="mailto:haul@apache.org">Christian Haul</a> |
| * @author <a href="mailto:jefft@apache.org">Jeff Turner</a> |
| * @version CVS $Id$ |
| */ |
| public abstract class AbstractMetaModule extends AbstractInputModule |
| implements Composable { |
| |
| /** The component manager instance */ |
| protected ComponentManager manager; |
| |
| /** The cached InputModule-Selector */ |
| protected ComponentSelector inputSelector = null; |
| |
| /** The cached default InputModule */ |
| protected InputModule input = null; |
| |
| /** The default InputModule name / shorthand. Defaults to 'request-param' */ |
| protected String defaultInput = "request-param"; // default to request parameters |
| |
| /** The default InputModule configuration */ |
| protected Configuration inputConf = null; // will become an empty configuration object |
| // during configure() so why bother here... |
| |
| /** Is this instance initialized? */ |
| protected boolean initialized = false; |
| |
| /* Constants */ |
| |
| protected final static String INPUT_MODULE_SELECTOR = InputModule.ROLE+"Selector"; |
| |
| /* Operation codes */ |
| private final static int OP_GET = 0; |
| private final static int OP_VALUES = 1; |
| private final static int OP_NAMES = 2; |
| private final static String[] OPNAME = new String[] {"GET_VALUE", "GET_VALUES", "GET_NAMES"}; |
| |
| |
| /** |
| * Set the current <code>ComponentManager</code> instance used by this |
| * <code>Composable</code>. |
| */ |
| public void compose(ComponentManager manager) throws ComponentException { |
| |
| this.manager=manager; |
| } |
| |
| |
| /** |
| * Initialize the meta module with exactly one other input |
| * module. Since "meta" modules require references to components |
| * of the same role, initialization cannot be done in initialize() |
| * when also implementing ThreadSafe since at that point the |
| * component selector is not yet initialized it would trigger the |
| * creation of a new one resulting in an endless loop of |
| * initializations. Therefore, every module needs to call this |
| * method when it first requires access to another module if the |
| * module itself has not been initialized. Override this method |
| * and dispose() to keep references to more than one module. |
| */ |
| public synchronized void lazy_initialize() { |
| |
| try { |
| // obtain input modules |
| if (!this.initialized) { |
| this.inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); |
| if (this.inputSelector != null && this.inputSelector instanceof ThreadSafe) { |
| |
| if (this.defaultInput != null) { |
| this.input = obtainModule(this.defaultInput); |
| } |
| |
| } else if (!(this.inputSelector instanceof ThreadSafe) ) { |
| this.manager.release(this.inputSelector); |
| this.inputSelector = null; |
| } |
| |
| this.initialized = true; |
| } |
| } catch (Exception e) { |
| if (getLogger().isWarnEnabled()) |
| getLogger().error("A problem occurred setting up input modules :'" + e.getMessage(), e); |
| } |
| } |
| |
| |
| /** |
| * Dispose exactly one cached InputModule. To work on more than |
| * one, override this method and initialize(). |
| */ |
| public void dispose() { |
| |
| if (this.inputSelector != null) { |
| if (this.input != null) |
| this.inputSelector.release(this.input); |
| this.manager.release(this.inputSelector); |
| } |
| } |
| |
| |
| /** |
| * Obtain a permanent reference to an InputModule. |
| */ |
| protected InputModule obtainModule(String type) { |
| ComponentSelector inputSelector = this.inputSelector; |
| InputModule module = null; |
| try { |
| if (inputSelector == null) { |
| inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); |
| } |
| if (inputSelector.hasComponent(type)) { |
| if (type != null && inputSelector.hasComponent(type)) { |
| module = (InputModule) inputSelector.select(type); |
| } |
| if (!(module instanceof ThreadSafe) ) { |
| inputSelector.release(module); |
| module = null; |
| } |
| } |
| if (type != null && module == null) |
| if (getLogger().isWarnEnabled()) |
| getLogger().warn("A problem occurred setting up '" + type |
| + "': Selector is not null, Component is " |
| + (inputSelector.hasComponent(type)? "known" : "unknown")); |
| |
| } catch (ComponentException ce) { |
| if (getLogger().isWarnEnabled()) |
| getLogger().warn("Could not obtain selector for InputModules: "+ce.getMessage()); |
| } finally { |
| if (this.inputSelector == null) |
| this.manager.release(inputSelector); |
| // FIXME: Is it OK to keep a reference to the module when we release the selector? |
| } |
| |
| return module; |
| } |
| |
| |
| /** |
| * release a permanent reference to an InputModule. |
| */ |
| protected void releaseModule(InputModule module) { |
| ComponentSelector inputSelector = this.inputSelector; |
| if (module != null) { |
| try { |
| // FIXME: Is it OK to release a module when we have released the selector before? |
| if (inputSelector == null) |
| inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); |
| |
| inputSelector.release(module); |
| module = null; |
| |
| } catch (ComponentException ce) { |
| if (getLogger().isWarnEnabled()) |
| getLogger().warn("Could not obtain selector for InputModules: "+ce.getMessage()); |
| } finally { |
| if (this.inputSelector == null) |
| this.manager.release(inputSelector); |
| } |
| } |
| } |
| |
| /** |
| * Get names of available attributes in the specified (usually statically |
| * assigned) Input Module. |
| * @see InputModule#getAttributeNames(Configuration, Map) |
| */ |
| protected Iterator getNames(Map objectModel, |
| InputModule staticMod, String staticModName, Configuration staticModConf) |
| throws ConfigurationException { |
| |
| return (Iterator) this.get(OP_NAMES, null, objectModel, staticMod, staticModName, staticModConf, null, null, null); |
| } |
| |
| /** |
| * Get names of available attributes in one of the specified Input Modules |
| * (static or dynamic, dynamic preferred). Dynamic IM may be |
| * <code>null</code>. |
| * @see InputModule#getAttributeNames(Configuration, Map) |
| */ |
| protected Iterator getNames(Map objectModel, |
| InputModule staticMod, String staticModName, Configuration staticModConf, |
| InputModule dynamicMod, String dynamicModName, Configuration dynamicModConf) |
| throws ConfigurationException { |
| |
| return (Iterator) this.get(OP_NAMES, null, objectModel, staticMod, staticModName, staticModConf, dynamicMod, dynamicModName, dynamicModConf); |
| } |
| |
| protected Object getValue(String attr, Map objectModel, ModuleHolder holder) throws ConfigurationException{ |
| return this.getValue(attr, objectModel, holder.input, holder.name, holder.config); |
| } |
| |
| protected Object getValue(String attr, Map objectModel, ModuleHolder staticHolder, ModuleHolder dynamicHolder) throws ConfigurationException{ |
| return this.getValue(attr, objectModel, staticHolder.input, staticHolder.name, dynamicHolder.config); |
| } |
| |
| protected Object[] getValues(String attr, Map objectModel, ModuleHolder holder) throws ConfigurationException{ |
| return this.getValues(attr, objectModel, holder.input, holder.name, holder.config); |
| } |
| |
| protected Object[] getValues(String attr, Map objectModel, ModuleHolder staticHolder, ModuleHolder dynamicHolder) throws ConfigurationException{ |
| return this.getValues(attr, objectModel, staticHolder.input, staticHolder.name, dynamicHolder.config); |
| } |
| |
| /** |
| * Get an attribute's value from a (usually statically assigned) Input |
| * Module. |
| * @see InputModule#getAttribute(String, Configuration, Map) |
| */ |
| protected Object getValue(String attr, Map objectModel, |
| InputModule staticMod, String staticModName, Configuration staticModConf) |
| throws ConfigurationException { |
| |
| return this.get(OP_GET, attr, objectModel, staticMod, staticModName, staticModConf, null, null, null); |
| } |
| |
| |
| /** |
| * Get attribute's value in one of the specified Input Modules |
| * (static or dynamic, dynamic preferred). Dynamic IM may be |
| * <code>null</code>. |
| * @see InputModule#getAttribute(String, Configuration, Map) |
| */ |
| protected Object getValue(String attr, Map objectModel, |
| InputModule staticMod, String staticModName, Configuration staticModConf, |
| InputModule dynamicMod, String dynamicModName, Configuration dynamicModConf) |
| throws ConfigurationException { |
| |
| return this.get(OP_GET, attr, objectModel, staticMod, staticModName, staticModConf, dynamicMod, dynamicModName, dynamicModConf); |
| } |
| |
| /** |
| * Get an attribute's values from a (usually statically assigned) Input |
| * Module. |
| * @see InputModule#getAttributeValues(String, Configuration, Map) |
| */ |
| protected Object[] getValues(String attr, Map objectModel, |
| InputModule staticMod, String staticModName, Configuration staticModConf) |
| throws ConfigurationException { |
| |
| return (Object[]) this.get(OP_VALUES, attr, objectModel, staticMod, staticModName, staticModConf, null, null, null); |
| } |
| |
| /** |
| * Get attribute's values in one of the specified Input Modules |
| * (static or dynamic, dynamic preferred). Dynamic IM may be |
| * <code>null</code>. |
| * @see InputModule#getAttributeValues(String, Configuration, Map) |
| */ |
| protected Object[] getValues(String attr, Map objectModel, |
| InputModule staticMod, String staticModName, Configuration staticModConf, |
| InputModule dynamicMod, String dynamicModName, Configuration dynamicModConf) |
| throws ConfigurationException { |
| |
| return (Object[]) this.get(OP_VALUES, attr, objectModel, staticMod, staticModName, staticModConf, dynamicMod, dynamicModName, dynamicModConf); |
| } |
| |
| |
| /** |
| * Encapsulates use of an InputModule. Does all the lookups and so on. |
| * The second module (dynamic) is preferred if it has an non null name. If |
| * an exception is encountered, a warn message is printed and null is |
| * returned. |
| * @param op Operation to perform ({@link #OP_GET}, {@link #OP_NAMES}, {@link #OP_VALUES}). |
| * |
| * @return Either an Object, an Object[], or an Iterator, depending on <code>op</code> param. |
| */ |
| private Object get(int op, String attr, Map objectModel, |
| InputModule staticMod, String staticModName, Configuration staticModConf, |
| InputModule dynamicMod, String dynamicModName, Configuration dynamicModConf) |
| throws ConfigurationException { |
| |
| ComponentSelector cs = this.inputSelector; |
| Object value = null; |
| String name = null; |
| InputModule input = null; |
| Configuration conf = null; |
| boolean release = false; |
| |
| try { |
| if (cs == null) { |
| try { |
| cs = (ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); |
| } catch (ComponentException e) { |
| throw new ConfigurationException("Could not find MetaModule's module selector", e); |
| } |
| } |
| |
| boolean useDynamic; |
| if (dynamicMod == null && dynamicModName == null) { |
| useDynamic = false; |
| input = staticMod; |
| name = staticModName; |
| conf = staticModConf; |
| } else { |
| useDynamic = true; |
| input = dynamicMod; |
| name = dynamicModName; |
| conf = dynamicModConf; |
| } |
| |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("MetaModule performing op "+OPNAME[op]+" on " + |
| (useDynamic?"dynamically":"statically") + " " + |
| (input==null?"created":"assigned") + |
| " module '"+name+"', using config "+dynamicModConf); |
| } |
| |
| if (input == null) { |
| if (cs.hasComponent(name)) { |
| release = true; |
| try { |
| input = (InputModule) cs.select(name); |
| } catch (ComponentException e) { |
| throw new ConfigurationException( |
| "MetaModule unable to create "+ |
| (useDynamic ? "dynamically" : "statically")+ |
| " specified internal module '"+name+"'", e); |
| } |
| } else { |
| throw new ConfigurationException("MetaModule: No such InputModule: "+name); |
| } |
| } |
| |
| switch (op) { |
| case OP_GET: |
| value = input.getAttribute(attr, conf, objectModel); |
| break; |
| case OP_VALUES: |
| value = input.getAttributeValues(attr, conf, objectModel); |
| break; |
| case OP_NAMES: |
| value = input.getAttributeNames(conf, objectModel); |
| break; |
| } |
| |
| if (getLogger().isDebugEnabled()) |
| getLogger().debug("using "+name+" as "+input+" for "+op+" ("+attr+") and "+conf+" gives "+value); |
| |
| } finally { |
| if (release) |
| cs.release(input); |
| |
| if (this.inputSelector == null) |
| this.manager.release(cs); |
| } |
| |
| return value; |
| } |
| |
| } |