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:
018: package org.apache.cocoon.components.modules.input;
019:
020: import java.util.Iterator;
021: import java.util.Map;
022:
023: import org.apache.avalon.framework.component.ComponentException;
024: import org.apache.avalon.framework.component.ComponentManager;
025: import org.apache.avalon.framework.component.ComponentSelector;
026: import org.apache.avalon.framework.component.Composable;
027: import org.apache.avalon.framework.configuration.Configuration;
028: import org.apache.avalon.framework.configuration.ConfigurationException;
029: import org.apache.avalon.framework.thread.ThreadSafe;
030:
031: /**
032: * AbstractMetaModule gives you the infrastructure for easily
033: * deploying more "meta" InputModules i.e. InputModules that are
034: * composed of other InputModules. In order to get at the Logger, use
035: * getLogger().
036: *
037: * @author <a href="mailto:haul@apache.org">Christian Haul</a>
038: * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
039: * @version CVS $Id: AbstractMetaModule.java 433543 2006-08-22 06:22:54Z crossley $
040: */
041: public abstract class AbstractMetaModule extends AbstractInputModule
042: implements Composable {
043:
044: /** The component manager instance */
045: protected ComponentManager manager;
046:
047: /** The cached InputModule-Selector */
048: protected ComponentSelector inputSelector = null;
049:
050: /** The cached default InputModule */
051: protected InputModule input = null;
052:
053: /** The default InputModule name / shorthand. Defaults to 'request-param' */
054: protected String defaultInput = "request-param"; // default to request parameters
055:
056: /** The default InputModule configuration */
057: protected Configuration inputConf = null; // will become an empty configuration object
058: // during configure() so why bother here...
059:
060: /** Is this instance initialized? */
061: protected boolean initialized = false;
062:
063: /* Constants */
064:
065: protected final static String INPUT_MODULE_SELECTOR = InputModule.ROLE
066: + "Selector";
067:
068: /* Operation codes */
069: private final static int OP_GET = 0;
070: private final static int OP_VALUES = 1;
071: private final static int OP_NAMES = 2;
072: private final static String[] OPNAME = new String[] { "GET_VALUE",
073: "GET_VALUES", "GET_NAMES" };
074:
075: /**
076: * Set the current <code>ComponentManager</code> instance used by this
077: * <code>Composable</code>.
078: */
079: public void compose(ComponentManager manager)
080: throws ComponentException {
081:
082: this .manager = manager;
083: }
084:
085: /**
086: * Initialize the meta module with exactly one other input
087: * module. Since "meta" modules require references to components
088: * of the same role, initialization cannot be done in initialize()
089: * when also implementing ThreadSafe since at that point the
090: * component selector is not yet initialized it would trigger the
091: * creation of a new one resulting in an endless loop of
092: * initializations. Therefore, every module needs to call this
093: * method when it first requires access to another module if the
094: * module itself has not been initialized. Override this method
095: * and dispose() to keep references to more than one module.
096: */
097: public synchronized void lazy_initialize() {
098:
099: try {
100: // obtain input modules
101: if (!this .initialized) {
102: this .inputSelector = (ComponentSelector) this .manager
103: .lookup(INPUT_MODULE_SELECTOR);
104: if (this .inputSelector != null
105: && this .inputSelector instanceof ThreadSafe) {
106:
107: if (this .defaultInput != null) {
108: this .input = obtainModule(this .defaultInput);
109: }
110:
111: } else if (!(this .inputSelector instanceof ThreadSafe)) {
112: this .manager.release(this .inputSelector);
113: this .inputSelector = null;
114: }
115:
116: this .initialized = true;
117: }
118: } catch (Exception e) {
119: if (getLogger().isWarnEnabled())
120: getLogger().error(
121: "A problem occurred setting up input modules :'"
122: + e.getMessage(), e);
123: }
124: }
125:
126: /**
127: * Dispose exactly one cached InputModule. To work on more than
128: * one, override this method and initialize().
129: */
130: public void dispose() {
131:
132: if (this .inputSelector != null) {
133: if (this .input != null)
134: this .inputSelector.release(this .input);
135: this .manager.release(this .inputSelector);
136: }
137: }
138:
139: /**
140: * Obtain a permanent reference to an InputModule.
141: */
142: protected InputModule obtainModule(String type) {
143: ComponentSelector inputSelector = this .inputSelector;
144: InputModule module = null;
145: try {
146: if (inputSelector == null) {
147: inputSelector = (ComponentSelector) this .manager
148: .lookup(INPUT_MODULE_SELECTOR);
149: }
150: if (inputSelector.hasComponent(type)) {
151: if (type != null && inputSelector.hasComponent(type)) {
152: module = (InputModule) inputSelector.select(type);
153: }
154: if (!(module instanceof ThreadSafe)) {
155: inputSelector.release(module);
156: module = null;
157: }
158: }
159: if (type != null && module == null)
160: if (getLogger().isWarnEnabled())
161: getLogger()
162: .warn(
163: "A problem occurred setting up '"
164: + type
165: + "': Selector is not null, Component is "
166: + (inputSelector
167: .hasComponent(type) ? "known"
168: : "unknown"));
169:
170: } catch (ComponentException ce) {
171: if (getLogger().isWarnEnabled())
172: getLogger().warn(
173: "Could not obtain selector for InputModules: "
174: + ce.getMessage());
175: } finally {
176: if (this .inputSelector == null)
177: this .manager.release(inputSelector);
178: // FIXME: Is it OK to keep a reference to the module when we release the selector?
179: }
180:
181: return module;
182: }
183:
184: /**
185: * release a permanent reference to an InputModule.
186: */
187: protected void releaseModule(InputModule module) {
188: ComponentSelector inputSelector = this .inputSelector;
189: if (module != null) {
190: try {
191: // FIXME: Is it OK to release a module when we have released the selector before?
192: if (inputSelector == null)
193: inputSelector = (ComponentSelector) this .manager
194: .lookup(INPUT_MODULE_SELECTOR);
195:
196: inputSelector.release(module);
197: module = null;
198:
199: } catch (ComponentException ce) {
200: if (getLogger().isWarnEnabled())
201: getLogger().warn(
202: "Could not obtain selector for InputModules: "
203: + ce.getMessage());
204: } finally {
205: if (this .inputSelector == null)
206: this .manager.release(inputSelector);
207: }
208: }
209: }
210:
211: /**
212: * Get names of available attributes in the specified (usually statically
213: * assigned) Input Module.
214: * @see InputModule#getAttributeNames(Configuration, Map)
215: */
216: protected Iterator getNames(Map objectModel, InputModule staticMod,
217: String staticModName, Configuration staticModConf)
218: throws ConfigurationException {
219:
220: return (Iterator) this .get(OP_NAMES, null, objectModel,
221: staticMod, staticModName, staticModConf, null, null,
222: null);
223: }
224:
225: /**
226: * Get names of available attributes in one of the specified Input Modules
227: * (static or dynamic, dynamic preferred). Dynamic IM may be
228: * <code>null</code>.
229: * @see InputModule#getAttributeNames(Configuration, Map)
230: */
231: protected Iterator getNames(Map objectModel, InputModule staticMod,
232: String staticModName, Configuration staticModConf,
233: InputModule dynamicMod, String dynamicModName,
234: Configuration dynamicModConf) throws ConfigurationException {
235:
236: return (Iterator) this .get(OP_NAMES, null, objectModel,
237: staticMod, staticModName, staticModConf, dynamicMod,
238: dynamicModName, dynamicModConf);
239: }
240:
241: protected Object getValue(String attr, Map objectModel,
242: ModuleHolder holder) throws ConfigurationException {
243: return this .getValue(attr, objectModel, holder.input,
244: holder.name, holder.config);
245: }
246:
247: protected Object getValue(String attr, Map objectModel,
248: ModuleHolder staticHolder, ModuleHolder dynamicHolder)
249: throws ConfigurationException {
250: return this .getValue(attr, objectModel, staticHolder.input,
251: staticHolder.name, dynamicHolder.config);
252: }
253:
254: protected Object[] getValues(String attr, Map objectModel,
255: ModuleHolder holder) throws ConfigurationException {
256: return this .getValues(attr, objectModel, holder.input,
257: holder.name, holder.config);
258: }
259:
260: protected Object[] getValues(String attr, Map objectModel,
261: ModuleHolder staticHolder, ModuleHolder dynamicHolder)
262: throws ConfigurationException {
263: return this .getValues(attr, objectModel, staticHolder.input,
264: staticHolder.name, dynamicHolder.config);
265: }
266:
267: /**
268: * Get an attribute's value from a (usually statically assigned) Input
269: * Module.
270: * @see InputModule#getAttribute(String, Configuration, Map)
271: */
272: protected Object getValue(String attr, Map objectModel,
273: InputModule staticMod, String staticModName,
274: Configuration staticModConf) throws ConfigurationException {
275:
276: return this .get(OP_GET, attr, objectModel, staticMod,
277: staticModName, staticModConf, null, null, null);
278: }
279:
280: /**
281: * Get attribute's value in one of the specified Input Modules
282: * (static or dynamic, dynamic preferred). Dynamic IM may be
283: * <code>null</code>.
284: * @see InputModule#getAttribute(String, Configuration, Map)
285: */
286: protected Object getValue(String attr, Map objectModel,
287: InputModule staticMod, String staticModName,
288: Configuration staticModConf, InputModule dynamicMod,
289: String dynamicModName, Configuration dynamicModConf)
290: throws ConfigurationException {
291:
292: return this .get(OP_GET, attr, objectModel, staticMod,
293: staticModName, staticModConf, dynamicMod,
294: dynamicModName, dynamicModConf);
295: }
296:
297: /**
298: * Get an attribute's values from a (usually statically assigned) Input
299: * Module.
300: * @see InputModule#getAttributeValues(String, Configuration, Map)
301: */
302: protected Object[] getValues(String attr, Map objectModel,
303: InputModule staticMod, String staticModName,
304: Configuration staticModConf) throws ConfigurationException {
305:
306: return (Object[]) this .get(OP_VALUES, attr, objectModel,
307: staticMod, staticModName, staticModConf, null, null,
308: null);
309: }
310:
311: /**
312: * Get attribute's values in one of the specified Input Modules
313: * (static or dynamic, dynamic preferred). Dynamic IM may be
314: * <code>null</code>.
315: * @see InputModule#getAttributeValues(String, Configuration, Map)
316: */
317: protected Object[] getValues(String attr, Map objectModel,
318: InputModule staticMod, String staticModName,
319: Configuration staticModConf, InputModule dynamicMod,
320: String dynamicModName, Configuration dynamicModConf)
321: throws ConfigurationException {
322:
323: return (Object[]) this .get(OP_VALUES, attr, objectModel,
324: staticMod, staticModName, staticModConf, dynamicMod,
325: dynamicModName, dynamicModConf);
326: }
327:
328: /**
329: * Encapsulates use of an InputModule. Does all the lookups and so on.
330: * The second module (dynamic) is preferred if it has an non null name. If
331: * an exception is encountered, a warn message is printed and null is
332: * returned.
333: * @param op Operation to perform ({@link #OP_GET}, {@link #OP_NAMES}, {@link #OP_VALUES}).
334: *
335: * @return Either an Object, an Object[], or an Iterator, depending on <code>op</code> param.
336: */
337: private Object get(int op, String attr, Map objectModel,
338: InputModule staticMod, String staticModName,
339: Configuration staticModConf, InputModule dynamicMod,
340: String dynamicModName, Configuration dynamicModConf)
341: throws ConfigurationException {
342:
343: ComponentSelector cs = this .inputSelector;
344: Object value = null;
345: String name = null;
346: InputModule input = null;
347: Configuration conf = null;
348: boolean release = false;
349:
350: try {
351: if (cs == null) {
352: try {
353: cs = (ComponentSelector) this .manager
354: .lookup(INPUT_MODULE_SELECTOR);
355: } catch (ComponentException e) {
356: throw new ConfigurationException(
357: "Could not find MetaModule's module selector",
358: e);
359: }
360: }
361:
362: boolean useDynamic;
363: if (dynamicMod == null && dynamicModName == null) {
364: useDynamic = false;
365: input = staticMod;
366: name = staticModName;
367: conf = staticModConf;
368: } else {
369: useDynamic = true;
370: input = dynamicMod;
371: name = dynamicModName;
372: conf = dynamicModConf;
373: }
374:
375: if (getLogger().isDebugEnabled()) {
376: getLogger().debug(
377: "MetaModule performing op "
378: + OPNAME[op]
379: + " on "
380: + (useDynamic ? "dynamically"
381: : "statically")
382: + " "
383: + (input == null ? "created"
384: : "assigned") + " module '"
385: + name + "', using config "
386: + dynamicModConf);
387: }
388:
389: if (input == null) {
390: if (cs.hasComponent(name)) {
391: release = true;
392: try {
393: input = (InputModule) cs.select(name);
394: } catch (ComponentException e) {
395: throw new ConfigurationException(
396: "MetaModule unable to create "
397: + (useDynamic ? "dynamically"
398: : "statically")
399: + " specified internal module '"
400: + name + "'", e);
401: }
402: } else {
403: throw new ConfigurationException(
404: "MetaModule: No such InputModule: " + name);
405: }
406: }
407:
408: switch (op) {
409: case OP_GET:
410: value = input.getAttribute(attr, conf, objectModel);
411: break;
412: case OP_VALUES:
413: value = input.getAttributeValues(attr, conf,
414: objectModel);
415: break;
416: case OP_NAMES:
417: value = input.getAttributeNames(conf, objectModel);
418: break;
419: }
420:
421: if (getLogger().isDebugEnabled())
422: getLogger().debug(
423: "using " + name + " as " + input + " for " + op
424: + " (" + attr + ") and " + conf
425: + " gives " + value);
426:
427: } finally {
428: if (release)
429: cs.release(input);
430:
431: if (this.inputSelector == null)
432: this.manager.release(cs);
433: }
434:
435: return value;
436: }
437:
438: }
|