| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.forms.binding.library; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.apache.avalon.framework.logger.AbstractLogEnabled; |
| |
| import org.apache.cocoon.forms.binding.Binding; |
| import org.apache.cocoon.forms.binding.BindingManager; |
| import org.apache.cocoon.forms.binding.JXPathBindingManager; |
| import org.apache.cocoon.forms.util.DomHelper; |
| import org.apache.cocoon.util.location.LocationAttributes; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.w3c.dom.Element; |
| |
| /** |
| * Form binding library. |
| * |
| * @version $Id$ |
| */ |
| public class Library extends AbstractLogEnabled { |
| |
| public static final String SEPARATOR = ":"; |
| |
| // own references |
| protected LibraryManager manager; |
| |
| // own instances |
| protected Map definitions = new HashMap(); |
| protected Map inclusions = new HashMap(); |
| |
| // shared object with dependencies |
| protected final Object shared = new Object(); |
| |
| protected String sourceURI; |
| protected JXPathBindingManager.Assistant assistant; |
| |
| |
| public Library(LibraryManager lm, JXPathBindingManager.Assistant assistant) { |
| this.manager = lm; |
| this.assistant = assistant; |
| } |
| |
| public void setSourceURI(String uri) { |
| sourceURI = uri; |
| } |
| |
| public String getSourceURI() { |
| return sourceURI; |
| } |
| |
| public boolean dependenciesHaveChanged() throws LibraryException { |
| Iterator i = this.inclusions.values().iterator(); |
| while (i.hasNext()) { |
| Dependency dep = (Dependency) i.next(); |
| if (!dep.isValid()) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * "Registers" a library to be referenced later under a certain key or prefix. |
| * Definitions will be accessible locally through prefixing: "prefix:definitionid" |
| * |
| * @param key the key |
| * @param sourceURI the source of the library to be know as "key" |
| * @return true if there was no such key used before, false otherwise |
| * @throws LibraryException if unable to load included library |
| */ |
| public boolean includeAs(String key, String sourceURI) |
| throws LibraryException { |
| // library keys may not contain ":"! |
| if (!inclusions.containsKey(key) || key.indexOf(SEPARATOR) > -1) { |
| manager.load(sourceURI, this.sourceURI); |
| inclusions.put(key, new Dependency(sourceURI)); |
| return true; |
| } |
| return false; |
| } |
| |
| public Binding getBinding(String key) throws LibraryException { |
| String librarykey = null; |
| String definitionkey = key; |
| |
| if (key.indexOf(SEPARATOR) > -1) { |
| String[] parts = StringUtils.split(key, SEPARATOR); |
| librarykey = parts[0]; |
| definitionkey = parts[1]; |
| for (int i = 2; i < parts.length; i++) { |
| definitionkey += SEPARATOR + parts[i]; |
| } |
| } |
| |
| if (librarykey != null) { |
| Dependency dependency = (Dependency) inclusions.get(librarykey); |
| if (dependency != null) { |
| try { |
| return manager.load(dependency.dependencyURI, sourceURI).getBinding(definitionkey); |
| } catch (Exception e) { |
| throw new LibraryException("Couldn't get library '" + librarykey + "' source='" + dependency + "'", e); |
| } |
| } else { |
| throw new LibraryException("Library '" + librarykey + "' does not exist! (lookup: '" + key + "')"); |
| } |
| } else { |
| return (Binding) definitions.get(definitionkey); |
| } |
| } |
| |
| public void buildLibrary(Element libraryElement) throws Exception { |
| sourceURI = LocationAttributes.getURI(libraryElement); |
| this.assistant.getContext().setLocalLibrary(this); |
| Element[] bindingElements = DomHelper.getChildElements(libraryElement, BindingManager.NAMESPACE); |
| for (int i = 0; i < bindingElements.length; i++) { |
| Element bindingElement = bindingElements[i]; |
| Binding binding = this.assistant.getBindingForConfigurationElement(bindingElement); |
| addBinding(binding); |
| } |
| } |
| |
| public void addBinding(Binding binding) throws LibraryException { |
| if (binding == null) { |
| return; |
| } |
| |
| if (definitions.containsKey(binding.getId())) { |
| throw new LibraryException("Library already contains a binding with this ID!"); |
| } |
| |
| binding.setEnclosingLibrary(this); |
| |
| definitions.put(binding.getId(), binding); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug(this + ": Added binding '" + binding.getId() + "'"); |
| } |
| } |
| |
| |
| /** |
| * Encapsulates a uri to designate an import plus a timestamp so previously reloaded |
| */ |
| protected class Dependency { |
| private final String dependencyURI; |
| private final Object shared; |
| |
| public Dependency(String dependencySourceURI) throws LibraryException { |
| this.dependencyURI = dependencySourceURI; |
| Library lib = manager.load(this.dependencyURI,sourceURI); |
| this.shared = lib.shared; |
| } |
| |
| public boolean isValid() throws LibraryException { |
| Library lib = manager.get(dependencyURI, sourceURI); |
| return lib != null && this.shared == lib.shared; |
| } |
| } |
| |
| } |