1 16 package org.apache.cocoon.forms.binding; 17 18 import java.util.ArrayList ; 19 import java.util.Stack ; 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 ; 48 import org.w3c.dom.Element ; 49 import org.xml.sax.InputSource ; 50 51 58 public class JXPathBindingManager extends AbstractLogEnabled implements 59 BindingManager, Contextualizable, Serviceable, Disposable, Initializable, Configurable, 60 ThreadSafe { 61 62 private static final String 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 { 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; 117 if (binding == null) { 118 try { 119 InputSource is = new InputSource (source.getInputStream()); 120 is.setSystemId(source.getURI()); 121 122 Document doc = DomHelper.parse(is, this.manager); 123 Element 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 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 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 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 196 201 public class Assistant { 202 203 private BindingBuilderContext context = new BindingBuilderContext(); 204 private Stack contextStack = new Stack (); 205 206 private JXPathBindingBuilderBase getBindingBuilder(String 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 222 public JXPathBindingBase getBindingForConfigurationElement( 223 Element configElm) throws BindingException { 224 String 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 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 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 ArrayList list = new ArrayList (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 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; } 288 } 289 if(!match) 291 list.add(extra[i]); 292 } 293 } 294 295 return (JXPathBindingBase[])list.toArray(new JXPathBindingBase[0]); 296 } 297 298 302 public JXPathBindingBase[] makeChildBindings(Element parentElement) throws BindingException { 303 return makeChildBindings(parentElement,new JXPathBindingBase[0]); 304 } 305 306 310 public JXPathBindingBase[] makeChildBindings(Element parentElement, JXPathBindingBase[] existingBindings) 311 throws BindingException { 312 if (existingBindings == null) 313 existingBindings = new JXPathBindingBase[0]; 314 315 if (parentElement != null) { 316 Element [] 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 id = DomHelper.getAttribute(childElements[i], "id", null); 326 String 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) 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 id, String path, JXPathBindingBase[] bindings) { 350 String 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 |