/* * 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.formmodel.library; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceSelector; import org.apache.cocoon.forms.FormsConstants; import org.apache.cocoon.forms.formmodel.WidgetDefinition; import org.apache.cocoon.forms.formmodel.WidgetDefinitionBuilder; import org.apache.cocoon.forms.formmodel.WidgetDefinitionBuilderContext; 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 model library. * * @version $Id$ */ public class Library extends AbstractLogEnabled { public static final String SEPARATOR = ":"; // managed instances protected ServiceSelector widgetDefinitionBuilderSelector; // 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; public Library(LibraryManager lm, ServiceSelector builderSelector) { manager = lm; widgetDefinitionBuilderSelector = builderSelector; } 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 { if (!inclusions.containsKey(key) || key.indexOf(SEPARATOR) > -1) { manager.load(sourceURI, this.sourceURI); inclusions.put(key, new Dependency(sourceURI)); return true; } return false; } public WidgetDefinition getDefinition(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).getDefinition(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 (WidgetDefinition) definitions.get(definitionkey); } } public void buildLibrary(Element libraryElement) throws Exception { sourceURI = LocationAttributes.getURI(libraryElement); Element widgetsElement = DomHelper.getChildElement(libraryElement, FormsConstants.DEFINITION_NS, "widgets", true); WidgetDefinitionBuilderContext context = new WidgetDefinitionBuilderContext(this); // All child elements of the widgets element are widgets Element[] widgetElements = DomHelper.getChildElements(widgetsElement, FormsConstants.DEFINITION_NS); for (int i = 0; i < widgetElements.length; i++) { Element widgetElement = widgetElements[i]; buildWidgetDefinition(widgetElement, context); } } private void buildWidgetDefinition(Element widgetDefinition, WidgetDefinitionBuilderContext context) throws Exception { String widgetName = widgetDefinition.getLocalName(); WidgetDefinitionBuilder builder; try { builder = (WidgetDefinitionBuilder) widgetDefinitionBuilderSelector.select(widgetName); } catch (ServiceException e) { throw new LibraryException("Unknown kind of widget '" + widgetName + "'.", e, DomHelper.getLocationObject(widgetDefinition)); } context.setSuperDefinition(null); String extend = DomHelper.getAttribute(widgetDefinition, "extends", null); if (extend != null) { context.setSuperDefinition(getDefinition(extend)); } WidgetDefinition definition = builder.buildWidgetDefinition(widgetDefinition, context); addDefinition(definition); } public void addDefinition(WidgetDefinition definition) throws LibraryException { if (definition == null) { return; } if (definitions.containsKey(definition.getId())) { throw new LibraryException("Library already contains a widget with this ID!"); } // let the definition know where it comes from definition.setEnclosingLibrary(this); // add def to our list of defs definitions.put(definition.getId(), definition); if (getLogger().isDebugEnabled()) { getLogger().debug(this + ": Added definition '" + definition.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; } } }