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.modules.input;
018:
019: import org.apache.avalon.framework.configuration.Configuration;
020: import org.apache.avalon.framework.configuration.ConfigurationException;
021: import org.apache.avalon.framework.component.ComponentSelector;
022: import org.apache.avalon.framework.thread.ThreadSafe;
023:
024: import java.util.Map;
025: import java.util.List;
026: import java.util.ArrayList;
027: import java.util.Arrays;
028: import java.util.Collection;
029: import java.util.Iterator;
030:
031: /**
032: * This modules allows to "chain" several other modules. If a module
033: * returns "null" as attribute value, the next module in the chain is
034: * queried until either a value can be obtained or the end of the
035: * chain is reached.
036: *
037: * <p>A typical example would be to "chain" request parameters,
038: * session attributes, and constants in this order. This way, an
039: * application could have a default skin that could be overridden by a
040: * user in her/his profile stored in the session. In addition, the
041: * user could request a different skin through passing a request
042: * parameter.</p>
043: *
044: * <p>Usage:</p>
045: *
046: * <p> Any number of <input-module/> blocks may appear in the
047: * component configuration. The @name attribute is used as the name of
048: * the requested input module. The complete <input-module/>
049: * block is passed at run-time to the module and thus can contain any
050: * configuration data for that particular module.</p>
051: *
052: * <p>Configuration:</p>
053: *
054: * <p>It can be controlled whether it returns a flat or a deep view,
055: * i.e. whether only values from the first module are returned if
056: * non-null or they are merged with values from other modules
057: * <code><all-values>true</all-values></code>. The same is
058: * possible for the attribute names
059: * (<code><all-names/></code>). In addition, empty strings could
060: * be treated the same as null values
061: * (<code><empty-as-null/></code>).</p>
062: *
063: * @author <a href="mailto:haul@apache.org">Christian Haul</a>
064: * @version CVS $Id: ChainMetaModule.java 433543 2006-08-22 06:22:54Z crossley $
065: */
066: public class ChainMetaModule extends AbstractMetaModule implements
067: ThreadSafe {
068:
069: private ModuleHolder[] inputs = null;
070:
071: private boolean emptyAsNull = false;
072: private boolean allNames = false;
073: private boolean allValues = false;
074:
075: public void configure(Configuration config)
076: throws ConfigurationException {
077:
078: Configuration[] confs = config.getChildren("input-module");
079: if (confs.length > 0) {
080: this .inputs = new ModuleHolder[confs.length];
081: int j = 0;
082: for (int i = 0; i < confs.length; i++) {
083: ModuleHolder module = new ModuleHolder();
084: module.name = confs[i].getAttribute("name", null);
085: if (module.name == null) {
086: if (getLogger().isErrorEnabled())
087: getLogger()
088: .error(
089: "No name attribute for module configuration. Skipping.");
090: continue;
091: }
092: module.config = confs[i];
093: this .inputs[j] = module;
094: j++;
095: }
096: }
097: this .emptyAsNull = config.getChild("empty-as-null")
098: .getValueAsBoolean(this .emptyAsNull);
099: this .allNames = config.getChild("all-names").getValueAsBoolean(
100: this .allNames);
101: this .allValues = config.getChild("all-values")
102: .getValueAsBoolean(this .allValues);
103: }
104:
105: public synchronized void lazy_initialize() {
106:
107: try {
108: // obtain input modules
109: if (!this .initialized) {
110: this .inputSelector = (ComponentSelector) this .manager
111: .lookup(INPUT_MODULE_SELECTOR);
112: if (this .inputSelector != null
113: && this .inputSelector instanceof ThreadSafe) {
114:
115: for (int i = 0; i < this .inputs.length; i++) {
116: if (this .inputs[i].name != null)
117: this .inputs[i].input = obtainModule(this .inputs[i].name);
118: }
119:
120: } else if (!(this .inputSelector instanceof ThreadSafe)) {
121: this .manager.release(this .inputSelector);
122: this .inputSelector = null;
123: }
124:
125: this .initialized = true;
126: }
127: } catch (Exception e) {
128: if (getLogger().isWarnEnabled())
129: getLogger().warn(
130: "A problem occurred setting up input modules :'"
131: + e.getMessage());
132: }
133: }
134:
135: public void dispose() {
136:
137: if (this .inputSelector != null) {
138:
139: for (int i = 0; i < this .inputs.length; i++) {
140: if (this .inputs[i].input != null)
141: this .inputSelector.release(this .inputs[i].input);
142: }
143:
144: this .manager.release(this .inputSelector);
145: }
146: }
147:
148: public Object[] getAttributeValues(String attr,
149: Configuration modeConf, Map objectModel)
150: throws ConfigurationException {
151:
152: if (!this .initialized) {
153: this .lazy_initialize();
154: }
155:
156: // obtain correct configuration objects
157: // default vs dynamic
158: Configuration[] inputConfigs = null;
159: boolean allValues = this .allValues;
160: boolean emptyAsNull = this .emptyAsNull;
161: if (modeConf != null && modeConf.getChildren().length > 0) {
162: inputConfigs = modeConf.getChildren("input-module");
163: emptyAsNull = modeConf.getChild("empty-as-null")
164: .getValueAsBoolean(emptyAsNull);
165: allValues = modeConf.getChild("all-values")
166: .getValueAsBoolean(allValues);
167: if (inputConfigs.length == 0)
168: inputConfigs = null;
169: }
170:
171: Object[] value = null;
172: boolean debug = getLogger().isDebugEnabled();
173: List values = null;
174: if (allValues)
175: values = new ArrayList();
176:
177: if (inputConfigs == null) {
178: // static configuration branch
179: int i = 0;
180: while (i < this .inputs.length
181: && (value == null || allValues)) {
182: if (this .inputs[i].name != null) {
183: value = getValues(attr, objectModel,
184: this .inputs[i].input, this .inputs[i].name,
185: this .inputs[i].config);
186: if (emptyAsNull && value != null
187: && value.length == 0)
188: value = null;
189: if (emptyAsNull && value != null
190: && value.length == 1
191: && value[0] instanceof String
192: && value[0].equals(""))
193: value = null;
194: if (debug)
195: getLogger().debug(
196: "read from " + this .inputs[i].name
197: + " attribute " + attr + " as "
198: + value);
199: if (allValues && value != null)
200: values.addAll(Arrays.asList(value));
201: }
202: i++;
203: }
204: } else {
205: // run-time configuration branch
206: int i = 0;
207: while (i < inputConfigs.length
208: && (value == null || allValues)) {
209: String name = inputConfigs[i]
210: .getAttribute("name", null);
211: if (name != null) {
212: value = getValues(attr, objectModel, null, name,
213: inputConfigs[i]);
214: if (emptyAsNull && value != null
215: && value.length == 0)
216: value = null;
217: if (emptyAsNull && value != null
218: && value.length == 1
219: && value[0] instanceof String
220: && value[0].equals(""))
221: value = null;
222: if (debug)
223: getLogger().debug(
224: "read from " + name + " attribute "
225: + attr + " as " + value);
226: if (allValues && value != null)
227: values.addAll(Arrays.asList(value));
228: }
229: i++;
230: }
231: }
232: if (debug)
233: getLogger().debug(
234: "result chaining for " + attr + " is "
235: + (allValues ? values.toArray() : value));
236: return (allValues ? values.toArray() : value);
237: }
238:
239: private void addIterator(Collection col, Iterator iter) {
240: while (iter != null && iter.hasNext())
241: col.add(iter.next());
242: }
243:
244: public Iterator getAttributeNames(Configuration modeConf,
245: Map objectModel) throws ConfigurationException {
246:
247: if (!this .initialized) {
248: this .lazy_initialize();
249: }
250:
251: // obtain correct configuration objects
252: // default vs dynamic
253: Configuration[] inputConfigs = null;
254: boolean emptyAsNull = this .emptyAsNull;
255: boolean allNames = this .allNames;
256: if (modeConf != null && modeConf.getChildren().length > 0) {
257: inputConfigs = modeConf.getChildren("input-module");
258: emptyAsNull = modeConf.getChild("empty-as-null")
259: .getValueAsBoolean(emptyAsNull);
260: allNames = modeConf.getChild("all-names")
261: .getValueAsBoolean(allNames);
262: if (inputConfigs.length == 0)
263: inputConfigs = null;
264: }
265:
266: Iterator value = null;
267: Collection values = null;
268: if (allNames)
269: values = new ArrayList();
270: boolean debug = getLogger().isDebugEnabled();
271:
272: if (inputConfigs == null) {
273: // static configuration branch
274: int i = 0;
275: while (i < this .inputs.length
276: && (value == null || allNames)) {
277: if (this .inputs[i].name != null) {
278: value = getNames(objectModel, this .inputs[i].input,
279: this .inputs[i].name, this .inputs[i].config);
280: if (debug)
281: getLogger()
282: .debug(
283: "read from "
284: + this .inputs[i].name
285: + " AttributeNames as "
286: + value);
287: if (allNames && value != null)
288: addIterator(values, value);
289: }
290: i++;
291: }
292: } else {
293: // run-time configuration branch
294: int i = 0;
295: while (i < inputConfigs.length && value == null) {
296: String name = inputConfigs[i]
297: .getAttribute("name", null);
298: if (name != null) {
299: value = getNames(objectModel, null, name,
300: inputConfigs[i]);
301: if (debug)
302: getLogger()
303: .debug(
304: "read from " + name
305: + " AttributeNames as "
306: + value);
307: if (allNames && value != null)
308: addIterator(values, value);
309: }
310: i++;
311: }
312: }
313: if (debug)
314: getLogger().debug(
315: "result chaining names is "
316: + (allNames ? values.iterator() : value));
317: return (allNames ? values.iterator() : value);
318: }
319:
320: public Object getAttribute(String attr, Configuration modeConf,
321: Map objectModel) throws ConfigurationException {
322:
323: Object[] values = this .getAttributeValues(attr, modeConf,
324: objectModel);
325: if (getLogger().isDebugEnabled())
326: getLogger().debug(
327: "result chaining single for " + attr + " is "
328: + (values != null ? values[0] : "null"));
329: return (values != null ? values[0] : null);
330: }
331:
332: }
|