You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by pi...@apache.org on 2004/11/02 17:45:58 UTC

svn commit: rev 56383 - in cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel: description runtime

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 {@link Block} represents a block descriptor.</p> 
+ * <p>A {@link Module} is a specialized implementation of a {@link Descriptor}
+ * encloses an kernel interface descriptor in a bean-like object.</p>
  *
  * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
  * @author Copyright &copy; 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 {@link 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 {@link Descriptor} represents a block or interface descriptor.</p> 
+ * <p>A {@link Descriptor} encloses an XML descriptor in a bean-like object.</p>
  *
  * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
  * @author Copyright &copy; 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 {@link 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 {@link 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 {@link 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 {@link 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 {@link 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 {@link 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 {@link Identifier} instance parsing a {@link URL}.</p>
-     *
-     * @param url The {@link 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 {@link Identifier} class encloses a kernel descriptor identifier.</p> 
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright &copy; 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 {@link Identifier} instance.</p>
+     */
+    protected Identifier() {
+        super();
+    }
+
+    /**
+     * <p>Create a new {@link 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 {@link 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 {@link 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 {@link URL} representing the full descriptor identifier.</p>
+     */
+    public URL toURL() {
+        if (this.url == null) throw new IllegalStateException();
+        return(this.url);
+    }
+
+    /**
+     * <p>Return the {@link 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 {@link Identifier} instance parsing a {@link URL}.</p>
+     *
+     * @param url The {@link 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 {@link Interface} represents an interface descriptor.</p> 
+ * <p>An {@link Interface} is a specialized implementation of a {@link Descriptor}
+ * encloses an kernel interface descriptor in a bean-like object.</p>
  *
  * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
  * @author Copyright &copy; 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&trade; 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 {@link Library} class defines a collection of {@link Descriptor} objects
- * enclosed in a simple {@link HashSet}.</p> 
+ * <p>The {@link Library} class defines a collection of {@link Descriptor} instances
+ * backed by a simple {@link HashSet}.</p> 
  *
  * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
  * @author Copyright &copy; 2000-2004 <a href="http://www.apache.org/">The Apache
@@ -41,13 +39,22 @@
      * <p>Add a new {@link Descriptor} to this {@link Library}.</p>
      *
      * @throws ClassCastException If the {@link Object} is not a {@link Descriptor}.
+     * @throws NullPointerException if the {@link 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 {@link Iterator} over all descriptors of a specified type.</p>
+     * <p>Returns an {@link Iterator} over all {@link Descriptor}s of the specified
+     * type stored in this {@link Library}.</p>
      *
      * @throws IllegalArgumentException If the type was not recognized.
      */
@@ -59,14 +66,17 @@
      * <p>Returns the {@link Descriptor} associated with a specified identifier.</p>
      *
      * @return A {@link 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 {@link Descriptor} associated with a specified identifier.</p>
      *
      * @return A {@link 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 {@link Descriptor} associated with a specified identifier.</p>
+     *
+     * @return A {@link 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 {@link Module} is a specialized implementation of a {@link Descriptor}
+ * encloses an kernel interface descriptor in a bean-like object.</p>
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright &copy; 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 {@link 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 {@link Dependencies} class provides a simple utility to analyse dependancy
+ * trees in block, interfaces and modules.</p> 
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright &copy; 2000-2004 <a href="http://www.apache.org/">The Apache
+ *         Software Foundation</a>. All rights reserved.
+ */
+public class Dependencies {
+
+    /** <p>The {@link List} of the current dependancies.</p> */
+    private List dependancies = null; 
+
+    /**
+     * <p>Create a new {@link Dependencies} instance.</p>
+     */
+    public Dependencies() {
+        this.dependancies = new ArrayList();
+    }
+
+    /**
+     * <p>Push an {@link 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 {@link Identifier} out of this instance.</p>
+     * 
+     * @throws IllegalArgumentException if the {@link 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 {@link DependencyException}.</p>
+     */
+    public DependencyException fail(String message) {
+        return (this.fail(message, null));
+    }
+
+    /**
+     * <p>Return a fully prepared {@link 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 {@link DependencyException} is thrown whenever a circular dependancy around
+ * a descriptor is found.</p> 
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright &copy; 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 {@link 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);
     }
 }