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.formmodel.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: import org.apache.avalon.framework.service.ServiceException;
025: import org.apache.avalon.framework.service.ServiceSelector;
026:
027: import org.apache.cocoon.forms.FormsConstants;
028: import org.apache.cocoon.forms.formmodel.WidgetDefinition;
029: import org.apache.cocoon.forms.formmodel.WidgetDefinitionBuilder;
030: import org.apache.cocoon.forms.formmodel.WidgetDefinitionBuilderContext;
031: import org.apache.cocoon.forms.util.DomHelper;
032: import org.apache.cocoon.util.location.LocationAttributes;
033:
034: import org.apache.commons.lang.StringUtils;
035: import org.w3c.dom.Element;
036:
037: /**
038: * Form model library.
039: *
040: * @version $Id: Library.java 517733 2007-03-13 15:37:22Z vgritsenko $
041: */
042: public class Library extends AbstractLogEnabled {
043:
044: public static final String SEPARATOR = ":";
045:
046: // managed instances
047: protected ServiceSelector widgetDefinitionBuilderSelector;
048:
049: // own references
050: protected LibraryManager manager;
051:
052: // own instances
053: protected Map definitions = new HashMap();
054: protected Map inclusions = new HashMap();
055:
056: // shared object with dependencies
057: protected final Object shared = new Object();
058:
059: protected String sourceURI;
060: protected WidgetDefinitionBuilderContext context;
061:
062: public Library(LibraryManager lm, ServiceSelector builderSelector) {
063: manager = lm;
064: context = new WidgetDefinitionBuilderContext();
065: context.setLocalLibrary(this );
066: widgetDefinitionBuilderSelector = builderSelector;
067: }
068:
069: public void setSourceURI(String uri) {
070: sourceURI = uri;
071: }
072:
073: public String getSourceURI() {
074: return sourceURI;
075: }
076:
077: public boolean dependenciesHaveChanged() throws LibraryException {
078: Iterator i = this .inclusions.values().iterator();
079: while (i.hasNext()) {
080: Dependency dep = (Dependency) i.next();
081: if (!dep.isValid()) {
082: return true;
083: }
084: }
085:
086: return false;
087: }
088:
089: /**
090: * "Registers" a library to be referenced later under a certain key or prefix.
091: * Definitions will be accessible locally through prefixing: "prefix:definitionid"
092: *
093: * @param key the key
094: * @param sourceURI the source of the library to be know as "key"
095: * @return true if there was no such key used before, false otherwise
096: * @throws LibraryException if unable to load included library
097: */
098: public boolean includeAs(String key, String sourceURI)
099: throws LibraryException {
100: if (!inclusions.containsKey(key) || key.indexOf(SEPARATOR) > -1) {
101: manager.load(sourceURI, this .sourceURI);
102: inclusions.put(key, new Dependency(sourceURI));
103: return true;
104: }
105: return false;
106: }
107:
108: public WidgetDefinition getDefinition(String key)
109: throws LibraryException {
110: String librarykey = null;
111: String definitionkey = key;
112:
113: if (key.indexOf(SEPARATOR) > -1) {
114: String[] parts = StringUtils.split(key, SEPARATOR);
115: librarykey = parts[0];
116: definitionkey = parts[1];
117: for (int i = 2; i < parts.length; i++) {
118: definitionkey += SEPARATOR + parts[i];
119: }
120: }
121:
122: if (librarykey != null) {
123: Dependency dependency = (Dependency) inclusions
124: .get(librarykey);
125: if (dependency != null) {
126: try {
127: return manager.load(dependency.dependencyURI,
128: sourceURI).getDefinition(definitionkey);
129: } catch (Exception e) {
130: throw new LibraryException("Couldn't get library '"
131: + librarykey + "' source='" + dependency
132: + "'", e);
133: }
134: } else {
135: throw new LibraryException("Library '" + librarykey
136: + "' does not exist! (lookup: '" + key + "')");
137: }
138: } else {
139: return (WidgetDefinition) definitions.get(definitionkey);
140: }
141: }
142:
143: public void buildLibrary(Element libraryElement) throws Exception {
144: sourceURI = LocationAttributes.getURI(libraryElement);
145: Element widgetsElement = DomHelper.getChildElement(
146: libraryElement, FormsConstants.DEFINITION_NS,
147: "widgets", true);
148: // All child elements of the widgets element are widgets
149: Element[] widgetElements = DomHelper.getChildElements(
150: widgetsElement, FormsConstants.DEFINITION_NS);
151: for (int i = 0; i < widgetElements.length; i++) {
152: Element widgetElement = widgetElements[i];
153: WidgetDefinition widgetDefinition = buildWidgetDefinition(widgetElement);
154: addDefinition(widgetDefinition);
155: }
156: }
157:
158: public void addDefinition(WidgetDefinition definition)
159: throws LibraryException {
160: if (definition == null) {
161: return;
162: }
163:
164: if (definitions.containsKey(definition.getId())) {
165: throw new LibraryException(
166: "Library already contains a widget with this ID!");
167: }
168:
169: // let the definition know where it comes from
170: definition.setEnclosingLibrary(this );
171:
172: // add def to our list of defs
173: definitions.put(definition.getId(), definition);
174: if (getLogger().isDebugEnabled()) {
175: getLogger().debug(
176: this + ": Added definition '" + definition.getId()
177: + "'");
178: }
179: }
180:
181: protected WidgetDefinition buildWidgetDefinition(
182: Element widgetDefinition) throws Exception {
183: String widgetName = widgetDefinition.getLocalName();
184: WidgetDefinitionBuilder builder;
185: try {
186: builder = (WidgetDefinitionBuilder) widgetDefinitionBuilderSelector
187: .select(widgetName);
188: } catch (ServiceException e) {
189: throw new LibraryException("Unknown kind of widget '"
190: + widgetName + "'.", e, DomHelper
191: .getLocationObject(widgetDefinition));
192: }
193:
194: context.setSuperDefinition(null);
195:
196: String extend = DomHelper.getAttribute(widgetDefinition,
197: "extends", null);
198: if (extend != null) {
199: context.setSuperDefinition(getDefinition(extend));
200: }
201:
202: return builder.buildWidgetDefinition(widgetDefinition, context);
203: }
204:
205: /**
206: * Encapsulates a uri to designate an import plus a timestamp so previously reloaded
207: */
208: protected class Dependency {
209: private final String dependencyURI;
210: private final Object shared;
211:
212: public Dependency(String dependencySourceURI)
213: throws LibraryException {
214: this .dependencyURI = dependencySourceURI;
215: Library lib = manager.load(this .dependencyURI, sourceURI);
216: this .shared = lib.shared;
217: }
218:
219: public boolean isValid() throws LibraryException {
220: Library lib = manager.get(dependencyURI, sourceURI);
221: return lib != null && this.shared == lib.shared;
222: }
223: }
224:
225: }
|