| /* |
| * Copyright 1999-2004 The Apache Software Foundation. |
| * |
| * Licensed 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 org.apache.avalon.framework.configuration.Configuration; |
| import org.apache.avalon.framework.configuration.ConfigurationException; |
| import org.apache.avalon.framework.component.ComponentSelector; |
| import org.apache.avalon.framework.thread.ThreadSafe; |
| |
| import java.util.Map; |
| import java.util.List; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Iterator; |
| |
| /** |
| * This modules allows to "chain" several other modules. If a module |
| * returns "null" as attribute value, the next module in the chain is |
| * queried until either a value can be obtained or the end of the |
| * chain is reached. |
| * |
| * <p>A typical example would be to "chain" request parameters, |
| * session attributes, and constants in this order. This way, an |
| * application could have a default skin that could be overridden by a |
| * user in her/his profile stored in the session. In addition, the |
| * user could request a different skin through passing a request |
| * parameter.</p> |
| * |
| * <p>Usage:</p> |
| * |
| * <p> Any number of <input-module/> blocks may appear in the |
| * component configuration. The @name attribute is used as the name of |
| * the requested input module. The complete <input-module/> |
| * block is passed at run-time to the module and thus can contain any |
| * configuration data for that particular module.</p> |
| * |
| * <p>Configuration:</p> |
| * |
| * <p>It can be controlled whether it returns a flat or a deep view, |
| * i.e. whether only values from the first module are returned if |
| * non-null or they are merged with values from other modules |
| * <code><all-values>true</all-values></code>. The same is |
| * possible for the attribute names |
| * (<code><all-names/></code>). In addition, empty strings could |
| * be treated the same as null values |
| * (<code><empty-as-null/></code>).</p> |
| * |
| * @author <a href="mailto:haul@apache.org">Christian Haul</a> |
| * @version CVS $Id: ChainMetaModule.java,v 1.4 2004/03/05 13:02:48 bdelacretaz Exp $ |
| */ |
| public class ChainMetaModule extends AbstractMetaModule implements ThreadSafe { |
| |
| private ModuleHolder[] inputs = null; |
| |
| private boolean emptyAsNull = false; |
| private boolean allNames = false; |
| private boolean allValues = false; |
| |
| public void configure(Configuration config) throws ConfigurationException { |
| |
| Configuration[] confs = config.getChildren("input-module"); |
| if (confs.length > 0) { |
| this.inputs = new ModuleHolder[confs.length]; |
| int j = 0; |
| for (int i=0; i<confs.length; i++) { |
| ModuleHolder module = new ModuleHolder(); |
| module.name = confs[i].getAttribute("name",null); |
| if (module.name == null) { |
| if (getLogger().isErrorEnabled()) |
| getLogger().error("No name attribute for module configuration. Skipping."); |
| continue; |
| } |
| module.config = confs[i]; |
| this.inputs[j]=module; |
| j++; |
| } |
| } |
| this.emptyAsNull = config.getChild("empty-as-null").getValueAsBoolean(this.emptyAsNull); |
| this.allNames = config.getChild("all-names").getValueAsBoolean(this.allNames); |
| this.allValues = config.getChild("all-values").getValueAsBoolean(this.allValues); |
| } |
| |
| |
| 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) { |
| |
| for (int i=0; i<this.inputs.length; i++) { |
| if (this.inputs[i].name != null) |
| this.inputs[i].input = obtainModule(this.inputs[i].name); |
| } |
| |
| } else if (!(this.inputSelector instanceof ThreadSafe) ) { |
| this.manager.release(this.inputSelector); |
| this.inputSelector = null; |
| } |
| |
| this.initialized = true; |
| } |
| } catch (Exception e) { |
| if (getLogger().isWarnEnabled()) |
| getLogger().warn("A problem occurred setting up input modules :'" + e.getMessage()); |
| } |
| } |
| |
| |
| public void dispose() { |
| |
| if (this.inputSelector != null) { |
| |
| for (int i=0; i<this.inputs.length; i++) { |
| if (this.inputs[i].input != null) |
| this.inputSelector.release(this.inputs[i].input); |
| } |
| |
| this.manager.release(this.inputSelector); |
| } |
| } |
| |
| |
| public Object[] getAttributeValues( String attr, Configuration modeConf, Map objectModel ) |
| throws ConfigurationException { |
| |
| if (!this.initialized) { |
| this.lazy_initialize(); |
| } |
| |
| // obtain correct configuration objects |
| // default vs dynamic |
| Configuration[] inputConfigs = null; |
| boolean allValues = this.allValues; |
| boolean emptyAsNull = this.emptyAsNull; |
| if (modeConf!=null && modeConf.getChildren().length > 0) { |
| inputConfigs = modeConf.getChildren("input-module"); |
| emptyAsNull = modeConf.getChild("empty-as-null").getValueAsBoolean(emptyAsNull); |
| allValues = modeConf.getChild("all-values").getValueAsBoolean(allValues); |
| if (inputConfigs.length == 0) inputConfigs = null; |
| } |
| |
| Object[] value = null; |
| boolean debug = getLogger().isDebugEnabled(); |
| List values = null; |
| if (allValues) values = new ArrayList(); |
| |
| if (inputConfigs == null) { |
| // static configuration branch |
| int i = 0; |
| while (i < this.inputs.length && (value == null || allValues)) { |
| if (this.inputs[i].name != null) { |
| value = getValues(attr, objectModel, this.inputs[i].input, this.inputs[i].name, this.inputs[i].config); |
| if (emptyAsNull && value != null && value.length == 0) value = null; |
| if (emptyAsNull && value != null && value.length == 1 && |
| value[0] instanceof String && value[0].equals("")) value = null; |
| if (debug) getLogger().debug("read from "+this.inputs[i].name+" attribute "+attr+" as "+value); |
| if (allValues && value != null) values.addAll(Arrays.asList(value)); |
| } |
| i++; |
| } |
| } else { |
| // run-time configuration branch |
| int i = 0; |
| while (i < inputConfigs.length && (value == null || allValues)) { |
| String name = inputConfigs[i].getAttribute("name",null); |
| if (name != null) { |
| value = getValues(attr, objectModel, null, name, inputConfigs[i]); |
| if (emptyAsNull && value != null && value.length == 0) value = null; |
| if (emptyAsNull && value != null && value.length == 1 && |
| value[0] instanceof String && value[0].equals("")) value = null; |
| if (debug) getLogger().debug("read from "+name+" attribute "+attr+" as "+value); |
| if (allValues && value != null) values.addAll(Arrays.asList(value)); |
| } |
| i++; |
| } |
| } |
| if (debug) getLogger().debug("result chaining for "+attr+" is "+(allValues? values.toArray() : value)); |
| return (allValues? values.toArray() : value); |
| } |
| |
| private void addIterator(Collection col, Iterator iter) { |
| while (iter != null && iter.hasNext()) |
| col.add(iter.next()); |
| } |
| |
| |
| public Iterator getAttributeNames( Configuration modeConf, Map objectModel ) |
| throws ConfigurationException { |
| |
| if (!this.initialized) { |
| this.lazy_initialize(); |
| } |
| |
| // obtain correct configuration objects |
| // default vs dynamic |
| Configuration[] inputConfigs = null; |
| boolean emptyAsNull = this.emptyAsNull; |
| boolean allNames = this.allNames; |
| if (modeConf!=null && modeConf.getChildren().length > 0) { |
| inputConfigs = modeConf.getChildren("input-module"); |
| emptyAsNull = modeConf.getChild("empty-as-null").getValueAsBoolean(emptyAsNull); |
| allNames = modeConf.getChild("all-names").getValueAsBoolean(allNames); |
| if (inputConfigs.length == 0) inputConfigs = null; |
| } |
| |
| Iterator value = null; |
| Collection values = null; |
| if (allNames) values = new ArrayList(); |
| boolean debug = getLogger().isDebugEnabled(); |
| |
| if (inputConfigs == null) { |
| // static configuration branch |
| int i = 0; |
| while (i < this.inputs.length && (value == null || allNames)) { |
| if (this.inputs[i].name != null) { |
| value = getNames(objectModel, this.inputs[i].input, this.inputs[i].name, this.inputs[i].config); |
| if (debug) getLogger().debug("read from "+this.inputs[i].name+" AttributeNames as "+value); |
| if (allNames && value != null) addIterator(values, value); |
| } |
| i++; |
| } |
| } else { |
| // run-time configuration branch |
| int i = 0; |
| while (i < inputConfigs.length && value == null) { |
| String name = inputConfigs[i].getAttribute("name",null); |
| if (name != null) { |
| value = getNames(objectModel, null, name, inputConfigs[i]); |
| if (debug) getLogger().debug("read from "+name+" AttributeNames as "+value); |
| if (allNames && value != null) addIterator(values, value); |
| } |
| i++; |
| } |
| } |
| if (debug) getLogger().debug("result chaining names is "+(allNames? values.iterator() : value)); |
| return (allNames? values.iterator() : value); |
| } |
| |
| |
| public Object getAttribute( String attr, Configuration modeConf, Map objectModel ) |
| throws ConfigurationException { |
| |
| Object[] values = this.getAttributeValues(attr,modeConf,objectModel); |
| if (getLogger().isDebugEnabled()) getLogger().debug("result chaining single for "+attr+" is "+(values != null? values[0] : "null")); |
| return (values != null? values[0] : null); |
| } |
| |
| |
| } |