KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > forms > binding > JXPathBindingManager


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.forms.binding;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.Stack JavaDoc;
20
21 import org.apache.avalon.framework.activity.Disposable;
22 import org.apache.avalon.framework.activity.Initializable;
23 import org.apache.avalon.framework.configuration.Configurable;
24 import org.apache.avalon.framework.configuration.Configuration;
25 import org.apache.avalon.framework.configuration.ConfigurationException;
26 import org.apache.avalon.framework.context.Context;
27 import org.apache.avalon.framework.context.ContextException;
28 import org.apache.avalon.framework.context.Contextualizable;
29 import org.apache.avalon.framework.logger.AbstractLogEnabled;
30 import org.apache.avalon.framework.service.ServiceException;
31 import org.apache.avalon.framework.service.ServiceManager;
32 import org.apache.avalon.framework.service.Serviceable;
33 import org.apache.avalon.framework.thread.ThreadSafe;
34 import org.apache.cocoon.components.LifecycleHelper;
35 import org.apache.cocoon.forms.CacheManager;
36 import org.apache.cocoon.forms.binding.library.Library;
37 import org.apache.cocoon.forms.binding.library.LibraryException;
38 import org.apache.cocoon.forms.binding.library.LibraryManager;
39 import org.apache.cocoon.forms.binding.library.LibraryManagerImpl;
40 import org.apache.cocoon.forms.datatype.DatatypeManager;
41 import org.apache.cocoon.forms.util.DomHelper;
42 import org.apache.cocoon.forms.util.SimpleServiceSelector;
43 import org.apache.cocoon.util.location.LocationAttributes;
44 import org.apache.commons.lang.exception.NestableRuntimeException;
45 import org.apache.excalibur.source.Source;
46 import org.apache.excalibur.source.SourceResolver;
47 import org.w3c.dom.Document JavaDoc;
48 import org.w3c.dom.Element JavaDoc;
49 import org.xml.sax.InputSource JavaDoc;
50
51 /**
52  * JXPathBindingManager provides an implementation of {@link BindingManager}by
53  * usage of the <a HREF="http://jakarta.apache.org/commons/jxpath/index.html">
54  * JXPath package </a>.
55  *
56  * @version $Id: JXPathBindingManager.java 292615 2005-09-30 03:40:16Z antonio $
57  */

58 public class JXPathBindingManager extends AbstractLogEnabled implements
59 BindingManager, Contextualizable, Serviceable, Disposable, Initializable, Configurable,
60 ThreadSafe {
61     
62     private static final String JavaDoc PREFIX = "CocoonFormBinding:";
63     
64     private ServiceManager manager;
65     
66     private DatatypeManager datatypeManager;
67     
68     private Configuration configuration;
69     
70     private SimpleServiceSelector bindingBuilderSelector;
71     
72     private CacheManager cacheManager;
73     
74     private Context avalonContext;
75     
76     private LibraryManagerImpl libraryManager;
77     
78     public void contextualize(Context context) throws ContextException {
79         this.avalonContext = context;
80     }
81     
82     public void service(ServiceManager manager) throws ServiceException {
83         this.manager = manager;
84         this.datatypeManager = (DatatypeManager) manager.lookup(DatatypeManager.ROLE);
85         this.cacheManager = (CacheManager) manager.lookup(CacheManager.ROLE);
86     }
87     
88     public void configure(Configuration configuration)
89     throws ConfigurationException {
90         this.configuration = configuration;
91     }
92     
93     public void initialize() throws Exception JavaDoc {
94         bindingBuilderSelector = new SimpleServiceSelector("binding",
95                 JXPathBindingBuilderBase.class);
96         LifecycleHelper.setupComponent(bindingBuilderSelector,
97                 getLogger(),
98                 this.avalonContext,
99                 this.manager,
100                 configuration.getChild("bindings"));
101         
102         libraryManager = new LibraryManagerImpl();
103         libraryManager.setBindingManager(this);
104         LifecycleHelper.setupComponent(libraryManager,
105                 getLogger(),
106                 this.avalonContext,
107                 this.manager,
108                 configuration.getChild("library"));
109     }
110     
111     public Binding createBinding(Source source) throws BindingException {
112         Binding binding = (Binding) this.cacheManager.get(source, PREFIX);
113         
114         if (binding != null && !binding.isValid())
115             binding = null; //invalidate
116

117         if (binding == null) {
118             try {
119                 InputSource JavaDoc is = new InputSource JavaDoc(source.getInputStream());
120                 is.setSystemId(source.getURI());
121                 
122                 Document JavaDoc doc = DomHelper.parse(is, this.manager);
123                 Element JavaDoc rootElm = doc.getDocumentElement();
124                 if (BindingManager.NAMESPACE.equals(rootElm.getNamespaceURI())) {
125                     binding = getBuilderAssistant()
126                     .getBindingForConfigurationElement(rootElm);
127                     ((JXPathBindingBase) binding).enableLogging(getLogger());
128                     if (getLogger().isDebugEnabled()) {
129                         getLogger().debug("Creation of new binding finished. " + binding);
130                     }
131                 } else {
132                     if (getLogger().isDebugEnabled()) {
133                         getLogger().debug("Root Element of said binding file is in wrong namespace.");
134                     }
135                 }
136                 
137                 this.cacheManager.set(binding, source, PREFIX);
138             } catch (BindingException e) {
139                 throw e;
140             } catch (Exception JavaDoc e) {
141                 throw new BindingException("Error creating binding from " +
142                         source.getURI(), e);
143             }
144         }
145         
146         return binding;
147     }
148     
149     public Binding createBinding(String JavaDoc bindingURI) throws BindingException {
150         SourceResolver sourceResolver = null;
151         Source source = null;
152         
153         try {
154             try {
155                 sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
156                 source = sourceResolver.resolveURI(bindingURI);
157             } catch (Exception JavaDoc e) {
158                 throw new BindingException("Error resolving binding source: " +
159                         bindingURI);
160             }
161             return createBinding(source);
162         } finally {
163             if (source != null) {
164                 sourceResolver.release(source);
165             }
166             if (sourceResolver != null) {
167                 manager.release(sourceResolver);
168             }
169         }
170     }
171     
172     public Assistant getBuilderAssistant() {
173         return new Assistant();
174     }
175     
176     public void dispose() {
177         if (this.bindingBuilderSelector != null) {
178             this.bindingBuilderSelector.dispose();
179             this.bindingBuilderSelector = null;
180         }
181         this.manager.release(this.datatypeManager);
182         this.datatypeManager = null;
183         this.manager.release(this.cacheManager);
184         this.cacheManager = null;
185         this.manager = null;
186     }
187     
188     /**
189      * Assistant Inner class discloses enough features to the created
190      * childBindings to recursively
191      *
192      * This patterns was chosen to prevent Inversion Of Control between this
193      * factory and its builder classes (that could be provided by third
194      * parties.)
195      */

196     /*
197      * NOTE: To get access to the logger in this inner class you must not call
198      * getLogger() as with JDK 1.3 this gives a NoSuchMethod error. You need to
199      * implement an explicit access method for the logger in the outer class.
200      */

201     public class Assistant {
202         
203         private BindingBuilderContext context = new BindingBuilderContext();
204         private Stack JavaDoc contextStack = new Stack JavaDoc();
205         
206         private JXPathBindingBuilderBase getBindingBuilder(String JavaDoc bindingType)
207         throws BindingException {
208             try {
209                 return (JXPathBindingBuilderBase) bindingBuilderSelector
210                 .select(bindingType);
211             } catch (ServiceException e) {
212                 throw new BindingException(
213                         "Cannot handle binding element with " + "name \""
214                         + bindingType + "\".", e);
215             }
216         }
217         
218         /**
219          * Creates a {@link Binding} following the specification in the
220          * provided config element.
221          */

222         public JXPathBindingBase getBindingForConfigurationElement(
223                 Element JavaDoc configElm) throws BindingException {
224             String JavaDoc bindingType = configElm.getLocalName();
225             JXPathBindingBuilderBase bindingBuilder = getBindingBuilder(bindingType);
226             
227             boolean flag = false;
228             if(context.getLocalLibrary() == null) {
229                 Library lib = new Library(libraryManager);
230                 context.setLocalLibrary(lib);
231                 lib.setAssistant(getBuilderAssistant());
232                 lib.setSourceURI(LocationAttributes.getURI(configElm));
233                 flag = true;
234             }
235             
236             if(context.getLocalLibrary()!=null
237                     && configElm.hasAttribute("extends")) {
238                 try {
239                     context.setSuperBinding(context.getLocalLibrary().getBinding(configElm.getAttribute("extends")));
240                     
241                 } catch(LibraryException e) {
242                     //throw new RuntimeException("Error extending binding! (at "+DomHelper.getLocation(configElm)+")",e);
243
throw new NestableRuntimeException("Error extending binding! (at "+DomHelper.getLocation(configElm)+")",e);
244                 }
245             } else {
246                 context.setSuperBinding(null);
247             }
248             
249             JXPathBindingBase childBinding = bindingBuilder.buildBinding(configElm, this);
250             
251             if(flag && childBinding != null) {
252                 childBinding.setLocalLibary(context.getLocalLibrary());
253             }
254             
255             // this might get called unnecessarily, but solves issues with the libraries
256
if(childBinding != null)
257                 childBinding.enableLogging(getLogger());
258             
259             
260             return childBinding;
261         }
262         
263         private JXPathBindingBase[] mergeBindings(JXPathBindingBase[] existing, JXPathBindingBase[] extra) {
264             
265             if(existing == null || existing.length == 0)
266                 return extra;
267             
268             if(extra == null || extra.length == 0)
269                 return existing;
270             
271             // have to do it the stupid painter way..
272
ArrayList JavaDoc list = new ArrayList JavaDoc(existing.length);
273             for(int i=0; i<existing.length; i++)
274                 list.add(existing[i]);
275             
276             for(int i=0; i<extra.length; i++) {
277                 if(extra[i].getId()==null)
278                     list.add(extra[i]);
279                 else {
280                     // try to replace existing one
281
boolean match = false;
282                     for(int j=0; j<list.size(); j++) {
283                         if(extra[i].getId().equals(((JXPathBindingBase)list.get(j)).getId())) {
284                             list.set(j,extra[i]);
285                             match = true;
286                             break; // stop searching
287
}
288                     }
289                     // if no match, just add
290
if(!match)
291                         list.add(extra[i]);
292                 }
293             }
294             
295             return (JXPathBindingBase[])list.toArray(new JXPathBindingBase[0]);
296         }
297         
298         /**
299          * proxy for compatibility
300          *
301          */

302         public JXPathBindingBase[] makeChildBindings(Element JavaDoc parentElement) throws BindingException {
303             return makeChildBindings(parentElement,new JXPathBindingBase[0]);
304         }
305         
306         /**
307          * Makes an array of childBindings for the child-elements of the
308          * provided configuration element.
309          */

310         public JXPathBindingBase[] makeChildBindings(Element JavaDoc parentElement, JXPathBindingBase[] existingBindings)
311         throws BindingException {
312             if (existingBindings == null)
313                 existingBindings = new JXPathBindingBase[0];
314             
315             if (parentElement != null) {
316                 Element JavaDoc[] childElements = DomHelper.getChildElements(
317                         parentElement, BindingManager.NAMESPACE);
318                 if (childElements.length > 0) {
319                     JXPathBindingBase[] childBindings = new JXPathBindingBase[childElements.length];
320                     for (int i = 0; i < childElements.length; i++) {
321                         
322                         pushContext();
323                         context.setSuperBinding(null);
324                         
325                         String JavaDoc id = DomHelper.getAttribute(childElements[i], "id", null);
326                         String JavaDoc path = DomHelper.getAttribute(childElements[i], "path", null);
327                         if(context.getLocalLibrary()!=null && childElements[i].getAttribute("extends")!=null) {
328                             try {
329                                 context.setSuperBinding(context.getLocalLibrary().getBinding(childElements[i].getAttribute("extends")));
330                                 
331                                 if(context.getSuperBinding() == null) // not found in library
332
context.setSuperBinding(getBindingByIdOrPath(id,path,existingBindings));
333                                 
334                             } catch(LibraryException e) {
335                                 throw new BindingException("Error extending binding! (at "+DomHelper.getLocation(childElements[i])+")",e);
336                             }
337                         }
338                         
339                         childBindings[i] = getBindingForConfigurationElement(childElements[i]);
340                         
341                         popContext();
342                     }
343                     return mergeBindings(existingBindings,childBindings);
344                 }
345             }
346             return existingBindings;
347         }
348         
349         private JXPathBindingBase getBindingByIdOrPath(String JavaDoc id, String JavaDoc path, JXPathBindingBase[] bindings) {
350             String JavaDoc name = id;
351             if(name == null) {
352                 name = "Context:"+path;
353             }
354             
355             for(int i=0; i<bindings.length; i++) {
356                 if(name.equals(bindings[i].getId()))
357                     return bindings[i];
358             }
359             return null;
360         }
361         
362         public DatatypeManager getDatatypeManager() {
363             return datatypeManager;
364         }
365         
366         public ServiceManager getServiceManager() {
367             return manager;
368         }
369         
370         public LibraryManager getLibraryManager() {
371             return libraryManager;
372         }
373         
374         public BindingBuilderContext getContext() {
375             return this.context;
376         }
377         private void pushContext() {
378             BindingBuilderContext c = new BindingBuilderContext(context);
379             contextStack.push(context);
380             context = c;
381         }
382         private void popContext() {
383             if(!contextStack.empty()) {
384                 context = (BindingBuilderContext)contextStack.pop();
385             } else {
386                 context = new BindingBuilderContext();
387             }
388         }
389         
390     }
391 }
392
Popular Tags