Author: pier Date: Sun Oct 31 18:10:16 2004 New Revision: 56181 Added: cocoon/whiteboard/kernel/ cocoon/whiteboard/kernel/LICENSE.txt cocoon/whiteboard/kernel/src/ cocoon/whiteboard/kernel/src/org/ cocoon/whiteboard/kernel/src/org/apache/ cocoon/whiteboard/kernel/src/org/apache/cocoon/ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/Kernel.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/KernelException.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/Configuration.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationBuilder.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationException.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationSerializer.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/Parameters.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/ 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/ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Deployer.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Factory.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Instance.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Runtime.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Wiring.java cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/startup/ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/startup/Main.java Log: Adding new dependancy-injection based Kernel
Added: cocoon/whiteboard/kernel/LICENSE.txt ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/LICENSE.txt Sun Oct 31 18:10:16 2004 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/Kernel.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/Kernel.java Sun Oct 31 18:10:16 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; + +/** + * <p>The [EMAIL PROTECTED] Kernel} interface describes the unique contract between the + * kernel internals and its blocks.</p> + * + * <p>Note that <i>normally</i> blocks deployed by this [EMAIL PROTECTED] Kernel} won't have + * to know about this interface, as all configuration is done through dependancy + * injection using <i>"Plain Old Java Objects"</i> setters and getters.</p> + * + * <p>Only objects requiring direct access to the [EMAIL PROTECTED] Kernel} itself and requiring + * to communicate with every part of the deployment environment will have to provide + * a simple <code>setKernel(Kernel kernel)</code> setter method which (when correctly + * configured) will be called with an instance of this interface.</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 interface Kernel { + + /** + * <p>Returns the instance of a component deployed by the [EMAIL PROTECTED] Kernel}.</p> + * + * @param name The name of the block instance deployed by this [EMAIL PROTECTED] Kernel}. + * @return A <b>non-null</b> object. + * @throws KernelException If an error occurred accessing the instance. + */ + public Object lookup(String name) + throws KernelException; + +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/KernelException.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/KernelException.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,38 @@ +/* =============================================================================== * + * 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; + +/** + * <p>A [EMAIL PROTECTED] KernelException} is thrown whenever an error occurred in the lookup + * operation performed by the [EMAIL PROTECTED] Kernel}.</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 KernelException extends Exception { + + /** + * <p>Create a new [EMAIL PROTECTED] KernelException} instance.</p> + */ + public KernelException(String message) { + super(message); + } + + /** + * <p>Create a new [EMAIL PROTECTED] KernelException} instance.</p> + */ + public KernelException(String message, Throwable throwable) { + super(message, throwable); + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/Configuration.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/Configuration.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,1159 @@ +/* =============================================================================== * + * 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.configuration; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * <p>The [EMAIL PROTECTED] Configuration} class provides an XML/DOM-like view over a + * set of configurable [EMAIL PROTECTED] Parameters}.</p> + * + * <p>In the context of a [EMAIL PROTECTED] Configuration}, [EMAIL PROTECTED] Parameters} are seen + * as "attributes" of the configuration element itself.</p> + * + * <p>Furthermore a number of methods have been added to retrieve the node + * namespace, name, and value, effectively allowing an XML-like structure + * to be mapped into a [EMAIL PROTECTED] Configuration}.</p> + * + * <p>This is <b>not</b> a complete XML representation of a document, as the + * [EMAIL PROTECTED] Configuration} class does no allow text nodes to be intermixed with + * children [EMAIL PROTECTED] Configuration} nodes, does not support comments and/or + * processing instructions and most important <b>does not support attribute + * name spaces</b>.</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 Configuration extends ArrayList { + + /** <p>Whether this instance is locked or not.</p> */ + private boolean locked = false; + + /** <p>The name of this [EMAIL PROTECTED] Configuration} element. */ + private String name = null; + + /** <p>The namespace associated with this [EMAIL PROTECTED] Configuration} element. */ + private String namespace = null; + + /** <p>The value of [EMAIL PROTECTED] Configuration} element. */ + private Object value = null; + + /** <p>The [EMAIL PROTECTED] Parameters} instance to use as attributes. */ + private Parameters attributes = null; + + /** <p>The configuration location (if any).</p> */ + private String location = null; + + /** <p>The configuration location URL (if any).</p> */ + private URL url = null; + + /** <p>The hash code of this instance.</p> */ + private int hash = 0; + + /* ====================================================================== */ + + /** + * <p>Create a new empty [EMAIL PROTECTED] Configuration} element to be used only + * when returning unavailable children.</p> + */ + private Configuration() { + super(); + this.name = ""; + this.namespace = null; + this.attributes = new Parameters(); + this.lock(); + this.hash = 0; + } + + /** + * <p>Create a new [EMAIL PROTECTED] Configuration} element with a specified name.</p> + * + * @param name this [EMAIL PROTECTED] Configuration} element name. + * @throws NullPointerException if the specified name was <b>null</b>. + * @throws IllegalArgumentException if the specified name was empty. + */ + public Configuration(String name) { + this(null, name, null); + } + + /** + * <p>Create a new [EMAIL PROTECTED] Configuration} element with a specified name and + * an optional namespace associated with it.</p> + * + * @param name this [EMAIL PROTECTED] Configuration} element name. + * @param namespace the name space associated with the element name. + * @throws NullPointerException if the specified name was <b>null</b>. + * @throws IllegalArgumentException if the specified name was empty. + */ + public Configuration(String namespace, String name) { + this(namespace, name, null); + } + + /** + * <p>Create a new [EMAIL PROTECTED] Configuration} element with a specified name and + * a [EMAIL PROTECTED] Parameters} instance to use as element attributes.</p> + * + * @param name this [EMAIL PROTECTED] Configuration} element name. + * @param attributes the [EMAIL PROTECTED] Parameters} instance to use as attributes. + * @throws NullPointerException if the specified name was <b>null</b>. + * @throws IllegalArgumentException if the specified name was empty. + */ + public Configuration(String name, Parameters attributes) { + this(null, name, attributes); + } + + /** + * <p>Create a new [EMAIL PROTECTED] Configuration} element with a specified name, an + * optional namespace associated with it and a [EMAIL PROTECTED] Parameters} instance + * to use as element attributes.</p> + * + * @param name this [EMAIL PROTECTED] Configuration} element name. + * @param namespace the name space associated with the element name. + * @param attributes the [EMAIL PROTECTED] Parameters} instance to use as attributes. + * @throws NullPointerException if the specified name was <b>null</b>. + * @throws IllegalArgumentException if the specified name was empty. + */ + public Configuration(String namespace, String name, Parameters attributes) { + super(); + if (name == null) throw new NullPointerException("Null name"); + if (name.equals("")) throw new IllegalArgumentException("Empty name"); + this.name = name; + this.namespace = ("".equals(namespace)? null: namespace); + this.attributes = (attributes == null? new Parameters(): attributes); + this.hash = new String(this.namespace + "|" + this.name).hashCode(); + } + + /* ====================================================================== */ + + /** + * <p>Lock this [EMAIL PROTECTED] Configuration} instance.</p> + * + * <p>After this method is called, no further modifications are allowed + * into this [EMAIL PROTECTED] Configuration} instance, and any modification operation + * will throw a [EMAIL PROTECTED] ConfigurationException}.</p> + * + * @return this [EMAIL PROTECTED] Configuration} instance. + */ + public Configuration lock() { + this.locked = true; + return(this); + } + + /* ====================================================================== */ + + /** + * <p>Return the name of this [EMAIL PROTECTED] Configuration} element.</p> + */ + public String name() { + return(this.name); + } + + /** + * <p>Return the namespace declaration (if any) associated with this + * [EMAIL PROTECTED] Configuration} element.</p> + */ + public String namespace() { + return(this.namespace); + } + + /** + * <p>Return the [EMAIL PROTECTED] Parameters} instance backing up attribute names + * and values.</p> + */ + public Parameters attributes() { + return(this.attributes); + } + + /* ====================================================================== */ + + /** + * <p>Add the specified [EMAIL PROTECTED] Configuration} instance as a child of this + * instance at the end of this list.</p> + * + * @param child the child [EMAIL PROTECTED] Configuration} + * @return <b>true</b> if this list was modified, <b>false</b> otherwise. + * @throws NullPointerException if the child was <b>null</b>. + * @throws ClassCastException if the child was not a [EMAIL PROTECTED] Configuration}. + */ + public boolean add(Object child) { + this.check(child); + return(super.add(child)); + } + + /** + * <p>Add the specified [EMAIL PROTECTED] Configuration} instance as a child of this + * instance at the specified offset.</p> + * + * @param index the offset where the child must be added. + * @param child the child [EMAIL PROTECTED] Configuration} + * @return <b>true</b> if this list was modified, <b>false</b> otherwise. + * @throws NullPointerException if the child was <b>null</b>. + * @throws ClassCastException if the child was not a [EMAIL PROTECTED] Configuration}. + */ + public void add(int index, Object child) { + this.check(child); + super.add(index, child); + } + + /** + * <p>Add the specified collection of [EMAIL PROTECTED] Configuration} instances as + * children of this instance at the end of this list.</p> + * + * @param children the collection of children [EMAIL PROTECTED] Configuration} + * @return <b>true</b> if this list was modified, <b>false</b> otherwise. + * @throws NullPointerException if any of the children was <b>null</b>. + * @throws ClassCastException if any of the children was not a + * [EMAIL PROTECTED] Configuration} instance. + */ + public boolean addAll(Collection children) { + if (children == null) return(false); + Iterator iterator = children.iterator(); + while (iterator.hasNext()) this.check(iterator.next()); + return(super.addAll(children)); + } + + /** + * <p>Add the specified collection of [EMAIL PROTECTED] Configuration} instances as + * children of this instance at the specified offset.</p> + * + * @param index the offset where the children must be added. + * @param children the collection of children [EMAIL PROTECTED] Configuration} + * @return <b>true</b> if this list was modified, <b>false</b> otherwise. + * @throws NullPointerException if any of the children was <b>null</b>. + * @throws ClassCastException if any of the children was not a + * [EMAIL PROTECTED] Configuration} instance. + */ + public boolean addAll(int index, Collection children) { + if (children == null) return(false); + Iterator iterator = children.iterator(); + while (iterator.hasNext()) this.check(iterator.next()); + return(super.addAll(index, children)); + } + + /** + * <p>Returns an unlocked deep copy of this [EMAIL PROTECTED] Configuration} + * instance.</p> + * + * <p>The value and attribute names and values themselves are not cloned, + * but the entire structure of all nested [EMAIL PROTECTED] Configuration} and + * [EMAIL PROTECTED] Parameters} instances will be cloned.</p> + * + * <p>The returned instance will not be locked.</p> + * + * @return a new <b>non null</b> cloned [EMAIL PROTECTED] Configuration} instance. + */ + public Object clone() { + Configuration configuration = (Configuration) super.clone(); + configuration.locked = false; + + /* Clone attributes and children */ + configuration.clear(); + configuration.attributes = (Parameters)this.attributes.clone(); + Configuration array[] = new Configuration[this.size()]; + array = (Configuration [])this.toArray(array); + for (int x = 0; x < array.length; x ++) { + configuration.add(array[x].clone()); + } + return(configuration); + } + + + + /* ====================================================================== */ + + /** + * <p>Return an [EMAIL PROTECTED] Iterator} over all children of this + * [EMAIL PROTECTED] Configuration} with a specified name.</p> + * + * @param name the name of all returned configuration children. + * @return a <b>non null</b> [EMAIL PROTECTED] Iterator}. + */ + public Iterator children(String name) { + return(new ConfigurationIterator(this, null, name)); + } + + /** + * <p>Return an [EMAIL PROTECTED] Iterator} over all children of this + * [EMAIL PROTECTED] Configuration} with a specified name and namespace.</p> + * + * @param name the name of all returned configuration children. + * @param namespace the namespace of all returned configuration children. + * @return a <b>non null</b> [EMAIL PROTECTED] Iterator}. + */ + public Iterator children(String namespace, String name) { + return(new ConfigurationIterator(this, namespace, name)); + } + + /** + * <p>Return the first child [EMAIL PROTECTED] Configuration} instance with the + * specified name.</p> + * + * <p>If a child cannot be found an empty [EMAIL PROTECTED] Configuration} instance + * is returned. The returned [EMAIL PROTECTED] Configuration} will have an empty (and + * therefore illegal) name. To check if the element returned was the one + * requested, the suggested method is to proceed in the following way:</p> + * + * <pre> + * Configuration conf = configuration.child(name); + * if (!configuration.name().equals(name)) { + * // There is no child with this name. + * }</pre> + * + * <p>The empty [EMAIL PROTECTED] Configuration} element is returned to allow + * constructs such as:</p> + * + * <pre> + * Configuration conf = configuration.child(name).child(name2).child(namex); + * </pre> + * + * @param name the name of the returned configuration child. + * @return a <b>non null</b> [EMAIL PROTECTED] Configuration} element. + */ + public Configuration child(String name) { + Iterator iterator = this.children(name); + if (iterator.hasNext()) return((Configuration)iterator.next()); + Configuration child = new Configuration(); + child.location = this.location; + child.url = this.url; + return(child); + } + + /** + * <p>Return the first child [EMAIL PROTECTED] Configuration} instance with the + * specified namespace and name.</p> + * + * <p>If a child cannot be found an empty [EMAIL PROTECTED] Configuration} instance + * is returned. The returned [EMAIL PROTECTED] Configuration} will have an empty (and + * therefore illegal) name. To check if the element returned was the one + * requested, the suggested method is to proceed in the following way:</p> + * + * <pre> + * Configuration conf = configuration.child(namespace, name); + * if (!configuration.name().equals(name)) { + * // There is no child with this name. + * }</pre> + * + * <p>The empty [EMAIL PROTECTED] Configuration} element is returned to allow + * constructs such as:</p> + * + * <pre> + * Configuration conf = configuration.child(name).child(name2).child(namex); + * </pre> + * + * @param name the name of the returned configuration child. + * @param namespace the namespace of the returned configuration child. + * @return a <b>non null</b> [EMAIL PROTECTED] Iterator}. + */ + public Configuration child(String namespace, String name) { + Iterator iterator = this.children(namespace, name); + if (iterator.hasNext()) return((Configuration)iterator.next()); + Configuration child = new Configuration(); + child.location = this.location; + child.url = this.url; + return(child); + } + + /* ====================================================================== */ + + /** + * <p>Create and return a [EMAIL PROTECTED] String} describing the location of this + * [EMAIL PROTECTED] Configuration} element, if known.</p> + * + * <p>The returned string will assume the following format: + * <code>[EMAIL PROTECTED],column</code>.</p> + * + * @return a <b>non null</b> [EMAIL PROTECTED] String} describing the location. + */ + public String location() { + return(this.location); + } + + /** + * <p>Return (if possible) a URL absolutely locating this + * [EMAIL PROTECTED] Configuration} as a file or resource.</p> + * + * @return a [EMAIL PROTECTED] URL} instance or <b>null</b> if unknown. + */ + public URL locationURL() { + return(this.url); + } + + /** + * Specify the location details for this [EMAIL PROTECTED] Configuration} item. + * + * @param location the path or URL of the source file. + * @param line the line number in the source file. + * @param column the column number in the source file. + */ + public String locate(String location, int line, int column) { + try { + this.url = new URL(location); + } catch (MalformedURLException e) { + // Forget about this exception + } + + /* Prepare the location string now */ + String old = this.location; + this.location = location; + if (line < 0) return(old); + this.location += "@line=" + line; + if (column < 0) return(old); + this.location += ",column=" + column; + return(old); + } + + /* ====================================================================== */ + + /** + * <p>Return the value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @return the value of this configuration. + * @throws ConfigurationException if the value was not set. + */ + public Object getValue() + throws ConfigurationException { + if (this.value == null) + throw new ConfigurationException("Value not set", this); + return(this.value); + } + + /** + * <p>Return the value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @return the value of this configuration or the specified default. + */ + public Object getValue(Object defaultValue) { + return(this.value == null? defaultValue: value); + } + + /** + * <p>Set the value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @param value the value of this configuration element. + * @return the value of this configuration. + * @throws NullPointerException if the specified value was <b>null</b>. + */ + public Object setValue(Object value) { + if (value == null) throw new NullPointerException("Null value"); + Object old = this.value; + this.value = value; + return(old); + } + + /** + * <p>Set the boolean value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @param value the value of this configuration element. + * @return the previous value of this configuration. + */ + public Object setValue(boolean value) { + return this.setValue(new Boolean(value)); + } + + /** + * <p>Set the double value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @param value the value of this configuration element. + * @return the previous value of this configuration. + */ + public Object setValue(double value) { + return this.setValue(new Double(value)); + } + + /** + * <p>Set the float value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @param value the value of this configuration element. + * @return the previous value of this configuration. + */ + public Object setValue(float value) { + return this.setValue(new Float(value)); + } + + /** + * <p>Set the int value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @param value the value of this configuration element. + * @return the previous value of this configuration. + */ + public Object setValue(int value) { + return this.setValue(new Integer(value)); + } + + /** + * <p>Set the long value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @param value the value of this configuration element. + * @return the previous value of this configuration. + */ + public Object setValue(long value) { + return this.setValue(new Long(value)); + } + + /** + * <p>Remove the value of this [EMAIL PROTECTED] Configuration} element.</p> + * + * @return the value of this configuration or <b>null</b>. + */ + public Object removeValue() { + Object old = this.value; + this.value = null; + return(old); + } + + /* ====================================================================== */ + + /** + * <p>Return the boolean representation of this element value.</p> + * + * @return the boolean value of the element value. + * @throws ConfigurationException if the value was not found or could + * not be converted to a boolean. + */ + public boolean getBooleanValue() + throws ConfigurationException { + Object object = this.getValue(); + if (object instanceof Boolean) return(((Boolean)object).booleanValue()); + String string = object.toString(); + if ("0".equals(string)) return(false); + if ("1".equals(string)) return(true); + if ("false".equalsIgnoreCase(string)) return(false); + if ("true".equalsIgnoreCase(string)) return(true); + throw this.error("boolean", null); + } + + /** + * <p>Return the boolean representation of this element value.</p> + * + * @param defaultValue the default value to assign if the value was + * not found or could not be converted. + * @return the boolean value of the element value or the specified default. + */ + public boolean getBooleanValue(boolean defaultValue) { + try { + return(this.getBooleanValue()); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the integer representation of this element value.</p> + * + * @return the integer value of the element value. + * @throws ConfigurationException if the value was not found or could + * not be converted to an integer. + */ + public int getIntegerValue() + throws ConfigurationException { + Object object = this.getValue(); + if (object instanceof Number) return(((Number)object).intValue()); + try { + return(Integer.parseInt(object.toString())); + } catch (NumberFormatException e) { + throw this.error("int", e); + } + } + + /** + * <p>Return the integer representation of this element value.</p> + * + * @param defaultValue the default value to assign if the element value was + * not found or could not be converted. + * @return the integer value of the element value or the specified default. + */ + public int getIntegerValue(int defaultValue) { + try { + return(this.getIntegerValue()); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the long integer representation of this element value.</p> + * + * @throws ConfigurationException if the value was not found or could + * not be converted to a long integer. + */ + public long getLongValue() + throws ConfigurationException { + Object object = this.getValue(); + if (object instanceof Number) return(((Number)object).longValue()); + try { + return(Long.parseLong(object.toString())); + } catch (NumberFormatException e) { + throw this.error("long", e); + } + } + + /** + * <p>Return the long integer representation of this element value.</p> + * + * @param defaultValue the default value to assign if the element value was + * not found or could not be converted. + * @return the long integer value of the element value or the specified default. + */ + public long getLongValue(long defaultValue) { + try { + return(this.getLongValue()); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the float representation of this element value.</p> + * + * @return the float value of the value. + * @throws ConfigurationException if the value was not found or could + * not be converted to a float. + */ + public float getFloatValue() + throws ConfigurationException { + Object object = this.getValue(); + if (object instanceof Number) return(((Number)object).floatValue()); + try { + return(Float.parseFloat(object.toString())); + } catch (NumberFormatException e) { + throw this.error("float", e); + } + } + + /** + * <p>Return the float representation of this element value.</p> + * + * @param defaultValue the default value to assign if the element value was + * not found or could not be converted. + * @return the float value of the element value or the specified default. + */ + public float getFloatValue(float defaultValue) { + try { + return(this.getFloatValue()); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the double representation of this element value.</p> + * + * @return the double value of the value. + * @throws ConfigurationException if the value was not found or could + * not be converted to a double. + */ + public double getDoubleValue() + throws ConfigurationException { + Object object = this.getValue(); + if (object instanceof Number) return(((Number)object).doubleValue()); + try { + return(Double.parseDouble(object.toString())); + } catch (NumberFormatException e) { + throw this.error("double", e); + } + } + + /** + * <p>Return the double representation of this element value.</p> + * + * @param defaultValue the default value to assign if the element value was + * not found or could not be converted. + * @return the double value of the element value or the specified default. + */ + public double getDoubleValue(double defaultValue) { + try { + return(this.getDoubleValue()); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the [EMAIL PROTECTED] String} representation of this element value.</p> + * + * <p>The returned [EMAIL PROTECTED] String} will be created invoking the + * [EMAIL PROTECTED] Object#toString() toString()} method on the value instance.</p> + * + * @return the [EMAIL PROTECTED] String} value of the element value. + * @throws ConfigurationException if the value was not found. + */ + public String getStringValue() + throws ConfigurationException { + return(this.getValue().toString()); + } + + /** + * <p>Return the [EMAIL PROTECTED] String} representation of this element value.</p> + * + * <p>The returned [EMAIL PROTECTED] String} will be created invoking the + * [EMAIL PROTECTED] Object#toString() toString()} method on the value instance.</p> + * + * @param defaultValue the default value to assign if the element value was + * not found or could not be converted. + * @return the [EMAIL PROTECTED] String} value of the element value or the specified default. + */ + public String getStringValue(String defaultValue) { + try { + return(this.getStringValue()); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the value as a specific type.</p> + * + * @param type the [EMAIL PROTECTED] Class} type of the value to return. + * @return a <b>non null</b> object instance. + * @throws ConfigurationException if the attribute was not found or could + * not be converted to the specified type. + */ + public Object getValueAs(Class type) + throws ConfigurationException { + if (Boolean.class.equals(type)) { + return new Boolean(this.getBooleanValue()); + } else if (Double.class.equals(type)) { + return new Double(this.getDoubleValue()); + } else if (Float.class.equals(type)) { + return new Float(this.getFloatValue()); + } else if (Integer.class.equals(type)) { + return new Integer(this.getIntegerValue()); + } else if (Long.class.equals(type)) { + return new Long(this.getLongValue()); + } else if (String.class.equals(type)) { + return this.getStringValue(); + } + throw new ConfigurationException("Unsupported type " + type.getName()); + } + + /* ====================================================================== */ + + /** + * <p>Check if this configuration contains the specified attribute.</p> + * + * @param name the name of the attribute to check. + * @return <b>true</b> if the attribute was found, <b>false</b> otherwise. + */ + public boolean hasAttribute(String name) { + return(this.attributes.containsKey(name)); + } + + /* ====================================================================== */ + + /** + * <p>Return the attribute value.</p> + * + * @param name the name of the attribute to retrieve. + * @return the value of the attribute or <b>null</b> if the attribute was + * not found. + */ + public Object getAttribute(String name) { + return(this.attributes.get(name)); + } + + /** + * <p>Return the attribute value.</p> + * + * @param name the name of the attribute. + * @param defaultValue the default value to return. + * @return the value of the attribute or the specified default. + */ + public Object getAttribute(String name, Object defaultValue) { + return(this.attributes.get(name, defaultValue)); + } + + /* ====================================================================== */ + + /** + * <p>Return the boolean representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a boolean. + * @return the boolean value of the attribute. + * @throws ConfigurationException if the attribute was not found or could + * not be converted to a boolean. + */ + public boolean getBooleanAttribute(String name) + throws ConfigurationException { + try { + return(this.attributes.getBoolean(name)); + } catch (ConfigurationException e) { + throw new ConfigurationException("Attribute \"" + name + "\" " + + "invalid or not found", this); + } + } + + /** + * <p>Return the boolean representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a boolean. + * @param defaultValue the default value to assign if the attribute was + * not found or could not be converted. + * @return the boolean value of the attribute or the specified default. + */ + public boolean getBooleanAttribute(String name, boolean defaultValue) { + return(this.attributes.getBoolean(name, defaultValue)); + } + + /* ====================================================================== */ + + /** + * <p>Return the integer representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as an integer. + * @return the integer value of the attribute. + * @throws ConfigurationException if the attribute was not found or could + * not be converted to an integer. + */ + public int getIntegerAttribute(String name) + throws ConfigurationException { + try { + return(this.attributes.getInteger(name)); + } catch (ConfigurationException e) { + throw new ConfigurationException("Attribute \"" + name + "\" " + + "invalid or not found", this); + } + } + + /** + * <p>Return the integer representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a integer. + * @param defaultValue the default value to assign if the attribute was + * not found or could not be converted. + * @return the integer value of the attribute or the specified default. + */ + public int getIntegerAttribute(String name, int defaultValue) { + return(this.attributes.getInteger(name, defaultValue)); + } + + /* ====================================================================== */ + + /** + * <p>Return the long integer representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a long integer. + * @return the long integer value of the attribute. + * @throws ConfigurationException if the attribute was not found or could + * not be converted to a long integer. + */ + public long getLongAttribute(String name) + throws ConfigurationException { + try { + return(this.attributes.getLong(name)); + } catch (ConfigurationException e) { + throw new ConfigurationException("Attribute \"" + name + "\" " + + "invalid or not found", this); + } + } + + /** + * <p>Return the long integer representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a long integer. + * @param defaultValue the default value to assign if the attribute was + * not found or could not be converted. + * @return the long integer value of the attribute or the specified default. + */ + public long getLongAttribute(String name, long defaultValue) { + return(this.attributes.getLong(name, defaultValue)); + } + + /* ====================================================================== */ + + /** + * <p>Return the float representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a float. + * @return the float value of the attribute. + * @throws ConfigurationException if the attribute was not found or could + * not be converted to a float. + */ + public float getFloatAttribute(String name) + throws ConfigurationException { + try { + return(this.attributes.getFloat(name)); + } catch (ConfigurationException e) { + throw new ConfigurationException("Attribute \"" + name + "\" " + + "invalid or not found", this); + } + } + + /** + * <p>Return the float representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a float. + * @param defaultValue the default value to assign if the attribute was + * not found or could not be converted. + * @return the float value of the attribute or the specified default. + */ + public float getFloatAttribute(String name, float defaultValue) { + return(this.attributes.getFloat(name, defaultValue)); + } + + /* ====================================================================== */ + + /** + * <p>Return the double representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a double. + * @return the double value of the attribute. + * @throws ConfigurationException if the attribute was not found or could + * not be converted to a doube. + */ + public double getDoubleAttribute(String name) + throws ConfigurationException { + try { + return(this.attributes.getDouble(name)); + } catch (ConfigurationException e) { + throw new ConfigurationException("Attribute \"" + name + "\" " + + "invalid or not found", this); + } + } + + /** + * <p>Return the double representation of the specified attribute.</p> + * + * @param name the name of the attribute to retrieve as a double. + * @param defaultValue the default value to assign if the attribute was + * not found or could not be converted. + * @return the double value of the attribute or the specified default. + */ + public double getDoubleAttribute(String name, double defaultValue) { + return(this.attributes.getDouble(name, defaultValue)); + } + + /* ====================================================================== */ + + /** + * <p>Return the [EMAIL PROTECTED] String} representation of the specified attribute.</p> + * + * <p>The returned [EMAIL PROTECTED] String} will be created invoking the + * [EMAIL PROTECTED] Object#toString() toString()} method on the value instance.</p> + * + * @param name the name of the attribute to retrieve as a [EMAIL PROTECTED] String}. + * @return the [EMAIL PROTECTED] String} value of the attribute. + * @throws ConfigurationException if the attribute was not found. + */ + public String getStringAttribute(String name) + throws ConfigurationException { + try { + return(this.attributes.getString(name)); + } catch (ConfigurationException e) { + throw new ConfigurationException("Attribute \"" + name + "\" " + + "invalid or not found", this); + } + } + + /** + * <p>Return the [EMAIL PROTECTED] String} representation of the specified attribute.</p> + * + * <p>The returned [EMAIL PROTECTED] String} will be created invoking the + * [EMAIL PROTECTED] Object#toString() toString()} method on the value instance.</p> + * + * @param name the name of the attribute to retrieve as a [EMAIL PROTECTED] String}. + * @param defaultValue the default value to assign if the attribute was + * not found or could not be converted. + * @return the [EMAIL PROTECTED] String} value of the attribute or the specified default. + */ + public String getStringAttribute(String name, String defaultValue) { + return(this.attributes.getString(name, defaultValue)); + } + + /* ====================================================================== */ + + /** + * <p>Return the specified attribute value as a specific type.</p> + * + * @param name the name of the attribute to return. + * @param type the [EMAIL PROTECTED] Class} type of the value to return. + * @return a <b>non null</b> object instance. + * @throws ConfigurationException if the attribute was not found or could + * not be converted to the specified type. + */ + public Object getAttributeAs(String name, Class type) + throws ConfigurationException { + if (Boolean.class.equals(type)) { + return new Boolean(this.getBooleanAttribute(name)); + } else if (Double.class.equals(type)) { + return new Double(this.getDoubleAttribute(name)); + } else if (Float.class.equals(type)) { + return new Float(this.getFloatAttribute(name)); + } else if (Integer.class.equals(type)) { + return new Integer(this.getIntegerAttribute(name)); + } else if (Long.class.equals(type)) { + return new Long(this.getLongAttribute(name)); + } else if (String.class.equals(type)) { + return this.getStringAttribute(name); + } + throw new ConfigurationException("Unsupported type " + type.getName()); + } + + /* ====================================================================== */ + + /** + * <p>Return a human readable [EMAIL PROTECTED] String} representation of this + * [EMAIL PROTECTED] Configuration} instance.</p> + * + * @return a <b>non null</b> [EMAIL PROTECTED] String}. + */ + public String toString() { + String value = getClass().getName() + "[" + name() + "]@" + hashCode(); + return(value); + } + + /** + * <p>Return the hash code of this [EMAIL PROTECTED] Configuration} instance.</p> + * + * @return the hash code. + */ + public int hashCode() { + return(this.hash); + } + + /** + * <p>Compare an [EMAIL PROTECTED] Object} for equality.</p> + * + * @param o an [EMAIL PROTECTED] Object} to compare for equality. + * @return <b>true</b> if the object equals this, <b>false</b> otherwise. + */ + public boolean equals(Object o) { + /* Simple check */ + if (o == null) return (false); + if (o == this) return (true); + return(false); + } + + /* ====================================================================== */ + + /** + * <p>Simple method to check the value of a child.</p> + */ + private void check(Object child) { + if (child == null) throw new NullPointerException("Can't add null"); + if (child instanceof Configuration) return; + throw new ClassCastException("Unable to add non Configuration child"); + } + + /** + * <p>Simple method to throw a nicely formatted exception.</p> + */ + private ConfigurationException error(String type, Throwable throwable) { + return new ConfigurationException("Value \""+ this.getStringValue("?") + + "\" can "+ "not be converted to a " + + type, this, throwable); + } + + /** + * <p>A simple iterator over children configurations.</p> + */ + private static class ConfigurationIterator implements Iterator { + /** <p>The next configuration element.</p> */ + private Configuration configuration = null; + + /** <p>The sub-iterator from where to fetch elements.</p> */ + private Iterator iterator = null; + + /** <p>The namespace of the [EMAIL PROTECTED] Configuration}s to return.</p> */ + private String namespace = null; + + /** <p>The name of the [EMAIL PROTECTED] Configuration}s to return.</p> */ + private String name = null; + + /** + * <p>Create a new [EMAIL PROTECTED] ConfigurationIterator} returning a selected + * part of the children of a specified [EMAIL PROTECTED] Configuration}.</p> + * + * @param c the [EMAIL PROTECTED] Configuration} to iterate for children. + * @param ns the namespace of the [EMAIL PROTECTED] Configuration}s to return. + * @param n the name of the [EMAIL PROTECTED] Configuration}s to return. + */ + private ConfigurationIterator(Configuration c, String ns, String n) { + this.iterator = c.iterator(); + this.namespace = ns; + this.name = n; + } + + /** + * <p>Check if this [EMAIL PROTECTED] Iterator} can return the next element.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> + * @version 1.0 (CVS $Revision: 1.4 $) + */ + public boolean hasNext() { + /* No name, no children. Bye! */ + if (this.name == null) return(false); + + /* Run on the nested iterator */ + while(this.iterator.hasNext()) { + + /* Return the next child configuration, whatever it is */ + Configuration child = (Configuration)iterator.next(); + + /* If we process namespaces check both name and namespace */ + if (this.namespace != null) { + if ((!this.namespace.equals(child.namespace())) + || (!this.name.equals(child.name()))) continue; + + /* If we process only names, check only the name */ + } else if (!this.name.equals(child.name())) continue; + + /* If we didn't "continue" before, we have a match */ + this.configuration = child; + return(true); + } + /* The nested iterator doesn't have any more children */ + return(false); + } + + /** + * <p>Return the next [EMAIL PROTECTED] Configuration} element available to this + * [EMAIL PROTECTED] ConfigurationIterator}.</p> + */ + public Object next() { + /* If the "hasNext()" method didn't produce anything, try it */ + if ((this.configuration == null) && (!this.hasNext())) { + throw new NoSuchElementException("Next element not found"); + } + + /* Return and invalidate the "next" object */ + Configuration current = this.configuration; + this.configuration = null; + return(current); + } + + /** + * <p>Block anyone attempting to remove only children.</p> + */ + public void remove() { + throw new UnsupportedOperationException("Use a normal iterator"); + } + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationBuilder.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationBuilder.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,271 @@ +/* =============================================================================== * + * 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.configuration; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * <p>The [EMAIL PROTECTED] ConfigurationBuilder} builds [EMAIL PROTECTED] Configuration} instances + * from XML data.</p> + * + * <p>This class can be instantiated and used directly as a SAX + * [EMAIL PROTECTED] DefaultHandler} to use with any SAX-2 compliant parser.</p> + * + * <p>Otherwise a simple static [EMAIL PROTECTED] #parse(InputSource)} method is provided + * using the default JAXP implementation of the platform to parse XML documents + * and producing [EMAIL PROTECTED] Configuration} instances.</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 ConfigurationBuilder extends DefaultHandler { + + /** <p>The returnable [EMAIL PROTECTED] Configuration} element.</p> */ + private Configuration configuration = null; + + /** <p>The current [EMAIL PROTECTED] Configuration} element.</p> */ + private Configuration current = null; + + /** <p>The stack of [EMAIL PROTECTED] Configuration} elements.</p> */ + private List stack = new ArrayList(); + + /** <p>The buffer holding element values.</p> */ + private StringBuffer buffer = null; + + /** <p>The current [EMAIL PROTECTED] Locator}.</p> */ + private Locator locator = null; + + /** + * <p>Create a new [EMAIL PROTECTED] ConfigurationBuilder} instance.</p> + */ + public ConfigurationBuilder() { + super(); + } + + /** + * <p>Return the parsed [EMAIL PROTECTED] Configuration} instance.</p> + * + * @return the parsed [EMAIL PROTECTED] Configuration} or <b>null</b>. + */ + public Configuration configuration() { + return(this.configuration); + } + + /** + * <p>Receive a [EMAIL PROTECTED] Locator} object to locate the different document + * events.</p> + * + * @param locator a <b>non null</b> [EMAIL PROTECTED] Locator} instance. + */ + public void setDocumentLocator (Locator locator) { + this.locator = locator; + } + + /** + * <p>Receive notification of the beginning of the document.</p> + * + * <p>This method will effectively reset the [EMAIL PROTECTED] Configuration} item + * being parsed.</p> + */ + public void startDocument () + throws SAXException { + this.current = null; + } + + /** + * <p>Receive notification of the end of the document.</p> + * + * <p>This method will effectively mark the [EMAIL PROTECTED] Configuration} item + * being parsed as returnable by the [EMAIL PROTECTED] #configuration()} method.</p> + */ + public void endDocument () + throws SAXException { + this.configuration = this.current; + } + + /** + * <p>Receive notification of the start of an element.</p> + * + * @param uri the namespace URI of the element. + * @param local the local name of the element. + * @param qualified the fully qualified name of the element. + * @param attributes all the XML attributes of the element. + */ + public void startElement(String uri, String local, String qualified, + Attributes attributes) + throws SAXException { + /* Convert the attributes into parameters */ + Parameters parameters = new Parameters(); + for (int x = 0; x < attributes.getLength(); x++) { + String name = attributes.getLocalName(x); + parameters.put(name, attributes.getValue(x)); + } + /* Create the new configuration element */ + Configuration element = new Configuration(uri, local, parameters); + if (this.locator != null) element.locate(locator.getSystemId(), + locator.getLineNumber(), + locator.getColumnNumber()); + + /* If no root element has been found yet, add it */ + if (this.current == null) this.current = element; + this.stack.add(element); + } + + /** + * <p>Receive notification of the end of an element.</p> + * + * @param uri the namespace URI of the element. + * @param local the local name of the element. + * @param qualified the fully qualified name of the element. + */ + public void endElement(String uri, String local, String qualified) + throws SAXException { + /* Process the value of the element */ + Configuration element = (Configuration) stack.remove(stack.size() - 1); + if (this.buffer != null) { + element.setValue(this.buffer.toString()); + this.buffer = null; + } + + /* If this is not the root element, add it to the parent element */ + if (stack.size() > 0) { + Configuration parent = (Configuration) stack.get(stack.size() - 1); + parent.add(element); + } + } + + /** + * <p>Receive notification of some character data.</p> + * + * @param characters an array of characters. + * @param start the index where relevant characters start from in the array. + * @param length the number of relevant characters in the array. + */ + public void characters(char characters[], int start, int length) + throws SAXException { + /* Append valid characters to the buffer (collapse spaces) */ + String value = new String(characters, start, length); + StringTokenizer tokenizer = new StringTokenizer(value); + while (tokenizer.hasMoreTokens()) { + value = tokenizer.nextToken().trim(); + if (value.length() == 0) continue; + if (this.buffer == null) { + this.buffer = new StringBuffer(value); + } else { + if (this.buffer.length() > 0) this.buffer.append(' '); + this.buffer.append(value); + } + } + } + + /** + * <p>Parse an XML file returning a [EMAIL PROTECTED] Configuration} instance.</p> + * + * @param document the XML document to parse. + * @throws IOException if an I/O error occurred parsing the document. + * @throws ConfigurationException if the XML file could not be parsed or + * represented as a [EMAIL PROTECTED] Configuration}. + */ + public static Configuration parse(File document) + throws ConfigurationException, IOException { + if (document == null) throw new NullPointerException("Null document"); + return(ConfigurationBuilder.parse(document.toURL())); + } + + /** + * <p>Parse an XML file returning a [EMAIL PROTECTED] Configuration} instance.</p> + * + * @param document the XML document to parse. + * @throws IOException if an I/O error occurred parsing the document. + * @throws ConfigurationException if the XML file could not be parsed or + * represented as a [EMAIL PROTECTED] Configuration}. + */ + public static Configuration parse(URL document) + throws ConfigurationException, IOException { + if (document == null) throw new NullPointerException("Null document"); + return(ConfigurationBuilder.parse(document.toString())); + } + + /** + * <p>Parse an XML file returning a [EMAIL PROTECTED] Configuration} instance.</p> + * + * @param document the XML document to parse. + * @throws IOException if an I/O error occurred parsing the document. + * @throws ConfigurationException if the XML file could not be parsed or + * represented as a [EMAIL PROTECTED] Configuration}. + */ + public static Configuration parse(String document) + throws ConfigurationException, IOException { + if (document == null) throw new NullPointerException("Null document"); + return(ConfigurationBuilder.parse(new InputSource(document))); + } + + /** + * <p>Parse an XML file returning a [EMAIL PROTECTED] Configuration} instance.</p> + * + * @param document the XML document to parse. + * @throws IOException if an I/O error occurred parsing the document. + * @throws ConfigurationException if the XML file could not be parsed or + * represented as a [EMAIL PROTECTED] Configuration}. + */ + public static Configuration parse(InputSource document) + throws ConfigurationException, IOException { + /* Check our InputSource */ + if (document == null) throw new NullPointerException("Null document"); + + /* Instantiate a non-validating namespace aware SAXParserFactory */ + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setValidating(false); + try { + /* Try to do some parsing */ + ConfigurationBuilder builder = new ConfigurationBuilder(); + SAXParser parser = factory.newSAXParser(); + parser.parse(document, builder); + return(builder.configuration()); + } catch(ParserConfigurationException e) { + throw new ConfigurationException("Unable to configure parser", e); + } catch(SAXParseException e) { + throw new ConfigurationException("Error parsing configurations " + + "from \"" + e.getSystemId() + + "\" line " + e.getLineNumber() + + " column "+ e.getColumnNumber() + + ": " + e.getMessage(), e); + } catch(SAXException e) { + Exception x = e.getException(); + if ((x != null) && (x instanceof ConfigurationException)) { + throw((ConfigurationException)x); + } + throw new ConfigurationException("Can't parse configurations from " + + "\"" + document.getSystemId() + + "\": " + e.getMessage(), e); + } + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationException.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationException.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,110 @@ +/* =============================================================================== * + * 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.configuration; + +/** + * <p>An exception identifying an error in a configuration operation.</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 ConfigurationException extends Exception { + + /** <p>The associated [EMAIL PROTECTED] Configuration} element.</p> */ + private Configuration configuration = null; + + /** + * <p>Create a new [EMAIL PROTECTED] ConfigurationException} instance.</p> + */ + public ConfigurationException() { + super(); + } + + /** + * <p>Create a new [EMAIL PROTECTED] ConfigurationException} instance with a + * specified detail message.</p> + * + * @param message the detail message of this exception. + */ + public ConfigurationException(String message) { + super(message); + } + + /** + * <p>Create a new [EMAIL PROTECTED] ConfigurationException} instance with a + * specified detail message and a related [EMAIL PROTECTED] Configuration}.</p> + * + * @param message the detail message of this exception. + * @param configuration the related configuration element. + */ + public ConfigurationException(String message, Configuration configuration) { + super(message + (configuration == null ? "" : + " [" + configuration.location() + "]")); + } + + /** + * <p>Create a new [EMAIL PROTECTED] ConfigurationException} instance with a + * specified detail message and cause.</p> + * + * @param message the detail message of this exception. + * @param cause the cause of this exception. + */ + public ConfigurationException(String message, Throwable cause) { + super(message, cause); + } + + /** + * <p>Create a new [EMAIL PROTECTED] ConfigurationException} instance with a + * specified detail message and cause.</p> + * + * @param message the detail message of this exception. + * @param configuration the related configuration element. + * @param cause the cause of this exception. + */ + public ConfigurationException(String message, Configuration configuration, + Throwable cause) { + super(message + (configuration == null ? "" : + " [" + configuration.location() + "]"), cause); + } + + /** + * <p>Create a new [EMAIL PROTECTED] ConfigurationException} instance with a + * specified cause.</p> + * + * @param cause the cause of this exception. + */ + public ConfigurationException(Throwable cause) { + super((cause == null ? null : cause.toString()), cause); + } + + /** + * <p>Return the associated [EMAIL PROTECTED] Configuration} element.</p> + * + * @return a [EMAIL PROTECTED] Configuration} element or <b>null</b>. + */ + public Configuration getConfiguration() { + return(this.configuration); + } + + /** + * <p>Return the associated [EMAIL PROTECTED] Configuration} location if known.</p> + * + * @see Configuration#location() + * @return a <b>non null</b> location [EMAIL PROTECTED] String}. + */ + public String getLocation() { + if (this.configuration != null) return(configuration.location()); + return("[EMAIL PROTECTED],-1"); + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationSerializer.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/ConfigurationSerializer.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,184 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * 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.configuration; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; + +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamResult; + +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +/** + * <p>The [EMAIL PROTECTED] ConfigurationSerializer} serializes [EMAIL PROTECTED] Configuration} + * instances as XML data.</p> + * + * <p>A simple static [EMAIL PROTECTED] #serialize(Configuration,ContentHandler)} method + * is provided for direct SAX-2 integration, otherwise the + * [EMAIL PROTECTED] #serialize(Configuration,OutputStream)} method will use the default + * JAXP implementation of the platform to serialize XML documents to + * [EMAIL PROTECTED] OutputStream} instances.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> + * @version 1.0 (CVS $Revision: 1.5 $) + */ +public class ConfigurationSerializer { + + /** <p>The character array used for indenting.</p> */ + private static final char indent[] = " ".toCharArray(); + + /** <p>The character array used for newlines.</p> */ + private static final char newline [] = + System.getProperty("line.separator").toCharArray(); + + /** <p>Deny creation of [EMAIL PROTECTED] ConfigurationSerializer} instances.</p> */ + public ConfigurationSerializer() { + super(); + } + + /** + * <p>Serialize a [EMAIL PROTECTED] Configuration} instance as an XML document to + * the specified [EMAIL PROTECTED] OutputStream}.</p> + * + * @param configuration the [EMAIL PROTECTED] Configuration} instance to serialize. + * @param out the [EMAIL PROTECTED] OutputStream} where XML will be written to. + * @throws SAXException if there was a problem generating XML data. + * @throws ConfigurationException if there was a problem generating XML data. + */ + public static void serialize(Configuration configuration, OutputStream out) + throws SAXException, ConfigurationException, IOException { + try { + SAXTransformerFactory fact = null; + fact = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); + TransformerHandler hdlr = fact.newTransformerHandler(); + hdlr.setResult(new StreamResult(out)); + serialize(configuration, hdlr); + } catch (TransformerFactoryConfigurationError e) { + throw new SAXException("JAXP transformer factory unavailable"); + } catch (TransformerConfigurationException e) { + throw new SAXException("JAXP transformer unavailable", e); + } catch (SAXException e) { + Exception x = e.getException(); + if ((x != null) && (x instanceof IOException)) { + throw ((IOException) x); + } + throw (e); + } + } + + /** + * <p>Serialize a [EMAIL PROTECTED] Configuration} instance to a specified + * SAX-2 [EMAIL PROTECTED] ContentHandler}.</p> + * + * @param configuration the [EMAIL PROTECTED] Configuration} instance to serialize. + * @param h the [EMAIL PROTECTED] ContentHandler} where events will be sent to. + * @throws SAXException if there was a problem generating XML data. + * @throws ConfigurationException if there was a problem generating XML data. + */ + public static void serialize(Configuration configuration, ContentHandler h) + throws SAXException, ConfigurationException { + h.startDocument(); + element(configuration, h, 0, null); + h.endDocument(); + } + + /** + * <p>Simple method to recursively serialize a [EMAIL PROTECTED] Configuration} + * element and all its children.</p> + * + * @param configuration the [EMAIL PROTECTED] Configuration} instance to serialize. + * @param h the [EMAIL PROTECTED] ContentHandler} where events will be sent to. + * @param indent the indenting level. + * @param namespace the currently declared namespace. + * @throws SAXException if there was a problem generating XML data. + * @throws ConfigurationException if there was a problem converting. + */ + private static void element(Configuration configuration, ContentHandler h, + int indent, String namespace) + throws SAXException, ConfigurationException { + /* Create and fill attributes from configuration properties */ + AttributesImpl attr = new AttributesImpl(); + Iterator iterator = configuration.attributes().keySet().iterator(); + while (iterator.hasNext()) { + String name = (String) iterator.next(); + attr.addAttribute("", name, name, "CDATA", + configuration.getStringAttribute(name)); + } + + /* Check for namespace declarations */ + boolean namespacedeclared = false; + if (namespace == null) { + if (configuration.namespace() != null) { + h.startPrefixMapping("", configuration.namespace()); + attr.addAttribute("", "xmlns", "xmlns", "CDATA", + configuration.namespace()); + namespacedeclared = true; + } + } else if (!namespace.equals(configuration.namespace())) { + String local = configuration.namespace(); + if (local == null) local = ""; + h.startPrefixMapping("", (local == null? "": local)); + attr.addAttribute("", "xmlns", "xmlns", "CDATA", + (local == null? "": local)); + namespacedeclared = true; + } + + /* Notify the content handler of an element start */ + indent(h, indent); + h.startElement("", configuration.name(), configuration.name(), attr); + + /* Dump the value if and only if we have it */ + char value[] = configuration.getStringValue("").toCharArray(); + if (value.length > 0) { + if (configuration.size() > 0) indent(h, (indent + 1)); + h.characters(value, 0, value.length); + } + + /* Recurse into our children processing them */ + iterator = configuration.iterator(); + while (iterator.hasNext()) { + Configuration current = (Configuration) iterator.next(); + element(current, h, (indent + 1), configuration.namespace()); + } + + /* Indent (if there was output) and put the end name */ + if (configuration.size() > 0) indent(h, indent); + h.endElement("", configuration.name(), configuration.name()); + + /* If we declared the namespace, undeclare it */ + if (namespacedeclared) h.endPrefixMapping(""); + } + + /** + * <p>Simple method to indent text in a [EMAIL PROTECTED] ContentHandler}.</p> + * + * @param h the [EMAIL PROTECTED] ContentHandler} where events will be sent to. + * @param n the indenting level. + * @throws SAXException if there was a problem generating XML data. + */ + private static void indent(ContentHandler h, int n) + throws SAXException { + h.characters(newline, 0, newline.length); + for (int x = 0; x < n; x ++) h.characters(indent, 0, indent.length); + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/Parameters.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/configuration/Parameters.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,590 @@ +/* =============================================================================== * + * 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.configuration; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +/** + * <p>The [EMAIL PROTECTED] Parameters} class defines a simple [EMAIL PROTECTED] Map} that can + * be used to configure components.</p> + * + * <p>A [EMAIL PROTECTED] Parameters} map differs from a regular [EMAIL PROTECTED] HashMap} in the + * sense that no <b>null</b> keys or values are accepted, and that keys can + * only be [EMAIL PROTECTED] String} instances.</p> + * + * <p>This class also provides simple methods for resolving values to some + * of the Java™ primitive types: boolean, int, long, float, double and + * [EMAIL PROTECTED] String}.</p> + * + * <p>Validation of [EMAIL PROTECTED] Parameters} instances can be performed using the + * [EMAIL PROTECTED] Parameters} 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 Parameters extends HashMap implements Map { + + /** <p>Whether this instance is locked or not.</p> */ + private boolean locked = false; + + /** + * <p>Create a new empty [EMAIL PROTECTED] Parameters} instance.</p> + */ + public Parameters() { + super(); + } + + /** + * <p>Create a new [EMAIL PROTECTED] Parameters} instance parsing all elements of a + * [EMAIL PROTECTED] Configuration} instance.</p> + * + * <p>Elements of the configuration that will be parsed must look like + * this:</p> + * + * <p><nobr><code><parameter + * name="<b>name</b>" + * value="<b>value</b>" + * <i>type="<b>type identifier</b>"</i>/></code></nobr></p> + * + * @throws ConfigurationException if the instance cannot be created. + */ + public Parameters(Configuration configuration) + throws ConfigurationException { + super(); + Iterator iterator = configuration.children("parameter"); + while (iterator.hasNext()) try { + Configuration c = (Configuration)iterator.next(); + String n = c.getStringAttribute("name"); + String t = c.getStringAttribute("type", "string"); + if ("string".equalsIgnoreCase(t)) { + this.put(n, c.getStringValue(c.getStringAttribute("value"))); + } else if ("boolean".equalsIgnoreCase(t)) { + this.put(n, c.getBooleanValue(c.getBooleanAttribute("value"))); + } else if ("double".equalsIgnoreCase(t)) { + this.put(n, c.getDoubleValue(c.getDoubleAttribute("value"))); + } else if ("float".equalsIgnoreCase(t)) { + this.put(n, c.getFloatValue(c.getFloatAttribute("value"))); + } else if ("integer".equalsIgnoreCase(t)) { + this.put(n, c.getIntegerValue(c.getIntegerAttribute("value"))); + } else if ("long".equalsIgnoreCase(t)) { + this.put(n, c.getLongValue(c.getLongAttribute("value"))); + } else if ("configuration".equalsIgnoreCase(t)) { + Configuration k = new Configuration(n); + k.addAll(c); + this.put(n, k); + } else { + this.put(n, c.getValue(c.getAttribute("value"))); + } + } catch (ConfigurationException e) { + throw new ConfigurationException(e.getMessage(), configuration, e); + } + } + + /** + * <p>Lock this [EMAIL PROTECTED] Parameters} instance.</p> + * + * <p>After this method is called, no further modifications are allowed + * into this [EMAIL PROTECTED] Parameters} instance, and any call to the + * [EMAIL PROTECTED] #put(Object,Object)} or [EMAIL PROTECTED] #remove(Object)} methods will + * throw an [EMAIL PROTECTED] UnsupportedOperationException}.</p> + * + * @return this [EMAIL PROTECTED] Parameters} instance. + */ + public Parameters lock() { + this.locked = true; + return(this); + } + + /* ====================================================================== */ + + /** + * <p>Return the parameter value.</p> + * + * @param name the name of the parameter to retrieve. + * @return the value of the parameter or <b>null</b> if the parameter was + * not found. + */ + public Object get(Object name) { + if (name == null) return(null); + return(super.get(name)); + } + + /** + * <p>Return the parameter value.</p> + * + * @param name the name of the parameter. + * @param defaultValue the default value to return. + * @return the value of the parameter or the specified default. + */ + public Object get(Object name, Object defaultValue) { + Object value = this.get(name); + return(value == null? defaultValue: value); + } + + /** + * <p>Put a new parameter in this [EMAIL PROTECTED] Parameters} map.</p> + * + * @param name the name of the parameter. + * @param value the value of the parameter. + * @throws NullPointerException if either name or value are <b>null</b>. + * @throws ClassCastException if the name is not a [EMAIL PROTECTED] String}. + * @throws UnsupportedOperationException if this instance is locked. + */ + public Object put(Object name, Object value) { + if (this.locked) throw new UnsupportedOperationException("Locked"); + if (name == null) throw new NullPointerException("Null name"); + if (value == null) throw new NullPointerException("Null value"); + if (name instanceof String) return(super.put(name, value)); + throw new ClassCastException("Invalid parameter name"); + } + + /** + * <p>Put a new boolean parameter in this [EMAIL PROTECTED] Parameters} map.</p> + * + * @param name the name of the parameter. + * @param value the value of the parameter. + * @throws NullPointerException if the name was <b>null</b>. + * @throws UnsupportedOperationException if this instance is locked. + */ + public Object put(Object name, boolean value) { + return this.put(name, new Boolean(value)); + } + + /** + * <p>Put a new double parameter in this [EMAIL PROTECTED] Parameters} map.</p> + * + * @param name the name of the parameter. + * @param value the value of the parameter. + * @throws NullPointerException if the name was <b>null</b>. + * @throws UnsupportedOperationException if this instance is locked. + */ + public Object put(Object name, double value) { + return this.put(name, new Double(value)); + } + + /** + * <p>Put a new float parameter in this [EMAIL PROTECTED] Parameters} map.</p> + * + * @param name the name of the parameter. + * @param value the value of the parameter. + * @throws NullPointerException if the name was <b>null</b>. + * @throws UnsupportedOperationException if this instance is locked. + */ + public Object put(Object name, float value) { + return this.put(name, new Float(value)); + } + + /** + * <p>Put a new int parameter in this [EMAIL PROTECTED] Parameters} map.</p> + * + * @param name the name of the parameter. + * @param value the value of the parameter. + * @throws NullPointerException if the name was <b>null</b>. + * @throws UnsupportedOperationException if this instance is locked. + */ + public Object put(Object name, int value) { + return this.put(name, new Integer(value)); + } + + /** + * <p>Put a new long parameter in this [EMAIL PROTECTED] Parameters} map.</p> + * + * @param name the name of the parameter. + * @param value the value of the parameter. + * @throws NullPointerException if the name was <b>null</b>. + * @throws UnsupportedOperationException if this instance is locked. + */ + public Object put(Object name, long value) { + return this.put(name, new Long(value)); + } + + /** + * <p>Remove a parameter in this [EMAIL PROTECTED] Parameters} map.</p> + * + * @param name the name of the parameter. + * @return the value of the parameter or <b>null</b> if the parameter was + * not found. + */ + public Object remove(Object name) { + if (name == null) return(null); + return(super.remove(name)); + } + + /** + * <p>Returns an unlocked shallow copy of this [EMAIL PROTECTED] Parameters} + * instance.</p> + * + * <p>The parameter names and values themselves are not cloned, and + * the returned instance will not be locked.</p> + * + * @return a new <b>non null</b> cloned [EMAIL PROTECTED] Parameters} instance. + */ + public Object clone() { + Parameters parameters = (Parameters) super.clone(); + parameters.locked = false; + return(parameters); + } + + /* ====================================================================== */ + + /** + * <p>Return the boolean representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a boolean. + * @return the boolean value of the parameter. + * @throws ConfigurationException if the parameter was not found or could + * not be converted to a boolean. + */ + public boolean getBoolean(String name) + throws ConfigurationException { + Object object = this.check(name); + if (object instanceof Boolean) return(((Boolean)object).booleanValue()); + String string = object.toString(); + if ("0".equals(string)) return(false); + if ("1".equals(string)) return(true); + if ("false".equalsIgnoreCase(string)) return(false); + if ("true".equalsIgnoreCase(string)) return(true); + throw this.error(name, "boolean", null); + } + + /** + * <p>Return the boolean representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a boolean. + * @param defaultValue the default value to assign if the parameter was + * not found or could not be converted. + * @return the boolean value of the parameter or the specified default. + */ + public boolean getBoolean(String name, boolean defaultValue) { + try { + return(this.getBoolean(name)); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the integer representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as an integer. + * @return the integer value of the parameter. + * @throws ConfigurationException if the parameter was not found or could + * not be converted to an integer. + */ + public int getInteger(String name) + throws ConfigurationException { + Object object = this.check(name); + if (object instanceof Number) return(((Number)object).intValue()); + try { + return(Integer.parseInt(object.toString())); + } catch (NumberFormatException e) { + throw this.error(name, "int", e); + } + } + + /** + * <p>Return the integer representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a integer. + * @param defaultValue the default value to assign if the parameter was + * not found or could not be converted. + * @return the integer value of the parameter or the specified default. + */ + public int getInteger(String name, int defaultValue) { + try { + return(this.getInteger(name)); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the long integer representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a long integer. + * @return the long integer value of the parameter. + * @throws ConfigurationException if the parameter was not found or could + * not be converted to a long integer. + */ + public long getLong(String name) + throws ConfigurationException { + Object object = this.check(name); + if (object instanceof Number) return(((Number)object).longValue()); + try { + return(Long.parseLong(object.toString())); + } catch (NumberFormatException e) { + throw this.error(name, "long", e); + } + } + + /** + * <p>Return the long integer representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a long integer. + * @param defaultValue the default value to assign if the parameter was + * not found or could not be converted. + * @return the long integer value of the parameter or the specified default. + */ + public long getLong(String name, long defaultValue) { + try { + return(this.getLong(name)); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the float representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a float. + * @return the float value of the parameter. + * @throws ConfigurationException if the parameter was not found or could + * not be converted to a float. + */ + public float getFloat(String name) + throws ConfigurationException { + Object object = this.check(name); + if (object instanceof Number) return(((Number)object).floatValue()); + try { + return(Float.parseFloat(object.toString())); + } catch (NumberFormatException e) { + throw this.error(name, "float", e); + } + } + + /** + * <p>Return the float representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a float. + * @param defaultValue the default value to assign if the parameter was + * not found or could not be converted. + * @return the float value of the parameter or the specified default. + */ + public float getFloat(String name, float defaultValue) { + try { + return(this.getFloat(name)); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the double representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a double. + * @return the double value of the parameter. + * @throws ConfigurationException if the parameter was not found or could + * not be converted to a doube. + */ + public double getDouble(String name) + throws ConfigurationException { + Object object = this.check(name); + if (object instanceof Number) return(((Number)object).doubleValue()); + try { + return(Double.parseDouble(object.toString())); + } catch (NumberFormatException e) { + throw this.error(name, "double", e); + } + } + + /** + * <p>Return the double representation of the specified parameter.</p> + * + * @param name the name of the parameter to retrieve as a double. + * @param defaultValue the default value to assign if the parameter was + * not found or could not be converted. + * @return the double value of the parameter or the specified default. + */ + public double getDouble(String name, double defaultValue) { + try { + return(this.getDouble(name)); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the [EMAIL PROTECTED] String} representation of the specified parameter.</p> + * + * <p>The returned [EMAIL PROTECTED] String} will be created invoking the + * [EMAIL PROTECTED] Object#toString() toString()} method on the value instance.</p> + * + * @param name the name of the parameter to retrieve as a [EMAIL PROTECTED] String}. + * @return the [EMAIL PROTECTED] String} value of the parameter. + * @throws ConfigurationException if the parameter was not found. + */ + public String getString(String name) + throws ConfigurationException { + return(this.check(name).toString()); + } + + /** + * <p>Return the [EMAIL PROTECTED] String} representation of the specified parameter.</p> + * + * <p>The returned [EMAIL PROTECTED] String} will be created invoking the + * [EMAIL PROTECTED] Object#toString() toString()} method on the value instance.</p> + * + * @param name the name of the parameter to retrieve as a [EMAIL PROTECTED] String}. + * @param defaultValue the default value to assign if the parameter was + * not found or could not be converted. + * @return the [EMAIL PROTECTED] String} value of the parameter or the specified default. + */ + public String getString(String name, String defaultValue) { + try { + return(this.getString(name)); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Return the [EMAIL PROTECTED] Configuration} (complex) value of the specified + * parameter.</p> + * + * <p>The parameter value <b>must</b> be stored as a [EMAIL PROTECTED] Configuration} + * object in this instance, otherwise this method will fail.</p> + * + * @param name the name of the [EMAIL PROTECTED] Configuration} parameter to retrieve. + * @return the [EMAIL PROTECTED] Configuration} value of the parameter. + * @throws ConfigurationException if the parameter was not found or its + * value was not a [EMAIL PROTECTED] Configuration}. + */ + public Configuration getConfiguration(String name) + throws ConfigurationException { + try { + return((Configuration)this.check(name)); + } catch (ClassCastException e) { + throw this.error(name, "configuration", e); + } + } + + /** + * <p>Return the [EMAIL PROTECTED] Configuration} (complex) value of the specified + * parameter.</p> + * + * <p>The parameter value <b>must</b> be stored as a [EMAIL PROTECTED] Configuration} + * object in this instance, otherwise this method will return the default + * value.</p> + * + * @param name the name of the [EMAIL PROTECTED] Configuration} parameter to retrieve. + * @param defaultValue the default value to assign if the parameter was + * not found or was not a [EMAIL PROTECTED] Configuration}. + * @return the [EMAIL PROTECTED] Configuration} value of the parameter. + * @throws ConfigurationException if the parameter was not found or its + * value was not a [EMAIL PROTECTED] Configuration}. + */ + public Configuration getConfiguration(String name, + Configuration defaultValue) { + try { + return(this.getConfiguration(name)); + } catch(ConfigurationException e) { + return(defaultValue); + } + } + + /* ====================================================================== */ + + /** + * <p>Convert this [EMAIL PROTECTED] Parameters} instance into [EMAIL PROTECTED] Properties}.</p> + * + * @return a <b>non null</b> [EMAIL PROTECTED] Properties} instance with all parameters + * it was possible to convert into properties. + */ + public Properties toProperties() { + Properties properties = new Properties(); + Iterator iterator = this.keySet().iterator(); + while (iterator.hasNext()) { + String name = (String)iterator.next(); + String value = this.getString(name, null); + if (value != null) properties.put(name, value); + } + return(properties); + } + + /* ====================================================================== */ + + /** + * <p>Verify that the specified parameter is of the specified type.</p> + * + * @param name the parameter name. + * @param type the parameter type. + * @return <b>true</b> if the parameter exists and is of the specified + * type, <b>false</b> otherwise. + * @throws UnsupportedOperationException if type was unrecognized. + */ + public boolean verify(String name, String type) { + try { + if ("string".equalsIgnoreCase(type)) { + this.getString(name); + } else if ("boolean".equalsIgnoreCase(type)) { + this.getBoolean(name); + } else if ("double".equalsIgnoreCase(type)) { + this.getDouble(name); + } else if ("float".equalsIgnoreCase(type)) { + this.getFloat(name); + } else if ("integer".equalsIgnoreCase(type)) { + this.getInteger(name); + } else if ("long".equalsIgnoreCase(type)) { + this.getLong(name); + } else if ("configuration".equalsIgnoreCase(type)) { + this.getConfiguration(name); + } else { + throw new UnsupportedOperationException("Unknown type " + type); + } + /* We got here without exceptions, then all is fine */ + return(true); + } catch (ConfigurationException e) { + /* Configuration exception? no value or can't convert */ + return(false); + } + } + + /* ====================================================================== */ + + /** + * <p>Simple method to check the value of a parameter.</p> + */ + private Object check(String name) + throws ConfigurationException { + if (name == null) throw new ConfigurationException("Null name"); + Object value = this.get(name); + if (value != null) return(value); + throw new ConfigurationException("Parameter \"" + name + + "\" not found"); + } + + /** + * <p>Simple method to throw a nicely formatted exception.</p> + */ + private ConfigurationException error(String n, String t, Throwable x) { + return new ConfigurationException("Parameter \"" + n + "\" value \"" + + this.getString(n, "?") + "\" can " + + "not be converted to a " + t, x); + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Block.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Block.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,157 @@ +/* =============================================================================== * + * 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.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.cocoon.kernel.KernelException; +import org.apache.cocoon.kernel.configuration.Configuration; + +/** + * <p>An [EMAIL PROTECTED] Block} represents an block descriptor.</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 Descriptor { + + /** <p>The name of the exposed Java interface.</p> */ + private String clazz = null; + /** <p>The name (if any) of the initializer method.</p> */ + private String initializer = null; + /** <p>The name (if any) of the destroyer method.</p> */ + private String destroyer = null; + /** <p>Whether the component is a singleton or not.</p> */ + private boolean singleton = true; + /** <p>The array of identifiers of all extended blocks.</p> */ + private String[] extensions = null; + /** <p>The array of identifiers of all implemented interfaces.</p> */ + private String[] implementations = null; + + /** + * <p>Create a new [EMAIL PROTECTED] Block} instance.</p> + * + * @param configuration A [EMAIL PROTECTED] Configuration} object enclosing the XML data. + * @throws KernelException If an error occurred processing the XML data. + */ + public Block(Configuration configuration) + throws KernelException { + /* Parse all generic stuff */ + super(configuration); + + /* Specific interface stuff */ + if (! "block".equals(configuration.name())) { + throw new KernelException("Invalid root element name for interface " + + " descriptor at " + configuration.location()); + } + + /* Provision */ + Configuration provides = configuration.child(NAMESPACE, "provides"); + this.clazz = provides.getStringAttribute("component", null); + if (this.clazz == null) { + throw new KernelException("Provided class name not specified at " + + provides.location()); + } + this.initializer = provides.getStringAttribute("initialize", null); + this.destroyer = provides.getStringAttribute("destroy", null); + this.singleton = provides.getBooleanAttribute("singleton", true); + if ((!singleton) && ((initializer != null) || (destroyer == null))) { + throw new KernelException("Non-singleton component declares initializer " + + "or destroyer method at " + provides.location()); + } + + /* Extensions and implementations */ + Iterator iterator = null; + Set list = null; + + /* Extensions */ + iterator = configuration.children(NAMESPACE, "extends"); + list = new HashSet(); + while (iterator.hasNext()) { + Configuration current = (Configuration) iterator.next(); + String id = current.getStringAttribute("block", null); + if (id == null) { + throw new KernelException("Extended block identifier not speci" + + "fied in descriptor at " + configuration.location()); + } + list.add(id); + } + this.extensions = (String[]) list.toArray(new String[list.size()]); + + /* Implementations */ + iterator = configuration.children(NAMESPACE, "extends"); + list = new HashSet(); + while (iterator.hasNext()) { + Configuration current = (Configuration) iterator.next(); + String id = current.getStringAttribute("block", null); + if (id == null) { + throw new KernelException("Extended block identifier not speci" + + "fied in descriptor at " + configuration.location()); + } + list.add(id); + } + this.implementations = (String[]) list.toArray(new String[list.size()]); + } + + /** + * <p>Return the class name of the provided Java™ class.</p> + */ + public String getComponent() { + return(this.clazz); + } + + /** + * <p>Return the name of the metod to call at initialization.</p> + */ + public String getComponentInitializer() { + return(this.initializer); + } + + /** + * <p>Return the name of the metod to call at destruction.</p> + */ + public String getComponentDestroyer() { + return(this.initializer); + } + + /** + * <p>Checks whether the component of this block is a singleton or not.</p> + */ + public boolean isSingletonComponent() { + return(this.singleton); + } + + /** + * <p>Return an array of all extended block identifers.</p> + */ + public String[] getExtendedBlocks() { + return(this.extensions); + } + + /** + * <p>Return an array of all implemented interface identifers.</p> + */ + public String[] getImplementedInterfaces() { + return(this.implementations); + } + + /** + * <p>Return the type of this descriptor.</p> + */ + public int getType() { + return Descriptor.BLOCK; + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Descriptor.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Descriptor.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,276 @@ +/* =============================================================================== * + * 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.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.cocoon.kernel.KernelException; +import org.apache.cocoon.kernel.configuration.Configuration; + +/** + * <p>A [EMAIL PROTECTED] Descriptor} represents a block or interface descriptor.</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 { + + /** <p>The namespace declaration of the XML descriptor.</p> */ + public static final String NAMESPACE = + "http://www.betaversion.org/tani/descriptor/1.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 array of libraries associated with this descriptor.</p> */ + private URL[] libraries = null; + + /** + * <p>Create a new [EMAIL PROTECTED] Descriptor} instance.</p> + * + * @param configuration A [EMAIL PROTECTED] Configuration} object enclosing the XML data. + * @throws KernelException If an error occurred processing the XML data. + */ + protected Descriptor(Configuration configuration) + throws KernelException { + /* Check the namespace */ + if (! NAMESPACE.equals(configuration.namespace())) { + throw new KernelException("Invalid namespace \"" + + configuration.namespace() + "\" declared for descriptor at " + + configuration.location()); + } + + /* Parse and setup the ID of this interface or block */ + String id = configuration.getStringAttribute("id", null); + if (id == null) { + throw new KernelException("Identifier not specified at " + + configuration.location()); + } + + try { + this.setupIdentifier(new URL(id)); + } catch (Throwable t) { + throw new KernelException("Unable to parse identifier \"" + id + "\"" + + " specified at " + configuration.location(), t); + } + + /* 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 KernelException("Library href attribute not specified " + + "in descriptor at " + configuration.location()); + } + try { + urls.add(new URL(href, url)); + } catch (Throwable t) { + throw new KernelException("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())); + } + + /** + * <p>Compare another [EMAIL PROTECTED] Descriptor} instance for compatibility.</p> + */ + public boolean isCompatibleWith(Descriptor descriptor) { + if (this.equals(descriptor)) return(true); + + 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); + + return(true); + } + + /** + * <p>Return the [EMAIL PROTECTED] URL} representing the full descriptor identifier.</p> + */ + public URL toURL() { + return(this.url); + } + + /** + * <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> + */ + public URL[] getLibraries() { + return(this.libraries); + } + + /* =========================================================================== */ + /* ABSTRACT METHODS */ + /* =========================================================================== */ + + /** + * <p>Return the type of this descriptor.</p> + */ + public abstract int getType(); + + /* =========================================================================== */ + /* 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. + */ + 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); + } + + /* 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); + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Interface.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Interface.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,68 @@ +/* =============================================================================== * + * 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.KernelException; +import org.apache.cocoon.kernel.configuration.Configuration; + +/** + * <p>An [EMAIL PROTECTED] Interface} represents an interface descriptor.</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 Interface extends Descriptor { + + /** <p>The name of the exposed Java interface.</p> */ + private String clazz = null; + + /** + * <p>Create a new [EMAIL PROTECTED] Interface} instance.</p> + * + * @param configuration A [EMAIL PROTECTED] Configuration} object enclosing the XML data. + * @throws KernelException If an error occurred processing the XML data. + */ + public Interface(Configuration configuration) + throws KernelException { + /* Parse all generic stuff */ + super(configuration); + + /* Specific interface stuff */ + if (! "interface".equals(configuration.name())) { + throw new KernelException("Invalid root element name for interface " + + " descriptor at " + configuration.location()); + } + + Configuration exposes = configuration.child(NAMESPACE, "exposes"); + this.clazz = exposes.getStringAttribute("interface", null); + if (this.clazz == null) { + throw new KernelException("Exposed interface name not specified at " + + exposes.location()); + } + } + + /** + * <p>Return the class name of the exposed Java™ interface.</p> + */ + public String getInterface() { + return(this.clazz); + } + + /** + * <p>Return the type of this descriptor.</p> + */ + public int getType() { + return Descriptor.INTERFACE; + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Library.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/description/Library.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,129 @@ +/* =============================================================================== * + * 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.Iterator; +import java.util.HashSet; +import java.util.NoSuchElementException; + +import org.apache.cocoon.kernel.KernelException; + +/** + * <p>The [EMAIL PROTECTED] Library} class defines a collection of [EMAIL PROTECTED] Descriptor} objects + * enclosed in 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 + * Software Foundation</a>. All rights reserved. + */ +public class Library extends HashSet { + + /** + * <p>Create a new [EMAIL PROTECTED] Library} instance.</p> + */ + public Library() { + super(); + } + + /** + * <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}. + */ + public boolean add(Object object) { + return(super.add((Descriptor) object)); + } + + /** + * <p>Returns an [EMAIL PROTECTED] Iterator} over all descriptors of a specified type.</p> + * + * @throws IllegalArgumentException If the type was not recognized. + */ + public Iterator iterator(int type) { + return new LibraryIterator(type, this.iterator()); + } + + /** + * <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. + */ + public Descriptor get(String identifier) + throws KernelException { + if (identifier == null) throw new NullPointerException("Null identifier"); + try { + return this.get(new URL(identifier)); + } catch (MalformedURLException e) { + throw new KernelException("Invalid descriptor " + identifier, 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. + */ + public Descriptor get(URL identifier) { + if (identifier == null) throw new NullPointerException("Null identifier"); + Iterator iterator = this.iterator(); + while (iterator.hasNext()) { + Descriptor current = (Descriptor) iterator.next(); + if (identifier.equals(current.toURL())) return(current); + } + return(null); + } + + /** + * <p>A simple [EMAIL PROTECTED] Iterator} implementation returning [EMAIL PROTECTED] Descriptor}s of + * a specified type from a given [EMAIL PROTECTED] Iterator}.</p> + */ + private static final class LibraryIterator implements Iterator { + private Iterator iterator = null; + private Descriptor next = null; + private int type = 0; + + private LibraryIterator(int type, Iterator iterator) { + if ((type == Descriptor.BLOCK) || (type == Descriptor.INTERFACE)) { + this.type = type; + } else { + throw new IllegalArgumentException("Invalid type " + type); + } + this.iterator = iterator; + } + + public boolean hasNext() { + if (this.next != null) return(true); + while (this.iterator.hasNext()) { + Descriptor current = (Descriptor) iterator.next(); + if (this.type != current.getType()) continue; + this.next = current; + return(true); + } + return(false); + } + + public Object next() { + if (next == null) this.hasNext(); + if (next == null) throw new NoSuchElementException(); + Object current = this.next; + this.next = null; + return(current); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Deployer.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Deployer.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,190 @@ +/* =============================================================================== * + * 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.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.cocoon.kernel.Kernel; +import org.apache.cocoon.kernel.KernelException; +import org.apache.cocoon.kernel.configuration.Configuration; +import org.apache.cocoon.kernel.description.Library; + +/** + * <p>The [EMAIL PROTECTED] Deployer} class is the main access point of the framework, providing + * ways to locate, instantiate, configure and deploy blocks and their components.</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 Deployer implements Kernel { + + /** <p>An empty array of [EMAIL PROTECTED] Object}s to be using in reflection.</p> */ + private static final Object NULL[] = new Object[0]; + + /** <p>The [EMAIL PROTECTED] Library} of all [EMAIL PROTECTED] Block}s and [EMAIL PROTECTED] Interface}s.</p> */ + private Library library = null; + /** <p>The [EMAIL PROTECTED] Runtime} of all available [EMAIL PROTECTED] Instance}s.</p> */ + private Runtime runtime = null; + /** <p>A [EMAIL PROTECTED] Map} of all initialized singleton components.</p> */ + private Map singletons = new HashMap(); + /** <p>A [EMAIL PROTECTED] Set} containing all components being initialized.</p> */ + private Set initializing = new HashSet(); + + /** + * <p>Create a new [EMAIL PROTECTED] Deployer} instance.</p> + */ + public Deployer() { + this.library = new Library(); + this.runtime = new Runtime(this.getClass().getClassLoader(), this.library); + } + + /** + * <p>Initialize this deployer using the specified [EMAIL PROTECTED] Configuration}.</p> + * + * @param configuration A [EMAIL PROTECTED] Configuration} containing descriptors locations + * and block instances. + */ + public void initialize(Configuration configuration) + throws KernelException { + this.initialize(configuration, configuration); + } + + /** + * <p>Initialize this deployer using the specified [EMAIL PROTECTED] Configuration}s.</p> + * + * @param descriptors A [EMAIL PROTECTED] Configuration} containing descriptors locations. + * @param instances A [EMAIL PROTECTED] Configuration} containing block instances. + */ + public void initialize(Configuration descriptors, Configuration instances) + throws KernelException { + Factory.configure(this.library, descriptors); + Factory.configure(this.runtime, instances); + + /* Initialize all singletons */ + Iterator iterator = this.runtime.iterator(); + while (iterator.hasNext()) { + /* Retrieve the instance and configuration */ + String name = (String) iterator.next(); + this.singletons.put(name, this.instantiate(name)); + } + } + + /** + * <p>Destroy this deployer and all block instances.</p> + */ + public void destroy() { + Iterator iterator = this.singletons.keySet().iterator(); + while (iterator.hasNext()) { + String current = (String) iterator.next(); + Object component = this.singletons.get(current); + Instance instance = this.runtime.getInstance(current); + Method destructor = instance.getComponentDestroyerMethod(); + try { + if (destructor != null) destructor.invoke(component, NULL); + } catch (Throwable t) { + // TODO: log this with the block logger! + System.err.println("Exception destroying singleton: " + current); + t.printStackTrace(System.err); + } + } + } + + /** + * <p>Returns the instance of a component deployed by the [EMAIL PROTECTED] Kernel}.</p> + */ + public Object lookup(String name) + throws KernelException { + /* Retrieve and check the instance */ + Instance instance = this.runtime.getInstance(name); + if (instance == null) { + throw new KernelException("Invalid instance name \"" + name + "\""); + } + + /* Prepare wiring and component */ + Object component = this.singletons.get(instance); + if (component == null) this.instantiate(name, instance); + Wiring wiring = new Wiring(component); + + /* Create and return the proxy instance */ + Class interfaces[] = instance.getImplementedInterfaces(); + try { + return Proxy.newProxyInstance(this.runtime, interfaces, wiring); + } catch (Throwable t) { + throw new KernelException("Unable to create proxy for " + name, t); + } + } + + /** + * <p>Return the [EMAIL PROTECTED] Runtime} instance associated with this.</p> + */ + protected Runtime getRuntime() { + return this.runtime; + } + + /** + * <p>Instantiate a new component given its block instance name.</p> + */ + private Object instantiate(String name) + throws KernelException { + return this.instantiate(name, this.runtime.getInstance(name)); + } + + /** + * <p>Instantiate a new component given its block instance and name.</p> + */ + private Object instantiate(String name, Instance instance) + throws KernelException { + if (instance == null) { + throw new KernelException("Invalid instance \"" + name + "\""); + } + + /* Prepare a new instance */ + Object component = null; + Class clazz = instance.getComponentClass(); + try { + component = clazz.newInstance(); + } catch (Throwable t) { + throw new KernelException("Can't instantiate " + clazz.getName(), t); + } + + /* Configure this component instance */ + Configuration configuration = this.runtime.getConfiguration(name); + if (this.initializing.contains(name)) { + throw new KernelException("Circular dependancy found initializing " + + "instance \"" + name + "\""); + } else { + this.initializing.add(name); + Factory.configure(component, this, configuration); + this.initializing.remove(name); + } + + /* Initialize the component and prepare the wiring */ + Method initializer = instance.getComponentInitializerMethod(); + try { + /* Non singletons will never have an initializer method set */ + if (initializer != null) initializer.invoke(component, NULL); + } catch (Throwable t) { + throw new KernelException("Can't initialize component " + name, t); + } + + /* Return the initialized component */ + return (component); + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Factory.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Factory.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,174 @@ +/* =============================================================================== * + * 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.beans.PropertyDescriptor; +import java.lang.reflect.Proxy; +import java.net.URL; +import java.util.Iterator; + +import org.apache.cocoon.kernel.Kernel; +import org.apache.cocoon.kernel.KernelException; +import org.apache.cocoon.kernel.configuration.Configuration; +import org.apache.cocoon.kernel.configuration.ConfigurationBuilder; +import org.apache.cocoon.kernel.description.Block; +import org.apache.cocoon.kernel.description.Descriptor; +import org.apache.cocoon.kernel.description.Interface; +import org.apache.cocoon.kernel.description.Library; + +/** + * <p>The [EMAIL PROTECTED] Factory} class is a utility class containing methods to + * configure [EMAIL PROTECTED] Library} and [EMAIL PROTECTED] Runtime} instances from XML files.</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 Factory { + + /** <p>Deny construction.</p> */ + private Factory() { + super(); + } + + /** + * <p>Configure the specified [EMAIL PROTECTED] Library} from a [EMAIL PROTECTED] Configuration}.</p> + */ + public static void configure(Library library, Configuration config) + throws KernelException { + if (library == null) throw new NullPointerException("Null library"); + if (config == null) throw new NullPointerException("Null configuration"); + + Iterator iterator = config.children("descriptor"); + Configuration current = config; + while (iterator.hasNext()) try { + current = (Configuration) iterator.next(); + String href = current.getStringAttribute("href"); + URL url = new URL(config.locationURL(), href); + Configuration descriptor = ConfigurationBuilder.parse(url); + if ("block".equals(descriptor.name())) { + library.add(new Block(descriptor)); + } else if ("interface".equals(descriptor.name())) { + library.add(new Interface(descriptor)); + } else { + throw new KernelException("Invalid descriptor root element \"" + + descriptor.name() + "\" found in descriptor at" + + descriptor.location()); + } + } catch (KernelException e) { + throw e; + } catch (Throwable t) { + throw new KernelException("Error processing descriptor at " + + current.location(), t); + } + } + + /** + * <p>Configure the specified [EMAIL PROTECTED] Runtime} from a [EMAIL PROTECTED] Configuration}.</p> + */ + public static void configure(Runtime runtime, Configuration config) + throws KernelException { + if (runtime == null) throw new NullPointerException("Null runtime"); + if (config == null) throw new NullPointerException("Null configuration"); + + Iterator iterator = config.children("instance"); + Configuration current = config; + while (iterator.hasNext()) try { + current = (Configuration) iterator.next(); + String name = current.getStringAttribute("name"); + String block = current.getStringAttribute("block"); + + Descriptor descriptor = runtime.getLibrary().get(block); + if (descriptor == null) { + throw new KernelException("Unable to retrieve descriptor for " + + "block \"" + block + " declared at " + current.location()); + } + if (descriptor.getType() != Descriptor.BLOCK) { + throw new KernelException("Unable to instantiate non-block \"" + + block + " declared at " + current.location()); + } + Instance instance = new Instance(runtime, (Block) descriptor); + runtime.add(name, instance, current); + } catch (KernelException e) { + throw e; + } catch (Throwable t) { + throw new KernelException("Unable to create block instance " + + "declared at " + current.location(), t); + } + } + + /** + * <p>Configure the specified component from a [EMAIL PROTECTED] Configuration}.</p> + */ + public static void configure(Object o, Deployer deployer, Configuration config) + throws KernelException { + Iterator iterator = config.children("set"); + while (iterator.hasNext()) { + + /* Look up the configurator and figure out the property name */ + Configuration current = (Configuration) iterator.next(); + String property = current.getStringAttribute("property", null); + if (property == null) { + throw new KernelException("Property name not specified at " + + current.location()); + } + + /* Using beans, access the property descriptor */ + PropertyDescriptor descriptor = null; + try { + String s = "set" + property.substring(0, 1).toUpperCase() + + property.substring(1); + descriptor = new PropertyDescriptor(property, o.getClass(), null, s); + } catch (Throwable t) { + throw new KernelException("Unable to retrieve setter method for pro" + + "perty \"" + property + "\" at " + current.location(), t); + } + + /* Do we have to set a value? */ + if (current.hasAttribute("value")) try { + Class type = descriptor.getPropertyType(); + Object value = current.getAttributeAs(property, type); + descriptor.getWriteMethod().invoke(o, new Object[] { value }); + continue; + } catch (Throwable t) { + throw new KernelException("Unable to set value for property \"" + + property + "\" specified at " + current.location(), t); + } + + /* Do we have to set a component? */ + if (current.hasAttribute("component")) try { + Object value = deployer.lookup(current.getStringAttribute("component")); + descriptor.getWriteMethod().invoke(o, new Object[] { value }); + continue; + } catch (Throwable t) { + throw new KernelException("Unable to set component for property \"" + + property + "\" specified at " + current.location(), t); + } + + /* Do we have to set the kernel itself? */ + if (current.getBooleanAttribute("kernel", false)) try { + Wiring w = new Wiring(deployer); + Class i[] = new Class[] { Kernel.class }; + Object value = Proxy.newProxyInstance(deployer.getRuntime(), i, w); + descriptor.getWriteMethod().invoke(o, new Object[] { value }); + continue; + } catch (Throwable t) { + throw new KernelException("Unable to set kernel for property \"" + + property + "\" specified at " + current.location(), t); + } + + /* We haven't continue(d), something bad happened */ + throw new KernelException("Invalid declaration at " + current.location()); + } + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Instance.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Instance.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,217 @@ +/* =============================================================================== * + * 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.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashSet; +import java.util.Set; + +import org.apache.cocoon.kernel.KernelException; +import org.apache.cocoon.kernel.description.Block; +import org.apache.cocoon.kernel.description.Descriptor; +import org.apache.cocoon.kernel.description.Interface; +import org.apache.cocoon.kernel.description.Library; + +/** + * <p>The [EMAIL PROTECTED] Instance} class represents a simple [EMAIL PROTECTED] Block} instance.</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 Instance extends URLClassLoader { + + /** <p>The component class.</p> */ + private Class component = null; + /** <p>The implemented interfaces.</p> */ + private Class interfaces[] = null; + /** <p>The component initializer method, if any.</p> */ + private Method initializer = null; + /** <p>The component destroyer method, if any.</p> */ + private Method destroyer = null; + /** <p>The [EMAIL PROTECTED] Block} instance associated with this [EMAIL PROTECTED] Instance}.</p> */ + private Block block = null; + + /** + * <p>Create a new [EMAIL PROTECTED] Instance} instance.</p> + */ + public Instance(Runtime runtime, Block block) + throws KernelException { + super(block.getLibraries(), runtime); + Library library = runtime.getLibrary(); + + /* Add all interfaces that must be implemented directly by this 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 KernelException("Block " + block.toString() + + " implements unknown block " + implementations[k]); + } + if (descriptor.getType() != Descriptor.BLOCK) { + throw new KernelException("Block " + block.toString() + + " implements non-interface " + descriptor.toString()); + } + + String clazz = ((Interface) descriptor).getInterface(); + try { + interfaces.add(runtime.loadClass(clazz)); + } catch (ClassNotFoundException e) { + throw new KernelException("Cant find class " + clazz + " exposed by " + + "interface " + descriptor.toString() + " implemented by " + + block.toString()); + } + } + + /* 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 KernelException("Block " + block.toString() + + " extends unknown block " + extensions[k]); + } + if (descriptor.getType() != Descriptor.BLOCK) { + throw new KernelException("Block " + block.toString() + + " extends non-block " + descriptor.toString()); + } + collector.add(block); + this.process(library, (Block) descriptor, collector, interfaces); + } + + /* Resolve the component class and verify that it implements what it must */ + try { + this.component = this.loadClass(block.getComponent()); + } catch (ClassNotFoundException e) { + throw new KernelException("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.component.isAssignableFrom(this.interfaces[k])) continue; + throw new KernelException("Component class \"" + this.component.getName() + + "\" is not assignable from \"" + this.interfaces[k] + "\""); + } + + /* Resolve the initializer and destroyer methods */ + String initializer = block.getComponentInitializer(); + if (initializer != null) try { + this.initializer = this.component.getMethod(initializer, new Class[0]); + } catch (NoSuchMethodException e) { + throw new KernelException("Initializer method \"" + initializer + + "\" for component \"" + block.getComponent() + "\" not found"); + } + String destroyer = block.getComponentInitializer(); + if (destroyer != null) try { + this.initializer = this.component.getMethod(destroyer, new Class[0]); + } catch (NoSuchMethodException e) { + throw new KernelException("Initializer method \"" + destroyer + + "\" for component \"" + block.getComponent() + "\" not found"); + } + + /* Remember where we're coming from */ + this.block = block; + } + + /** + * <p>Return the [EMAIL PROTECTED] Block} associated with this [EMAIL PROTECTED] Instance}.</p> + */ + public Block getBlock() { + return(this.block); + } + + /** + * <p>Return the [EMAIL PROTECTED] Class} of the component provided by this [EMAIL PROTECTED] Block} + * [EMAIL PROTECTED] Instance}.</p> + */ + public Class getComponentClass() { + return(this.component); + } + + /** + * <p>Return the [EMAIL PROTECTED] Method} to call upon intialization of the component.</p> + */ + public Method getComponentInitializerMethod() { + return(this.initializer); + } + + /** + * <p>Return the [EMAIL PROTECTED] Method} to call upon destruction of the component.</p> + */ + public Method getComponentDestroyerMethod() { + return(this.destroyer); + } + + /** + * <p>Return an array of [EMAIL PROTECTED] Class}es of all interfaces declared to be + * implemented by the component of this [EMAIL PROTECTED] Block} [EMAIL PROTECTED] Instance}.</p> + */ + public Class[] getImplementedInterfaces() { + return(this.interfaces); + } + + /** + * <p>Add all libraries provided by a given block and its super-blocks.</p> + */ + private void process(Library library, Block block, Set collector, Set interfaces) + throws KernelException { + /* Check circularities */ + if (collector.contains(block)) { + throw new KernelException("Circularity exception analysing " + + "extensions for block " + block.toString()); + } + collector.add(block); + + /* Process interfaces */ + String implementations[] = block.getImplementedInterfaces(); + for (int k = 0; k < implementations.length; k++) { + Descriptor descriptor = library.get(implementations[k]); + if (descriptor == null) { + throw new KernelException("Block " + block.toString() + + " implements unknown block " + implementations[k]); + } + if (descriptor.getType() != Descriptor.BLOCK) { + throw new KernelException("Block " + block.toString() + + " implements non-interface " + descriptor.toString()); + } + + String clazz = ((Interface) descriptor).getInterface(); + try { + interfaces.add(this.getParent().loadClass(clazz)); + } catch (ClassNotFoundException e) { + throw new KernelException("Cant find class " + clazz + " exposed by " + + "interface " + descriptor.toString() + " implemented by " + + block.toString()); + } + } + + /* Process libraries */ + URL libraries[] = block.getLibraries(); + for (int k = 0; k < libraries.length; k++) { + super.addURL(libraries[k]); + } + String extensions[] = block.getExtendedBlocks(); + for (int k = 0; k < extensions.length; k++) { + Descriptor descriptor = library.get(extensions[k]); + if (descriptor.getType() != Descriptor.BLOCK) { + throw new KernelException("Block " + block.toString() + + " extends non-block " + descriptor.toString()); + } + this.process(library, (Block) descriptor, collector, interfaces); + } + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Runtime.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Runtime.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,109 @@ +/* =============================================================================== * + * 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.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.cocoon.kernel.configuration.Configuration; +import org.apache.cocoon.kernel.description.Block; +import org.apache.cocoon.kernel.description.Descriptor; +import org.apache.cocoon.kernel.description.Library; + +/** + * <p>The [EMAIL PROTECTED] Runtime} class represents a collection of several [EMAIL PROTECTED] Block} + * [EMAIL PROTECTED] Instance}s.</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 Runtime extends URLClassLoader { + + private Library library = null; + private Map wrappers = new HashMap(); + + /** + * <p>Create a new [EMAIL PROTECTED] Runtime} instance.</p> + */ + public Runtime(ClassLoader parent, Library library) { + super(new URL[0], parent); + this.library = library; + Iterator iterator = library.iterator(Descriptor.INTERFACE); + while (iterator.hasNext()) { + URL libraries[] = ((Descriptor) iterator.next()).getLibraries(); + for (int k = 0; k < libraries.length; k++) super.addURL(libraries[k]); + } + } + + /** + * <p>Return the [EMAIL PROTECTED] Library} associated with this [EMAIL PROTECTED] Runtime}.</p> + */ + public Library getLibrary() { + return(this.library); + } + + /** + * <p>Push a new [EMAIL PROTECTED] Block} [EMAIL PROTECTED] Instance} into this [EMAIL PROTECTED] Runtime}.</p> + */ + protected void add(String name, Instance instance, Configuration configuration) { + if (name == null) throw new NullPointerException("Null name"); + this.wrappers.put(name, new Wrapper(instance, configuration)); + } + + /** + * <p>Return an [EMAIL PROTECTED] Iterator} over all [EMAIL PROTECTED] Instance} names configured.</p> + */ + public Iterator iterator() { + return(this.wrappers.keySet().iterator()); + } + + /** + * <p>Return the [EMAIL PROTECTED] Block} associated with the given name.</p> + */ + public Block getBlock(String name) { + return ((Wrapper)this.wrappers.get(name)).instance.getBlock(); + } + + /** + * <p>Return the [EMAIL PROTECTED] Instance} associated with the given name.</p> + */ + public Instance getInstance(String name) { + return ((Wrapper)this.wrappers.get(name)).instance; + } + + /** + * <p>Return the [EMAIL PROTECTED] Configuration} associated with the given name.</p> + */ + public Configuration getConfiguration(String name) { + return ((Wrapper)this.wrappers.get(name)).configuration; + } + + /** + * <p>A simple class wrapping aroung a [EMAIL PROTECTED] Block} [EMAIL PROTECTED] Instance} and its + * [EMAIL PROTECTED] Configuration}s.</p> + */ + private static final class Wrapper { + private Instance instance = null; + private Configuration configuration = null; + private Wrapper(Instance instance, Configuration config) { + if (instance == null) throw new NullPointerException("Null instance"); + if (config == null) throw new NullPointerException("Null configuration"); + this.instance = instance; + this.configuration = config; + } + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Wiring.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/runtime/Wiring.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,45 @@ +/* =============================================================================== * + * 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.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * <p>A simple [EMAIL PROTECTED] InvocationHandler} managing proxied object instances.</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 Wiring implements InvocationHandler { + + /** <p>The instance of the proxied object.</p> */ + private Object instance = null; + + /** + * <p>Create a new [EMAIL PROTECTED] Wiring} instance.</p> + */ + public Wiring(Object instance) { + if (instance == null) throw new NullPointerException("Null proxy instance"); + this.instance = instance; + } + + /** + * <p>Invoke the method over the remote proxied object instance.</p> + */ + public Object invoke(Object proxy, Method method, Object[] parameters) + throws Throwable { + return(method.invoke(null, parameters)); + } +} Added: cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/startup/Main.java ============================================================================== --- (empty file) +++ cocoon/whiteboard/kernel/src/org/apache/cocoon/kernel/startup/Main.java Sun Oct 31 18:10:16 2004 @@ -0,0 +1,87 @@ +/* =============================================================================== * + * 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.startup; + +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.runtime.Deployer; + +/** + * <p>A simple class initializing a [EMAIL PROTECTED] Kernel} from a the command line.</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 Main implements Runnable { + + /** <p>The current [EMAIL PROTECTED] Deployer} instance.</p> */ + private Deployer deployer = null; + + /** + * <p>Create a new [EMAIL PROTECTED] Main} instance.</p> + */ + private Main(Deployer deployer) { + if (deployer == null) throw new NullPointerException("Null deployer"); + this.deployer = deployer; + } + + /** + * <p>Called upon shutdown by the [EMAIL PROTECTED] Runtime}, this method will destroy the + * configured [EMAIL PROTECTED] Deployer} instance before the JVM is terminated.</p> + */ + public void run() { + this.deployer.destroy(); + } + + /** + * <p>Initialize from the command line.</p> + */ + public static void main(String args[]) + throws Throwable { + if ((args.length < 1) || (args.length > 2)) { + String name = Main.class.getName(); + System.err.println("Usage:"); + System.err.println(" " + name + " <conf-file>"); + System.err.println(" or"); + System.err.println(" " + name + " <desc-file> <inst-file>"); + System.err.println(); + System.err.println(" <conf-file> Combined descriptor/instances XML"); + System.err.println(" <desc-file> Descriptors locator XML"); + System.err.println(" <inst-file> Instances deployment XML"); + System.err.println(); + System.exit(1); + return; + } + + /* Parse the (possibly two) configurations */ + Configuration descriptors = ConfigurationBuilder.parse(args[0]); + Configuration instances = (args.length == 1 ? descriptors : + ConfigurationBuilder.parse(args[0])); + + /* Create and initialize a new deployer */ + Deployer deployer = new Deployer(); + deployer.initialize(descriptors, instances); + + /* Add the shutdown hook */ + Runtime.getRuntime().addShutdownHook(new Thread(new Main(deployer))); + + /* + * If non-daemon threads are still running, this thread will siply exit but + * the Java Virtual Machine will remain alive-and-kicking. If there are no + * other threads, the previously registered shutdown hook will be run and + * the whole shabang will die gracefully... Oh, how nice this is! + */ + } +}