Author: pier Date: Tue Nov 2 08:45:57 2004 New Revision: 56383 Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Identifier.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Module.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Dependencies.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/DependencyException.java Modified: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Block.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Descriptor.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Interface.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Library.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Factory.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Instance.java Log: Renaming "Abstract" into "Module". Separating "Descriptor" and "Identifier". Added code to track dependency failures.
Modified: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Block.java ============================================================================== --- cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Block.java (original) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Block.java Tue Nov 2 08:45:57 2004 @@ -12,21 +12,18 @@ * =============================================================================== */ package org.apache.cocoon.kernel.description; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - import org.apache.cocoon.kernel.configuration.Configuration; import org.apache.cocoon.kernel.runtime.DeployerException; /** - * <p>A [EMAIL PROTECTED] Block} represents a block descriptor.</p> + * <p>A [EMAIL PROTECTED] Module} is a specialized implementation of a [EMAIL PROTECTED] Descriptor} + * encloses an kernel interface descriptor in a bean-like object.</p> * * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache * Software Foundation</a>. All rights reserved. */ -public class Block extends Abstract { +public class Block extends Descriptor { /** <p>The name of the exposed Java interface.</p> */ private String clazz = null; @@ -37,7 +34,9 @@ /** <p>Whether the component is a singleton or not.</p> */ private boolean singleton = true; /** <p>The array of identifiers of all implemented interfaces.</p> */ - private String[] implementations = null; + private Identifier[] implementations = null; + /** <p>The array of identifiers of all required modules.</p> */ + private Identifier[] requirements = null; /** * <p>Create a new [EMAIL PROTECTED] Block} instance.</p> @@ -51,26 +50,18 @@ super(configuration); /* Specific block stuff */ - if (! "block".equals(configuration.name())) { + if (! NAMES[BLOCK].equals(configuration.name())) { throw new DeployerException("Invalid root element name for block " + " descriptor at " + configuration.location()); } - - /* Implementations */ - Iterator iterator = configuration.children(NAMESPACE, "implements"); - Set list = new HashSet(); - while (iterator.hasNext()) { - Configuration current = (Configuration) iterator.next(); - String id = current.getStringAttribute("block", null); - if (id == null) { - throw new DeployerException("Extended block identifier not speci" - + "fied in descriptor at " + configuration.location()); - } - list.add(id); - } - this.implementations = (String[]) list.toArray(new String[list.size()]); - /* Provision */ + /* Interface implementations and module requirements */ + this.implementations = super.collectIdentifiers(configuration, + "implementations", "implements", NAMES[INTERFACE]); + this.requirements = super.collectIdentifiers(configuration, + "requirements", "requires", NAMES[MODULE]); + + /* Component provision */ Configuration provides = configuration.child(NAMESPACE, "provides"); this.clazz = provides.getStringAttribute("component", null); @@ -85,17 +76,9 @@ this.destroyer = provides.getStringAttribute("destroy", null); this.singleton = provides.getBooleanAttribute("singleton", true); if ((!singleton) && ((initializer != null) || (destroyer == null))) { - throw new DeployerException("Non-singleton component declares initializer " - + "or destroyer method at " + provides.location()); + throw new DeployerException("Non-singleton component declares " + + "initializer or destroyer method at " + provides.location()); } - - } - - /** - * <p>Check if this block is an <i>abstract</i> block.</p> - */ - public boolean isAbstract() { - return(this.clazz == null); } /** @@ -129,8 +112,15 @@ /** * <p>Return an array of all implemented interface identifers.</p> */ - public String[] getImplementedInterfaces() { + public Identifier[] getImplementedInterfaces() { return(this.implementations); + } + + /** + * <p>Return an array of all required module identifers.</p> + */ + public Identifier[] getRequiredModules() { + return(this.requirements); } /** Modified: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Descriptor.java ============================================================================== --- cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Descriptor.java (original) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Descriptor.java Tue Nov 2 08:45:57 2004 @@ -14,44 +14,39 @@ import java.net.MalformedURLException; import java.net.URL; -import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; -import java.util.List; -import java.util.StringTokenizer; +import java.util.Set; import org.apache.cocoon.kernel.configuration.Configuration; +import org.apache.cocoon.kernel.configuration.ConfigurationException; import org.apache.cocoon.kernel.runtime.DeployerException; /** - * <p>A [EMAIL PROTECTED] Descriptor} represents a block or interface descriptor.</p> + * <p>A [EMAIL PROTECTED] Descriptor} encloses an XML descriptor in a bean-like object.</p> * * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache * Software Foundation</a>. All rights reserved. */ -public abstract class Descriptor { +public abstract class Descriptor extends Identifier { /** <p>The namespace declaration of the XML descriptor.</p> */ public static final String NAMESPACE = "http://apache.org/cocoon/blocks/descriptor/1.0"; /** <p>The type identifying an abstract descriptor.</p> */ - public static final int ABSTRACT = 0; + public static final int MODULE = 0; /** <p>The type identifying a block descriptor.</p> */ public static final int BLOCK = 1; /** <p>The type identifying an interface descriptor.</p> */ public static final int INTERFACE = 2; - /** <p>The full URL of the identifier.</p> */ - private URL url = null; - /** <p>The unversioned part of the identifier.</p> */ - private URL base = null; - /** <p>The major version number.</p> */ - private int major = -1; - /** <p>The minor version number.</p> */ - private int minor = -1; - /** <p>The revision number.</p> */ - private int revision = -1; + /** <p>The names associated with each descriptor type.</p> */ + public static final String NAMES[] = new String [] {"module", "block", "interface"}; + /** <p>The array of libraries associated with this descriptor.</p> */ private URL[] libraries = null; + /** <p>The array of identifiers of all extended blocks.</p> */ + private Identifier[] extensions = null; /** * <p>Create a new [EMAIL PROTECTED] Descriptor} instance.</p> @@ -61,6 +56,7 @@ */ protected Descriptor(Configuration configuration) throws DeployerException { + /* Check the namespace */ if (! NAMESPACE.equals(configuration.namespace())) { throw new DeployerException("Invalid namespace \"" @@ -68,121 +64,45 @@ + configuration.location()); } - /* Parse and setup the ID of this interface or block */ - String id = configuration.getStringAttribute("id", null); - if (id == null) { - throw new DeployerException("Identifier not specified at " - + configuration.location()); - } - + /* Parse and setup the ID of this descriptor */ try { - this.setupIdentifier(new URL(id)); - } catch (Throwable t) { - throw new DeployerException("Unable to parse identifier \"" + id + "\"" - + " specified at " + configuration.location(), t); + super.setup(new URL(configuration.getStringAttribute("id"))); + } catch (ConfigurationException exception) { + throw new DeployerException("Descriptor identifier not specified at " + + configuration.location(), exception); + } catch (MalformedURLException exception) { + throw new DeployerException("Invalid descriptor identifier specified at " + + configuration.location(), exception); } /* Resolve libraries locations */ - URL href = configuration.locationURL(); Configuration libraries = configuration.child(NAMESPACE, "libraries"); Iterator iterator = libraries.children(NAMESPACE, "library"); - List urls = new ArrayList(); - while (iterator.hasNext()) { - Configuration current = (Configuration) iterator.next(); - String url = current.getStringAttribute("href", null); - if (url == null) { - throw new DeployerException("Library href attribute not specified " - + "in descriptor at " + configuration.location()); - } - try { - urls.add(new URL(href, url)); - } catch (Throwable t) { - throw new DeployerException("Unable to resolve library URL speci" - + "fied in descriptor at " + configuration.location(), t); - } - } - this.libraries = (URL[]) urls.toArray(new URL[urls.size()]); - } - - /** - * <p>Return the base identifier (URL without version) of this descriptor.</p> - */ - public URL getBaseIdentifier() { - return(this.base); - } - - /** - * <p>Return the major version number of this descriptor.</p> - */ - public int getMajorVersionNumber() { - return(this.major); - } - - /** - * <p>Return the minor version number of this descriptor.</p> - */ - public int getMinorVersionNumber() { - return(this.minor); - } - - /** - * <p>Return the revision number of this descriptor.</p> - */ - public int getRevisionNumber() { - return(this.revision); - } - - /** - * <p>Compare another [EMAIL PROTECTED] Descriptor} instance for equality.</p> - */ - public boolean equals(Object object) { - if (object == null) return(false); - if (! (object instanceof Descriptor)) return(false); - return(this.toURL().equals(((Descriptor)object).toURL())); - } + Set collector = new HashSet(); + Configuration current = null; - /** - * <p>Compare another [EMAIL PROTECTED] Descriptor} instance for compatibility.</p> - */ - public boolean isCompatibleWith(Descriptor descriptor) { - if (this.equals(descriptor)) return(true); + while (iterator.hasNext()) try { + current = (Configuration) iterator.next(); + String url = current.getStringAttribute("href"); + collector.add(new URL(configuration.locationURL(), url)); + + } catch (ConfigurationException exception) { + throw new DeployerException("Library location not specified in " + + "descriptor at " + current.location(), exception); + + } catch (MalformedURLException exception) { + throw new DeployerException("Invalid library location specified in " + + " descriptor at " + current.location(), exception); + } - URL this_id = this.getBaseIdentifier(); - URL desc_id = descriptor.getBaseIdentifier(); - int this_maj = this.getMajorVersionNumber(); - int desc_maj = descriptor.getMajorVersionNumber(); - int this_min = this.getMinorVersionNumber(); - int desc_min = descriptor.getMinorVersionNumber(); - - if (!this_id.equals(desc_id)) return(false); - if (this_maj != desc_maj) return(false); - if (this_min < desc_min) return(false); + this.libraries = (URL[]) collector.toArray(new URL[collector.size()]); - return(true); - } - - /** - * <p>Return the [EMAIL PROTECTED] URL} representing the full descriptor identifier.</p> - */ - public URL toURL() { - return(this.url); + /* Extensions */ + this.extensions = this.collectIdentifiers(configuration, "extensions", + "extends", configuration.name()); } /** - * <p>Return the [EMAIL PROTECTED] String} representing the full descriptor identifier.</p> - */ - public String toString() { - return(this.toURL().toString()); - } - - /** - * <p>Return a hash code for this instance.</p> - */ - public int hashCode() { - return(this.toURL().hashCode()); - } - - /** * <p>Return an array of [EMAIL PROTECTED] URL}s enclosing all libraries declared in this * descriptor.</p> */ @@ -190,6 +110,13 @@ return(this.libraries); } + /** + * <p>Return an array of all extended block identifers.</p> + */ + public Identifier[] getExtendedBlocks() { + return(this.extensions); + } + /* =========================================================================== */ /* ABSTRACT METHODS */ /* =========================================================================== */ @@ -200,78 +127,42 @@ public abstract int getType(); /* =========================================================================== */ - /* PRIVATE METHODS */ + /* PROTECTED METHODS */ /* =========================================================================== */ /** - * <p>Set up this [EMAIL PROTECTED] Identifier} instance parsing a [EMAIL PROTECTED] URL}.</p> - * - * @param url The [EMAIL PROTECTED] URL} to parse. - * @throws MalformedURLException if the URL could not be parsed. + * <p>Iterate through a given configuration trying to find the identifiers + * located in all element with a given name and in a specified attribute.</p> + * + * @throws ConfigurationException if an element did not contain the attribute. */ - private void setupIdentifier(URL url) - throws MalformedURLException { - /* Get the path */ - String path = url.getPath(); - - /* Check that url is something like http://somewhere/... */ - if (path.indexOf('/') != 0) - throw new MalformedURLException("URL doesn't specify path"); - - /* Retrieve version info out of the URL */ - String version = path.substring(path.lastIndexOf('/') + 1); - if (version.length() == 0) - throw new MalformedURLException("URL doesn't specify version"); - if (path.lastIndexOf('/') < 1) - throw new MalformedURLException("URL doesn't specify version"); - - /* Retrieve the block path out of the URL */ - path = path.substring(1, path.lastIndexOf('/')); - if (path.length() == 0) - throw new MalformedURLException("URL doesn't specify base path"); - - /* Parse the version string */ - StringTokenizer tokenizer = new StringTokenizer(version, "."); - if (!tokenizer.hasMoreTokens()) - throw new MalformedURLException("Major version not specified"); - String major = tokenizer.nextToken(); - if (!tokenizer.hasMoreTokens()) - throw new MalformedURLException("Minor version not specified"); - String minor = tokenizer.nextToken(); - String revision = null; - if (tokenizer.hasMoreTokens()) revision = tokenizer.nextToken(); - - /* Parse numbers in version */ - try { - /* Parse and check major version number */ - this.major = Integer.parseInt(major); - if ((this.major < 0) || (this.minor > 254)) { - throw new MalformedURLException("0 <= Major version <= 254"); - } - - /* Parse and check minor version number */ - this.minor = Integer.parseInt(minor); { - if ((this.minor < 0) || (this.minor > 254)) - throw new MalformedURLException("0 <= Minor version <= 254"); - } - - /* Parse and check revision number */ - if (revision != null) { - this.revision = Integer.parseInt(revision); - if ((this.revision < 0) || (this.revision > 254)) { - throw new MalformedURLException("0 <= Revision <= 254"); - } - } - } catch (NumberFormatException e) { - throw new MalformedURLException("Invalid version number "+ version); + protected Identifier[] collectIdentifiers(Configuration configuration, + String parent, String element, String attribute) + throws DeployerException { + + /* Check if we were given a parent element name */ + if (parent != null) configuration = configuration.child(NAMESPACE, parent); + + /* Prepare the iterator of all named children of the configuration */ + Iterator iterator = configuration.children(NAMESPACE, element); + Set collector = new HashSet(); + + while (iterator.hasNext()) try { + configuration = (Configuration) iterator.next(); + String identifier = configuration.getStringAttribute(attribute); + collector.add(new Identifier(identifier)); + + } catch (MalformedURLException exception) { + throw new DeployerException("Invalid identifier specified in descriptor " + + configuration.location(), exception); + + } catch (ConfigurationException exception) { + throw new DeployerException("Element <" + element + "/> does not " + + "contain the required " + attribute + " attribute at " + + configuration.location(), exception); } - /* Reconstruct the URL and check */ - this.base = new URL(url, '/' + path + '/'); - this.url = new URL(url, '/' + path + '/' + this.major + '.' + this.minor - + (this.revision < 0 ? "" : ("." + this.revision))); - if (!this.url.toString().equals(url.toString())) - throw new MalformedURLException("Parsing versioned URL " + url - + " returned invalid " + this.url); + /* Return whatever we have collected */ + return (Identifier[]) collector.toArray(new Identifier[collector.size()]); } } Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Identifier.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Identifier.java Tue Nov 2 08:45:57 2004 @@ -0,0 +1,205 @@ +/* =============================================================================== * + * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. * + * * + * Licensed 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.kernel.description; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.StringTokenizer; + +/** + * <p>The [EMAIL PROTECTED] Identifier} class encloses a kernel descriptor identifier.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> + * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache + * Software Foundation</a>. All rights reserved. + */ +public class Identifier { + + /** <p>The full URL of the identifier.</p> */ + private URL url = null; + /** <p>The unversioned part of the identifier.</p> */ + private URL base = null; + /** <p>The major version number.</p> */ + private int major = -1; + /** <p>The minor version number.</p> */ + private int minor = -1; + /** <p>The revision number.</p> */ + private int revision = -1; + + /** + * <p>Create a new [EMAIL PROTECTED] Identifier} instance.</p> + */ + protected Identifier() { + super(); + } + + /** + * <p>Create a new [EMAIL PROTECTED] Identifier} instance.</p> + */ + public Identifier(String identifier) + throws MalformedURLException { + if (identifier == null) throw new NullPointerException("Null identifier"); + this.setup(new URL(identifier)); + } + + /** + * <p>Create a new [EMAIL PROTECTED] Identifier} instance.</p> + */ + public Identifier(URL identifier) + throws MalformedURLException { + if (identifier == null) throw new NullPointerException("Null identifier"); + this.setup(identifier); + } + + /** + * <p>Return the base identifier (URL without version) of this descriptor.</p> + */ + public URL getBaseIdentifier() { + if (this.url == null) throw new IllegalStateException(); + return(this.base); + } + + /** + * <p>Return the major version number of this descriptor.</p> + */ + public int getMajorVersionNumber() { + if (this.url == null) throw new IllegalStateException(); + return(this.major); + } + + /** + * <p>Return the minor version number of this descriptor.</p> + */ + public int getMinorVersionNumber() { + if (this.url == null) throw new IllegalStateException(); + return(this.minor); + } + + /** + * <p>Return the revision number of this descriptor.</p> + */ + public int getRevisionNumber() { + if (this.url == null) throw new IllegalStateException(); + return(this.revision); + } + + /** + * <p>Check if the the specified [EMAIL PROTECTED] Object} equals this instance.</p> + */ + public boolean equals(Object object) { + if (this.url == null) throw new IllegalStateException(); + if (object == null) return(false); + if (! (object instanceof Identifier)) return(false); + return(this.toURL().equals(((Identifier)object).toURL())); + } + + /** + * <p>Return the [EMAIL PROTECTED] URL} representing the full descriptor identifier.</p> + */ + public URL toURL() { + if (this.url == null) throw new IllegalStateException(); + return(this.url); + } + + /** + * <p>Return the [EMAIL PROTECTED] String} representing the full descriptor identifier.</p> + */ + public String toString() { + if (this.url == null) throw new IllegalStateException(); + return(this.toURL().toString()); + } + + /** + * <p>Return a hash code for this instance.</p> + */ + public int hashCode() { + if (this.url == null) throw new IllegalStateException(); + return(this.toURL().hashCode()); + } + + /* =========================================================================== */ + /* PRIVATE METHODS */ + /* =========================================================================== */ + + /** + * <p>Set up this [EMAIL PROTECTED] Identifier} instance parsing a [EMAIL PROTECTED] URL}.</p> + * + * @param url The [EMAIL PROTECTED] URL} to parse. + * @throws MalformedURLException if the URL could not be parsed. + */ + protected void setup(URL url) + throws MalformedURLException { + /* Get the path */ + String path = url.getPath(); + + /* Check that url is something like http://somewhere/... */ + if (path.indexOf('/') != 0) + throw new MalformedURLException("URL doesn't specify path"); + + /* Retrieve version info out of the URL */ + String version = path.substring(path.lastIndexOf('/') + 1); + if (version.length() == 0) + throw new MalformedURLException("URL doesn't specify version"); + if (path.lastIndexOf('/') < 1) + throw new MalformedURLException("URL doesn't specify version"); + + /* Retrieve the block path out of the URL */ + path = path.substring(1, path.lastIndexOf('/')); + if (path.length() == 0) + throw new MalformedURLException("URL doesn't specify base path"); + + /* Parse the version string */ + StringTokenizer tokenizer = new StringTokenizer(version, "."); + if (!tokenizer.hasMoreTokens()) + throw new MalformedURLException("Major version not specified"); + String major = tokenizer.nextToken(); + if (!tokenizer.hasMoreTokens()) + throw new MalformedURLException("Minor version not specified"); + String minor = tokenizer.nextToken(); + String revision = null; + if (tokenizer.hasMoreTokens()) revision = tokenizer.nextToken(); + + /* Parse numbers in version */ + try { + /* Parse and check major version number */ + this.major = Integer.parseInt(major); + if ((this.major < 0) || (this.minor > 254)) { + throw new MalformedURLException("0 <= Major version <= 254"); + } + + /* Parse and check minor version number */ + this.minor = Integer.parseInt(minor); { + if ((this.minor < 0) || (this.minor > 254)) + throw new MalformedURLException("0 <= Minor version <= 254"); + } + + /* Parse and check revision number */ + if (revision != null) { + this.revision = Integer.parseInt(revision); + if ((this.revision < 0) || (this.revision > 254)) { + throw new MalformedURLException("0 <= Revision <= 254"); + } + } + } catch (NumberFormatException e) { + throw new MalformedURLException("Invalid version number "+ version); + } + + /* Reconstruct the URL and check */ + this.base = new URL(url, '/' + path + '/'); + this.url = new URL(url, '/' + path + '/' + this.major + '.' + this.minor + + (this.revision < 0 ? "" : ("." + this.revision))); + if (!this.url.toString().equals(url.toString())) + throw new MalformedURLException("Parsing versioned URL " + url + + " returned invalid " + this.url); + } +} Modified: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Interface.java ============================================================================== --- cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Interface.java (original) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Interface.java Tue Nov 2 08:45:57 2004 @@ -16,7 +16,8 @@ import org.apache.cocoon.kernel.runtime.DeployerException; /** - * <p>An [EMAIL PROTECTED] Interface} represents an interface descriptor.</p> + * <p>An [EMAIL PROTECTED] Interface} is a specialized implementation of a [EMAIL PROTECTED] Descriptor} + * encloses an kernel interface descriptor in a bean-like object.</p> * * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache @@ -39,11 +40,12 @@ super(configuration); /* Specific interface stuff */ - if (! "interface".equals(configuration.name())) { + if (! NAMES[INTERFACE].equals(configuration.name())) { throw new DeployerException("Invalid root element name for interface " + " descriptor at " + configuration.location()); } - + + /* Interface exposition */ Configuration exposes = configuration.child(NAMESPACE, "exposes"); this.clazz = exposes.getStringAttribute("interface", null); if (this.clazz == null) { @@ -51,11 +53,11 @@ + exposes.location()); } } - + /** * <p>Return the class name of the exposed Java™ interface.</p> */ - public String getInterface() { + public String getInterfaceName() { return(this.clazz); } Modified: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Library.java ============================================================================== --- cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Library.java (original) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Library.java Tue Nov 2 08:45:57 2004 @@ -18,11 +18,9 @@ import java.util.HashSet; import java.util.NoSuchElementException; -import org.apache.cocoon.kernel.runtime.DeployerException; - /** - * <p>The [EMAIL PROTECTED] Library} class defines a collection of [EMAIL PROTECTED] Descriptor} objects - * enclosed in a simple [EMAIL PROTECTED] HashSet}.</p> + * <p>The [EMAIL PROTECTED] Library} class defines a collection of [EMAIL PROTECTED] Descriptor} instances + * backed by a simple [EMAIL PROTECTED] HashSet}.</p> * * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache @@ -41,13 +39,22 @@ * <p>Add a new [EMAIL PROTECTED] Descriptor} to this [EMAIL PROTECTED] Library}.</p> * * @throws ClassCastException If the [EMAIL PROTECTED] Object} is not a [EMAIL PROTECTED] Descriptor}. + * @throws NullPointerException if the [EMAIL PROTECTED] Object} was <b>null</b>. */ public boolean add(Object object) { - return(super.add((Descriptor) object)); + if (object == null) throw new NullPointerException("Null descriptor"); + + if (super.contains(object)) { + throw new IllegalArgumentException("Descriptor " + object.toString() + + " already present in this Library instance"); + } + + return (super.add((Descriptor) object)); } /** - * <p>Returns an [EMAIL PROTECTED] Iterator} over all descriptors of a specified type.</p> + * <p>Returns an [EMAIL PROTECTED] Iterator} over all [EMAIL PROTECTED] Descriptor}s of the specified + * type stored in this [EMAIL PROTECTED] Library}.</p> * * @throws IllegalArgumentException If the type was not recognized. */ @@ -59,14 +66,17 @@ * <p>Returns the [EMAIL PROTECTED] Descriptor} associated with a specified identifier.</p> * * @return A [EMAIL PROTECTED] Descriptor} instance or <b>null</b> if not found. + * @throws IllegalArgumentException if the identifier was not valid. + * @throws NullPointerException if the identifier was <b>null</b>. */ - public Descriptor get(String identifier) - throws DeployerException { + public Descriptor get(String identifier) { if (identifier == null) throw new NullPointerException("Null identifier"); try { - return this.get(new URL(identifier)); + return this.get(new Identifier(identifier)); } catch (MalformedURLException e) { - throw new DeployerException("Invalid descriptor " + identifier, e); + String message = "Invalid identifier " + identifier; + IllegalArgumentException x = new IllegalArgumentException(message); + throw (IllegalArgumentException) x.initCause(e); } } @@ -74,13 +84,31 @@ * <p>Returns the [EMAIL PROTECTED] Descriptor} associated with a specified identifier.</p> * * @return A [EMAIL PROTECTED] Descriptor} instance or <b>null</b> if not found. + * @throws IllegalArgumentException if the identifier was not valid. + * @throws NullPointerException if the identifier was <b>null</b>. */ public Descriptor get(URL identifier) { if (identifier == null) throw new NullPointerException("Null identifier"); + try { + return this.get(new Identifier(identifier)); + } catch (MalformedURLException e) { + String message = "Invalid identifier " + identifier.toString(); + IllegalArgumentException x = new IllegalArgumentException(message); + throw (IllegalArgumentException) x.initCause(e); + } + } + + /** + * <p>Returns the [EMAIL PROTECTED] Descriptor} associated with a specified identifier.</p> + * + * @return A [EMAIL PROTECTED] Descriptor} instance or <b>null</b> if not found. + * @throws NullPointerException if the identifier was <b>null</b>. + */ + public Descriptor get(Identifier identifier) { Iterator iterator = this.iterator(); while (iterator.hasNext()) { - Descriptor current = (Descriptor) iterator.next(); - if (identifier.equals(current.toURL())) return(current); + Descriptor descriptor = (Descriptor) iterator.next(); + if (descriptor.equals(identifier)) return(descriptor); } return(null); } Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Module.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Module.java Tue Nov 2 08:45:57 2004 @@ -0,0 +1,49 @@ +/* =============================================================================== * + * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. * + * * + * Licensed 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.kernel.description; + +import org.apache.cocoon.kernel.configuration.Configuration; +import org.apache.cocoon.kernel.runtime.DeployerException; + +/** + * <p>A [EMAIL PROTECTED] Module} is a specialized implementation of a [EMAIL PROTECTED] Descriptor} + * encloses an kernel interface descriptor in a bean-like object.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> + * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache + * Software Foundation</a>. All rights reserved. + */ +public class Module extends Descriptor { + + /** + * <p>Create a new [EMAIL PROTECTED] Module} instance.</p> + */ + public Module(Configuration configuration) + throws DeployerException { + super(configuration); + + /* Specific module stuff */ + String name = configuration.name(); + if (! NAMES[MODULE].equals(name)) { + throw new DeployerException("Invalid root element name for module " + + " descriptor at " + configuration.location()); + } + } + + /** + * <p>Return the type of this descriptor.</p> + */ + public int getType() { + return Descriptor.MODULE; + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Dependencies.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Dependencies.java Tue Nov 2 08:45:57 2004 @@ -0,0 +1,122 @@ +/* =============================================================================== * + * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. * + * * + * Licensed 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.kernel.runtime; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cocoon.kernel.description.Identifier; + +/** + * <p>The [EMAIL PROTECTED] Dependencies} class provides a simple utility to analyse dependancy + * trees in block, interfaces and modules.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> + * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache + * Software Foundation</a>. All rights reserved. + */ +public class Dependencies { + + /** <p>The [EMAIL PROTECTED] List} of the current dependancies.</p> */ + private List dependancies = null; + + /** + * <p>Create a new [EMAIL PROTECTED] Dependencies} instance.</p> + */ + public Dependencies() { + this.dependancies = new ArrayList(); + } + + /** + * <p>Push an [EMAIL PROTECTED] Identifier} into this instance.</p> + */ + public void push(Identifier identifier) + throws DependencyException { + if (identifier == null) throw new NullPointerException("Null identifier"); + + /* Loop detected? */ + if (this.dependancies.contains(identifier)) { + List collector = new ArrayList(); + StringBuffer message = new StringBuffer("Circular dependency detected:"); + int start = -1; + for (int x = 0; x < this.dependancies.size(); x++) { + Identifier current = (Identifier) this.dependancies.get(x); + if (current.equals(identifier)) start = 1; + if (start > 0) { + message.append(System.getProperty("line.separator")); + message.append(Integer.toString(start ++)); + message.append(": "); + message.append(current); + collector.add(current); + } + } + message.append(System.getProperty("line.separator")); + message.append(Integer.toString(start ++)); + message.append(": * "); + message.append(identifier); + collector.add(identifier); + + Identifier identifiers[] = new Identifier[collector.size()]; + identifiers = (Identifier[]) collector.toArray(identifiers); + throw new DependencyException(message.toString(), identifiers); + } + + /* No loop, add the sucker */ + this.dependancies.add(identifier); + } + + /** + * <p>Pop the last [EMAIL PROTECTED] Identifier} out of this instance.</p> + * + * @throws IllegalArgumentException if the [EMAIL PROTECTED] Identifier} is not the last. + */ + public void pop(Identifier identifier) { + int pos = this.dependancies.size() - 1; + Identifier last = (Identifier) this.dependancies.get(pos); + if (last.equals(identifier)) { + this.dependancies.remove(pos); + } else { + throw new IllegalArgumentException("Invalid pop of \"" + identifier + + "\" when last element is \"" + last + "\""); + } + } + + /** + * <p>Return a fully prepared [EMAIL PROTECTED] DependencyException}.</p> + */ + public DependencyException fail(String message) { + return (this.fail(message, null)); + } + + /** + * <p>Return a fully prepared [EMAIL PROTECTED] DependencyException}.</p> + */ + public DependencyException fail(String message, Throwable throwable) { + List collector = new ArrayList(); + StringBuffer buffer = new StringBuffer(message); + buffer.append(":"); + + for (int x = 0; x < this.dependancies.size(); x++) { + Identifier current = (Identifier) this.dependancies.get(x); + buffer.append(System.getProperty("line.separator")); + buffer.append(Integer.toString(x + 1)); + buffer.append(": "); + buffer.append(current); + collector.add(current); + } + + Identifier identifiers[] = new Identifier[collector.size()]; + identifiers = (Identifier[]) collector.toArray(identifiers); + return new DependencyException(buffer.toString(), identifiers); + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/DependencyException.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/DependencyException.java Tue Nov 2 08:45:57 2004 @@ -0,0 +1,44 @@ +/* =============================================================================== * + * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. * + * * + * Licensed 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.kernel.runtime; + +import org.apache.cocoon.kernel.description.Identifier; + +/** + * <p>A [EMAIL PROTECTED] DependencyException} is thrown whenever a circular dependancy around + * a descriptor is found.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> + * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache + * Software Foundation</a>. All rights reserved. + */ +public class DependencyException extends DeployerException { + + /** <p>The array of identifiers in circular dependancy.</p> */ + private Identifier identifiers[] = null; + + /** + * <p>Create a new [EMAIL PROTECTED] DependencyException} instance.</p> + */ + protected DependencyException(String message, Identifier identifiers[]) { + super(message); + this.identifiers = identifiers; + } + + /** + * <p>Return the ordered array causing circular dependancies.</p> + */ + public Identifier[] getDependencies() { + return this.identifiers; + } +} Modified: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Factory.java ============================================================================== --- cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Factory.java (original) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Factory.java Tue Nov 2 08:45:57 2004 @@ -24,7 +24,7 @@ import org.apache.cocoon.kernel.Kernel; import org.apache.cocoon.kernel.configuration.Configuration; import org.apache.cocoon.kernel.configuration.ConfigurationBuilder; -import org.apache.cocoon.kernel.description.Abstract; +import org.apache.cocoon.kernel.description.Module; import org.apache.cocoon.kernel.description.Block; import org.apache.cocoon.kernel.description.Descriptor; import org.apache.cocoon.kernel.description.Interface; @@ -60,15 +60,17 @@ String href = current.getStringAttribute("href"); URL url = new URL(config.locationURL(), href); Configuration descriptor = ConfigurationBuilder.parse(url); - if ("abstract".equals(descriptor.name())) { - library.add(new Abstract(descriptor)); - } else if ("block".equals(descriptor.name())) { + String name = descriptor.name(); + + if (Descriptor.NAMES[Descriptor.MODULE].equals(name)) { + library.add(new Module(descriptor)); + } else if (Descriptor.NAMES[Descriptor.BLOCK].equals(name)) { library.add(new Block(descriptor)); - } else if ("interface".equals(descriptor.name())) { + } else if (Descriptor.NAMES[Descriptor.INTERFACE].equals(name)) { library.add(new Interface(descriptor)); } else { throw new DeployerException("Invalid descriptor root element \"" - + descriptor.name() + "\" found in descriptor at" + + descriptor.name() + "\" found in descriptor at " + descriptor.location()); } } catch (DeployerException e) { Modified: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Instance.java ============================================================================== --- cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Instance.java (original) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Instance.java Tue Nov 2 08:45:57 2004 @@ -18,9 +18,9 @@ import java.util.HashSet; import java.util.Set; -import org.apache.cocoon.kernel.description.Abstract; import org.apache.cocoon.kernel.description.Block; import org.apache.cocoon.kernel.description.Descriptor; +import org.apache.cocoon.kernel.description.Identifier; import org.apache.cocoon.kernel.description.Interface; import org.apache.cocoon.kernel.description.Library; @@ -50,49 +50,23 @@ public Instance(Runtime runtime, Block block) throws DeployerException { super(block.getLibraries(), runtime); - Library library = runtime.getLibrary(); - - /* Add all interfaces that must be implemented directly by this block */ + this.block = block; + + /* Process all interfaces, all extended blocks and all modules */ + Dependencies dependencies = new Dependencies(); + dependencies.push(block); Set interfaces = new HashSet(); - String implementations[] = block.getImplementedInterfaces(); - for (int k = 0; k < implementations.length; k++) { - Descriptor descriptor = library.get(implementations[k]); - if (descriptor == null) { - throw new DeployerException("Block " + block.toString() - + " implements unknown block " + implementations[k]); - } - if (descriptor.getType() != Descriptor.INTERFACE) { - throw new DeployerException("Block " + block.toString() - + " implements non-interface " + descriptor.toString()); - } - String clazz = ((Interface) descriptor).getInterface(); - try { - interfaces.add(runtime.loadClass(clazz)); - } catch (ClassNotFoundException e) { - throw new DeployerException("Cant find class " + clazz + " exposed by " - + "interface " + descriptor.toString() + " implemented by " - + block.toString()); - } - } + this.process(runtime.getLibrary(), block.getImplementedInterfaces(), + dependencies, interfaces, Descriptor.INTERFACE); + this.process(runtime.getLibrary(), block.getExtendedBlocks(), + dependencies, interfaces, Descriptor.BLOCK); + this.process(runtime.getLibrary(), block.getRequiredModules(), + dependencies, interfaces, Descriptor.MODULE); + + this.interfaces = new Class[interfaces.size()]; + this.interfaces = (Class[]) interfaces.toArray(this.interfaces); - /* Add the libraries of all extended blocks and check for indirect implems */ - Set collector = new HashSet(); - String extensions[] = block.getExtendedBlocks(); - for (int k = 0; k < extensions.length; k++) { - Descriptor descriptor = library.get(extensions[k]); - if (descriptor == null) { - throw new DeployerException("Block " + block.toString() - + " extends unknown block " + extensions[k]); - } - if (descriptor.getType() == Descriptor.INTERFACE) { - throw new DeployerException("Block " + block.toString() - + " extends interface " + descriptor.toString()); - } - collector.add(block); - this.process(library, (Abstract) descriptor, collector, interfaces); - } - /* Resolve the component class and verify that it implements what it must */ try { this.component = this.loadClass(block.getComponent()); @@ -100,10 +74,11 @@ throw new DeployerException("Unable to resolve component class " + block.getComponent() + " for block " + block.toString(), e); } - this.interfaces = (Class[])interfaces.toArray(new Class[interfaces.size()]); + for (int k = 0; k < this.interfaces.length; k++) { if (this.interfaces[k].isAssignableFrom(this.component)) continue; - throw new DeployerException("Component class \"" + this.component.getName() + + throw new DeployerException("Component \"" + this.component.getName() + "\" is not assignable from \"" + this.interfaces[k] + "\""); } @@ -122,7 +97,7 @@ throw new DeployerException("Initializer method \"" + destroyer + "\" for component \"" + block.getComponent() + "\" not found"); } - + /* Remember where we're coming from */ this.block = block; } @@ -165,55 +140,74 @@ } /** - * <p>Add all libraries provided by a given block and its super-blocks.</p> + * <p>Add all interfaces which must be implemented by this block.</p> */ - private void process(Library lib, Abstract abs, Set collector, Set interfaces) - throws DeployerException { - /* Check circularities */ - if (collector.contains(abs)) { - throw new DeployerException("Circularity exception analysing " - + "extensions for block " + abs.toString()); - } - collector.add(abs); - - /* Process interfaces */ - if (abs.getType() == Descriptor.BLOCK) { - String implementations[] = ((Block)abs).getImplementedInterfaces(); - for (int k = 0; k < implementations.length; k++) { - Descriptor descriptor = lib.get(implementations[k]); - if (descriptor == null) { - throw new DeployerException("Block " + abs.toString() + " imple" - + "ments unknown interface " + implementations[k]); - } - if (descriptor.getType() != Descriptor.INTERFACE) { - throw new DeployerException("Block " + abs.toString() - + " implements non-interface " + descriptor.toString()); - } - - String clazz = ((Interface) descriptor).getInterface(); - try { - interfaces.add(this.getParent().loadClass(clazz)); - } catch (ClassNotFoundException e) { - throw new DeployerException("Cant find class " + clazz - + " exposed by interface " + descriptor.toString() - + " implemented by " + abs.toString()); - } - } + private void process(Library library, Identifier identifiers[], + Dependencies dependencies, Set interfaces, int type) + throws DependencyException { + for (int x = 0; x < identifiers.length; x ++) { + this.process(library, identifiers[x], dependencies, interfaces, type); + } + } + + /** + * <p>Add all interfaces which must be implemented by this block.</p> + */ + private void process(Library library, Identifier identifier, + Dependencies dependencies, Set interfaces, int type) + throws DependencyException { + /* Dependencies check */ + dependencies.push(identifier); + + /* Analyse current interface */ + Descriptor desc = library.get(identifier); + if (desc == null) { + throw dependencies.fail("Descriptor " + identifier + " unknonwn"); + } + + /* Make sure that we are getting what we want */ + if (type != desc.getType()) { + throw dependencies.fail("Invalid descriptor type for " + desc + + ": required \"" + Descriptor.NAMES[type] + "\" found \"" + + Descriptor.NAMES[desc.getType()] + "\""); } - /* Process libraries */ - URL libraries[] = abs.getLibraries(); - for (int k = 0; k < libraries.length; k++) { - super.addURL(libraries[k]); - } - String extensions[] = abs.getExtendedBlocks(); - for (int k = 0; k < extensions.length; k++) { - Descriptor descriptor = lib.get(extensions[k]); - if (descriptor.getType() == Descriptor.INTERFACE) { - throw new DeployerException("Block " + abs.toString() - + " extends interface " + descriptor.toString()); + /* Add java interfaces exposed by interface blocks */ + if (type == Descriptor.INTERFACE) { + String clazz = ((Interface) desc).getInterfaceName(); + try { + /* Load in the parent classloader, the runtime */ + interfaces.add(this.getParent().loadClass(clazz)); + } catch (Throwable t) { + throw dependencies.fail("Unable to locate or access " + clazz + + " for interface " + identifier, t); } - this.process(lib, (Abstract) descriptor, collector, interfaces); } + + /* Add the libraries if this is a block or a module */ + if ((type == Descriptor.BLOCK) || (type == Descriptor.MODULE)) { + URL libs[] = desc.getLibraries(); + for (int x = 0; x < libs.length; x ++) super.addURL(libs[x]); + } + + /* Process extensions declared by the descriptor */ + Identifier identifiers[] = desc.getExtendedBlocks(); + this.process(library, identifiers, dependencies, interfaces, type); + + /* Process interfaces and modules of a block */ + if (type == Descriptor.BLOCK) { + Block block = (Block) desc; + + identifiers = block.getImplementedInterfaces(); + type = Descriptor.INTERFACE; + this.process(library, identifiers, dependencies, interfaces, type); + + identifiers = block.getRequiredModules(); + type = Descriptor.MODULE; + this.process(library, identifiers, dependencies, interfaces, type); + } + + /* Pop from the dependencies check */ + dependencies.pop(identifier); } }