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.woody.binding;
018:
019: import org.apache.avalon.framework.activity.Disposable;
020: import org.apache.avalon.framework.activity.Initializable;
021: import org.apache.avalon.framework.configuration.Configurable;
022: import org.apache.avalon.framework.configuration.Configuration;
023: import org.apache.avalon.framework.configuration.ConfigurationException;
024: import org.apache.avalon.framework.logger.AbstractLogEnabled;
025: import org.apache.avalon.framework.service.ServiceException;
026: import org.apache.avalon.framework.service.ServiceManager;
027: import org.apache.avalon.framework.service.Serviceable;
028: import org.apache.avalon.framework.thread.ThreadSafe;
029: import org.apache.cocoon.woody.CacheManager;
030: import org.apache.cocoon.woody.datatype.DatatypeManager;
031: import org.apache.cocoon.woody.util.DomHelper;
032: import org.apache.cocoon.woody.util.SimpleServiceSelector;
033: import org.apache.excalibur.source.Source;
034: import org.w3c.dom.Document;
035: import org.w3c.dom.Element;
036: import org.xml.sax.InputSource;
037:
038: /**
039: * JXPathBindingManager provides an implementation of {@link BindingManager}by
040: * usage of the <a href="http://jakarta.apache.org/commons/jxpath/index.html">
041: * JXPath package </a>.
042: *
043: * @version CVS $Id: JXPathBindingManager.java 433543 2006-08-22 06:22:54Z crossley $
044: */
045: public class JXPathBindingManager extends AbstractLogEnabled implements
046: BindingManager, Serviceable, Disposable, Initializable,
047: Configurable, ThreadSafe {
048:
049: private static final String PREFIX = "WoodyBinding:";
050:
051: private ServiceManager manager;
052:
053: private DatatypeManager datatypeManager;
054:
055: private Configuration configuration;
056:
057: private SimpleServiceSelector bindingBuilderSelector;
058:
059: private CacheManager cacheManager;
060:
061: public void service(ServiceManager manager) throws ServiceException {
062: this .manager = manager;
063: this .datatypeManager = (DatatypeManager) manager
064: .lookup(DatatypeManager.ROLE);
065: this .cacheManager = (CacheManager) manager
066: .lookup(CacheManager.ROLE);
067: }
068:
069: public void configure(Configuration configuration)
070: throws ConfigurationException {
071: this .configuration = configuration;
072: }
073:
074: public void initialize() throws Exception {
075: bindingBuilderSelector = new SimpleServiceSelector("binding",
076: JXPathBindingBuilderBase.class);
077: bindingBuilderSelector.enableLogging(getLogger());
078: bindingBuilderSelector.configure(configuration
079: .getChild("bindings"));
080: }
081:
082: public Binding createBinding(Source source) throws BindingException {
083: Binding binding = (Binding) this .cacheManager.get(source,
084: PREFIX);
085: if (binding == null) {
086: try {
087: InputSource is = new InputSource(source
088: .getInputStream());
089: is.setSystemId(source.getURI());
090:
091: Document doc = DomHelper.parse(is);
092: Element rootElm = doc.getDocumentElement();
093: if (BindingManager.NAMESPACE.equals(rootElm
094: .getNamespaceURI())) {
095: binding = getBuilderAssistant()
096: .getBindingForConfigurationElement(rootElm);
097: ((JXPathBindingBase) binding)
098: .enableLogging(getLogger());
099: if (getLogger().isDebugEnabled()) {
100: getLogger().debug(
101: "Creation of new Binding finished. "
102: + binding);
103: }
104: } else {
105: if (getLogger().isDebugEnabled()) {
106: getLogger()
107: .debug(
108: "Root Element of said binding file is in wrong namespace.");
109: }
110: }
111:
112: this .cacheManager.set(binding, source, PREFIX);
113: } catch (BindingException e) {
114: throw e;
115: } catch (Exception e) {
116: throw new BindingException(
117: "Error creating binding from "
118: + source.getURI(), e);
119: }
120: }
121:
122: return binding;
123: }
124:
125: private Assistant getBuilderAssistant() {
126: return new Assistant();
127: }
128:
129: public void dispose() {
130: if (this .bindingBuilderSelector != null) {
131: this .bindingBuilderSelector.dispose();
132: this .bindingBuilderSelector = null;
133: }
134: this .manager.release(this .datatypeManager);
135: this .datatypeManager = null;
136: this .manager.release(this .cacheManager);
137: this .cacheManager = null;
138: this .manager = null;
139: }
140:
141: /**
142: * Assistant Inner class discloses enough features to the created
143: * childBindings to recursively
144: *
145: * This patterns was chosen to prevent Inversion Of Control between this
146: * factory and its builder classes (that could be provided by third
147: * parties.)
148: */
149: /*
150: * NOTE: To get access to the logger in this inner class you must not call
151: * getLogger() as with JDK 1.3 this gives a NoSuchMethod error. You need to
152: * implement an explicit access method for the logger in the outer class.
153: */
154: public class Assistant {
155:
156: private JXPathBindingBuilderBase getBindingBuilder(
157: String bindingType) throws BindingException {
158: try {
159: return (JXPathBindingBuilderBase) bindingBuilderSelector
160: .select(bindingType);
161: } catch (ServiceException e) {
162: throw new BindingException(
163: "Cannot handle binding element with "
164: + "name \"" + bindingType + "\".", e);
165: }
166: }
167:
168: /**
169: * Creates a {@link Binding}following the specification in the
170: * provided config element.
171: */
172: public JXPathBindingBase getBindingForConfigurationElement(
173: Element configElm) throws BindingException {
174: String bindingType = configElm.getLocalName();
175: JXPathBindingBuilderBase bindingBuilder = getBindingBuilder(bindingType);
176: JXPathBindingBase childBinding = bindingBuilder
177: .buildBinding(configElm, this );
178: return childBinding;
179: }
180:
181: /**
182: * Makes an array of childBindings for the child-elements of the
183: * provided configuration element.
184: */
185: public JXPathBindingBase[] makeChildBindings(
186: Element parentElement) throws BindingException {
187: if (parentElement != null) {
188: Element[] childElements = DomHelper.getChildElements(
189: parentElement, BindingManager.NAMESPACE);
190: if (childElements.length > 0) {
191: JXPathBindingBase[] childBindings = new JXPathBindingBase[childElements.length];
192: for (int i = 0; i < childElements.length; i++) {
193: childBindings[i] = getBindingForConfigurationElement(childElements[i]);
194: }
195: return childBindings;
196: }
197: }
198: return null;
199: }
200:
201: public DatatypeManager getDatatypeManager() {
202: return datatypeManager;
203: }
204:
205: public ServiceManager getServiceManager() {
206: return manager;
207: }
208: }
209: }
|