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.forms.binding.library;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022:
023: import org.apache.avalon.framework.logger.AbstractLogEnabled;
024:
025: import org.apache.cocoon.forms.binding.Binding;
026: import org.apache.cocoon.forms.binding.BindingManager;
027: import org.apache.cocoon.forms.binding.JXPathBindingManager;
028: import org.apache.cocoon.forms.util.DomHelper;
029: import org.apache.cocoon.util.location.LocationAttributes;
030:
031: import org.apache.commons.lang.StringUtils;
032: import org.w3c.dom.Element;
033:
034: /**
035: * Form binding library.
036: *
037: * @version $Id: Library.java 517733 2007-03-13 15:37:22Z vgritsenko $
038: */
039: public class Library extends AbstractLogEnabled {
040:
041: public static final String SEPARATOR = ":";
042:
043: // own references
044: protected LibraryManager manager;
045:
046: // own instances
047: protected Map definitions = new HashMap();
048: protected Map inclusions = new HashMap();
049:
050: // shared object with dependencies
051: protected final Object shared = new Object();
052:
053: protected String sourceURI;
054: protected JXPathBindingManager.Assistant assistant;
055:
056: public Library(LibraryManager lm,
057: JXPathBindingManager.Assistant assistant) {
058: this .manager = lm;
059: this .assistant = assistant;
060: }
061:
062: public void setSourceURI(String uri) {
063: sourceURI = uri;
064: }
065:
066: public String getSourceURI() {
067: return sourceURI;
068: }
069:
070: public boolean dependenciesHaveChanged() throws LibraryException {
071: Iterator i = this .inclusions.values().iterator();
072: while (i.hasNext()) {
073: Dependency dep = (Dependency) i.next();
074: if (!dep.isValid()) {
075: return true;
076: }
077: }
078:
079: return false;
080: }
081:
082: /**
083: * "Registers" a library to be referenced later under a certain key or prefix.
084: * Definitions will be accessible locally through prefixing: "prefix:definitionid"
085: *
086: * @param key the key
087: * @param sourceURI the source of the library to be know as "key"
088: * @return true if there was no such key used before, false otherwise
089: * @throws LibraryException if unable to load included library
090: */
091: public boolean includeAs(String key, String sourceURI)
092: throws LibraryException {
093: // library keys may not contain ":"!
094: if (!inclusions.containsKey(key) || key.indexOf(SEPARATOR) > -1) {
095: manager.load(sourceURI, this .sourceURI);
096: inclusions.put(key, new Dependency(sourceURI));
097: return true;
098: }
099: return false;
100: }
101:
102: public Binding getBinding(String key) throws LibraryException {
103: String librarykey = null;
104: String definitionkey = key;
105:
106: if (key.indexOf(SEPARATOR) > -1) {
107: String[] parts = StringUtils.split(key, SEPARATOR);
108: librarykey = parts[0];
109: definitionkey = parts[1];
110: for (int i = 2; i < parts.length; i++) {
111: definitionkey += SEPARATOR + parts[i];
112: }
113: }
114:
115: if (librarykey != null) {
116: Dependency dependency = (Dependency) inclusions
117: .get(librarykey);
118: if (dependency != null) {
119: try {
120: return manager.load(dependency.dependencyURI,
121: sourceURI).getBinding(definitionkey);
122: } catch (Exception e) {
123: throw new LibraryException("Couldn't get library '"
124: + librarykey + "' source='" + dependency
125: + "'", e);
126: }
127: } else {
128: throw new LibraryException("Library '" + librarykey
129: + "' does not exist! (lookup: '" + key + "')");
130: }
131: } else {
132: return (Binding) definitions.get(definitionkey);
133: }
134: }
135:
136: public void buildLibrary(Element libraryElement) throws Exception {
137: sourceURI = LocationAttributes.getURI(libraryElement);
138: this .assistant.getContext().setLocalLibrary(this );
139: Element[] bindingElements = DomHelper.getChildElements(
140: libraryElement, BindingManager.NAMESPACE);
141: for (int i = 0; i < bindingElements.length; i++) {
142: Element bindingElement = bindingElements[i];
143: Binding binding = this .assistant
144: .getBindingForConfigurationElement(bindingElement);
145: addBinding(binding);
146: }
147: }
148:
149: public void addBinding(Binding binding) throws LibraryException {
150: if (binding == null) {
151: return;
152: }
153:
154: if (definitions.containsKey(binding.getId())) {
155: throw new LibraryException(
156: "Library already contains a binding with this ID!");
157: }
158:
159: binding.setEnclosingLibrary(this );
160:
161: definitions.put(binding.getId(), binding);
162: if (getLogger().isDebugEnabled()) {
163: getLogger().debug(
164: this + ": Added binding '" + binding.getId() + "'");
165: }
166: }
167:
168: /**
169: * Encapsulates a uri to designate an import plus a timestamp so previously reloaded
170: */
171: protected class Dependency {
172: private final String dependencyURI;
173: private final Object shared;
174:
175: public Dependency(String dependencySourceURI)
176: throws LibraryException {
177: this .dependencyURI = dependencySourceURI;
178: Library lib = manager.load(this .dependencyURI, sourceURI);
179: this .shared = lib.shared;
180: }
181:
182: public boolean isValid() throws LibraryException {
183: Library lib = manager.get(dependencyURI, sourceURI);
184: return lib != null && this.shared == lib.shared;
185: }
186: }
187:
188: }
|