aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From z..@apache.org
Subject svn commit: r1075094 [5/17] - in /aries/tags/blueprint-0.1-incubating: ./ blueprint-api/ blueprint-api/src/ blueprint-api/src/main/ blueprint-api/src/main/appended-resources/ blueprint-api/src/main/appended-resources/META-INF/ blueprint-api/src/main/ja...
Date Sun, 27 Feb 2011 17:47:18 GMT
Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ComponentDefinitionRegistryProcessor.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ComponentDefinitionRegistryProcessor.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ComponentDefinitionRegistryProcessor.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ComponentDefinitionRegistryProcessor.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint;
+
+/**
+ * A processor that processes Blueprint component definitions after they have been parsed but before
+ * component managers are created.
+ * 
+ * Component definition registry processors must be advertised as such in the blueprint xml. Do this by using
+ * the custom attribute defined in the extension schema.
+ * <pre>
+ *    &lt;bp:bean ext:role="processor" ...&gt;
+ * </pre>
+ * 
+ * When a definition registry processor is invoked type converters and registry processors have been already
+ * been created. Hence, changing component definitions for these or any components referenced by them will have 
+ * no effect.
+ * 
+ * Note: a processor that replaces existing component definitions with new ones should take care to copy
+ * interceptors defined against the old component definition if appropriate
+ * 
+ * @version $Rev: 922829 $, $Date: 2010-03-14 12:34:19 +0000 (Sun, 14 Mar 2010) $
+ */
+public interface ComponentDefinitionRegistryProcessor {
+
+    /**
+     * Process a <code>ComponentDefinitionRegistry</code>
+     * @param registry 
+     */
+    public void process(ComponentDefinitionRegistry registry);
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ComponentNameAlreadyInUseException.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ComponentNameAlreadyInUseException.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ComponentNameAlreadyInUseException.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ComponentNameAlreadyInUseException.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,34 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint;
+
+public class ComponentNameAlreadyInUseException extends RuntimeException {
+    
+    private String conflictingName;
+
+    public ComponentNameAlreadyInUseException(String conflictingName) {
+        this.conflictingName = conflictingName;
+    }
+    
+    public String getMessage() {
+        return "Name '" + this.conflictingName + "' is already in use by a registered component";
+    }
+
+    public String getConflictingName() {
+        return this.conflictingName;
+    }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBeanMetadata.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,50 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint;
+
+import org.osgi.service.blueprint.reflect.BeanMetadata;
+
+/**
+ * An extended <code>BeanMetadata</code> that allows specifying if
+ * the bean instances are processors or not.
+ * 
+ * Such processors have to be instantiated before instantiating all
+ * other singletons, but to avoid breaking the lazy activation of
+ * bundles, the Blueprint container needs to be aware of those and not
+ * try to load the class to perform some introspection.
+ */
+public interface ExtendedBeanMetadata extends BeanMetadata {
+
+    boolean isProcessor();
+    
+    /**
+     * Provide an actual class, this overrides the class name if set. This is
+     * useful for Namespace Handler services that do not want to force the
+     * Blueprint bundle to import implementation classes.
+     *
+     * @return Return the class to use in runtime or <code>null</code>.
+     */
+    
+    Class<?> getRuntimeClass();
+
+    /**
+     * Whether the bean allows properties to be injected directly into its fields in the case
+     * where an appropriate setter method is not available.
+     * @return Whether field injection is allowed
+     */
+    boolean getFieldInjection();
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBlueprintContainer.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBlueprintContainer.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBlueprintContainer.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedBlueprintContainer.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,62 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint;
+
+import java.security.AccessControlContext;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.aries.blueprint.container.ServiceRecipe;
+import org.apache.aries.blueprint.di.Repository;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.blueprint.container.BlueprintContainer;
+import org.osgi.service.blueprint.container.BlueprintListener;
+import org.osgi.service.blueprint.container.Converter;
+
+/**
+ * TODO: javadoc
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public interface ExtendedBlueprintContainer extends BlueprintContainer {
+
+    BundleContext getBundleContext();
+
+    Bundle getExtenderBundle();
+
+    BlueprintListener getEventDispatcher();
+
+    Converter getConverter();
+
+    Class loadClass(String name) throws ClassNotFoundException;
+
+    ComponentDefinitionRegistry getComponentDefinitionRegistry();
+
+    <T extends Processor> List<T> getProcessors(Class<T> type);
+
+    Repository getRepository();
+    
+    ServiceRegistration registerService(String[] classes, Object service, Dictionary properties);
+    
+    Object getService(ServiceReference reference);
+    
+    AccessControlContext getAccessControlContext();
+            
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedReferenceListMetadata.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedReferenceListMetadata.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedReferenceListMetadata.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedReferenceListMetadata.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,30 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint;
+
+import org.osgi.service.blueprint.reflect.ReferenceListMetadata;
+
+/**
+ * TODO: javadoc
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public interface ExtendedReferenceListMetadata extends ReferenceListMetadata, ExtendedServiceReferenceMetadata {
+
+    int PROXY_METHOD_GREEDY = 2;
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedServiceReferenceMetadata.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedServiceReferenceMetadata.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedServiceReferenceMetadata.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ExtendedServiceReferenceMetadata.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,34 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint;
+
+import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata;
+
+/**
+ * TODO: javadoc
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public interface ExtendedServiceReferenceMetadata extends ServiceReferenceMetadata {
+
+    int PROXY_METHOD_DEFAULT = 0;
+
+    int PROXY_METHOD_CLASSES = 1;
+
+    int getProxyMethod();
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/Interceptor.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/Interceptor.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/Interceptor.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/Interceptor.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint;
+
+import java.lang.reflect.Method;
+
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+
+/**
+ * An Interceptor interface provides support for custom interceptor implementation.
+ */
+public interface Interceptor {
+    /**
+     * This is called just before the method m is invocation.
+     * @param cm : the component's metada
+     * @param m: the method to be invoked
+     * @param parameters: method parameters
+     * @return token which will subsequently be passed to postCall
+     * @throws Throwable
+     */
+    public Object preCall(ComponentMetadata cm, Method m, Object... parameters) throws Throwable;
+    
+    /**
+     * This method is called after the method m is invoked and returned normally.
+     * @param cm: the component metadata
+     * @param m: the method invoked
+     * @param returnType : the return object
+     * @param preCallToken token returned by preCall
+     * @throws Throwable
+     */
+    public void postCallWithReturn(ComponentMetadata cm, Method m, Object returnType, Object preCallToken) throws Throwable;
+    
+    /**
+     * The method is called after the method m is invoked and causes an exception.
+     * @param cm : the component metadata
+     * @param m : the method invoked
+     * @param ex : the <code>Throwable</code> thrown
+     * @param preCallToken token returned by preCall
+     * @throws Throwable
+     */
+    public void postCallWithException(ComponentMetadata cm, Method m, Throwable ex, Object preCallToken) throws Throwable;
+    
+    
+    /**
+     * Return the rank of the interceptor, which is used to determine the order of the interceptors to be invoked
+     * Rank is between Integer.MIN_VALUE and Integer.MAX_VALUE, interceptors are called in the order of highest value
+     * rank first to lowest value rank last i.e. an interceptor with rank Integer.MAX_VALUE will be called before 
+     * all others (except of the same rank).
+     * @return the rank of the interceptor
+     */
+    public int getRank();
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,121 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint;
+
+import java.net.URL;
+import java.util.Set;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+import org.osgi.service.blueprint.reflect.Metadata;
+
+/**
+ * A processor for custom blueprint extensions
+ * 
+ * Namespace handlers must be registered in the OSGi service registry with the 
+ * <code>osgi.service.blueprint.namespace</code> service property denoting the namespace URIs this
+ * handler can process. The service property value can be either a single <code>String</code> or <code>URI</code>, 
+ * or a <code>Collection</code> respectively array of <code>String</code> or <code>URI</code>.
+ * 
+ * During parsing when the blueprint extender encounters an element from a non-blueprint namespace it will search
+ * for a namespace handler for the namespace that is compatible with blueprint bundle being processed. Then
+ * for a stand-alone component the parser will invoke the <code>parse</code> method 
+ * to create the <code>Metadata</code> for the xml element while for an element that is part
+ * of an existing component the parser will invoke the <code>decorated</code> method to augment
+ * the enclosing <code>ComponentMetadata</code> instance.  Various utilities to interact with 
+ * the blueprint parser are available to a namespace handler via the <code>ParserContext</code> argument 
+ * passed to <code>parse</code> and <code>decorate</code>.
+ * 
+ * Recommended behaviour:
+ * <ul>
+ * <li>New metadata objects should be created via calling <code>ParserContext.createMetadata(..)</code> and
+ * casting the returned object to the appropriate <code>MutableComponentMetadata</code> interface. 
+ * This method ensures that the metadata object implements the interfaces necessary for other namespace handlers
+ * to be able to use the metadata object.<br/>
+ * Also, to prevent id clashes, component ids should be generated by calling <code>ParserContext.generateId()</code>.
+ * </li>
+ * <li>A namespace handler should not return new metadata instances from the <code>decorate</code> method if 
+ * the same result could also be achieved by operating on a <code>MutableComponentMetadata</code> instance.
+ * </li>
+ * <li>A namespace handler should not assume the existence of predefined entries in the component definition
+ * registry such as <code>blueprintBundle</code> or <code>blueprintBundleContext</code>. In the case of a dry
+ * parse (i.e. a parse of the blueprint xml files without a backing OSGi bundle), these values will not be 
+ * available
+ * </li>
+ * </ul>
+ */
+public interface NamespaceHandler  {
+    /**
+     * Retrieve a URL from where the schema for a given namespace can be retrieved
+     * @param namespace The schema's namespace
+     * @return A URL that points to the location of the schema or null if the namespace validation
+     * is not needed
+     */
+    URL getSchemaLocation(String namespace);
+
+    /**
+     * Specify a set of classes that must be consistent between a blueprint bundle and this namespace handler
+     * 
+     * The blueprint extender will not invoke a namespace handler if any of the managed classes are inconsistent
+     * with the class space of the blueprint bundle (i.e. if the blueprint bundle loads any of the managed classes
+     * from a different classloader).
+     * 
+     * @return a <code>Set</code> of classes that must be compatible with any blueprint bundle for which this namespace 
+     * handler is to apply or <code>null</code> if no compatibility checks are to be performed
+     */
+    Set<Class> getManagedClasses();
+    
+    /**
+     * Parse a stand-alone blueprint component 
+     *
+     * Given an <code>Element</code> node as a root, this method parses the stand-alone component and returns its
+     * metadata. The supplied <code>ParserContext</code> should be used to parse embedded blueprint elements as well
+     * as creating metadata.
+     * 
+     * @param element The DOM element representing the custom component
+     * @param context The <code>ParserContext</code> for parsing sub-components and creating metadata objects
+     * @return A metadata instance representing the custom component. This should be an instance of an appropriate
+     * <code>MutableMetadata</code> type to enable further decoration by other namespace handlers
+     */
+    Metadata parse(Element element, ParserContext context);
+    
+    /**
+     * Process a child node of an enclosing blueprint component. 
+     * 
+     * If the decorator method returns a new <code>ComponentMetadata</code> instance, this will replace the argument 
+     * <code>ComponentMetadata</code> in subsequent parsing and namespace handler invocations. A namespace
+     * handler that elects to return a new <code>ComponentMetadata</code> instance should
+     * ensure that existing interceptors are registered against the new instance if appropriate.
+     * 
+     * Due to the interaction with interceptors, a namespace handler should prefer to change a component metadata
+     * instead of returning a new instance wherever possible. This can be achieved by casting a 
+     * <code>ComponentMetadata</code> to its corresponding <code>MutabableComponentMetadata</code> instance.
+     * Note however that a given <code>ComponentMetadata</code> instance cannot be guaranteed to implement
+     * the mutable interface if it was constructed by an agent other than the blueprint extender.
+     * 
+     * @param node The node associated with this NamespaceHandler that should be used to decorate the enclosing 
+     * component
+     * @param component The enclosing blueprint component
+     * @param context The parser context
+     * @return The decorated component to be used instead of the original enclosing component. This can of course be
+     * the original component.
+     */
+    ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context);
+             
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ParserContext.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ParserContext.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ParserContext.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ParserContext.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,90 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint;
+
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+import org.osgi.service.blueprint.reflect.Metadata;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+public interface ParserContext  {
+    /**
+     * Returns the DOM Node that was passed to the NamespaceHandler call for which
+     * this ParserContext instance was created.
+     */
+    Node getSourceNode();
+
+    ComponentDefinitionRegistry getComponentDefinitionRegistry();
+    
+    /**
+     * Retrieve the <code>ComponentMetadata</code> of the component that
+     * encloses the current <code>Node</code> that is to be parsed by a 
+     * namespace handler.
+     * 
+     * In case of top-level components this method will return <code>null</code>.
+     * @returns the enclosing component's metadata or null if there is no enclosing component
+     */
+    ComponentMetadata getEnclosingComponent();
+    
+    /**
+     * Create a new metadata instance of the given type. The returned
+     * object will also implement the appropriate <code>MutableComponentMetadata</code>
+     * interface, so as to allow the caller to set the properties of the 
+     * metadata.
+     *
+     * Note that the returned object may not be initialised, so callers
+     * should take care to assure every property needed by the blueprint
+     * extender is set.
+     *
+     * @param type the class of the Metadata object to create
+     * @param <T> The expected Metadata type to be created
+     * @return a new instance
+     */
+    <T extends Metadata> T createMetadata(Class<T> type);
+
+    /**
+     * Invoke the blueprint parser to parse a DOM element.
+     * @param type the class of the Metadata type to be parsed
+     * @param enclosingComponent The component metadata that contains the Element
+     * to be parsed
+     * @param element The DOM element that is to be parsed
+     * @param <T> The expected metadata type to be parsed
+     */
+    <T> T parseElement(Class<T> type, ComponentMetadata enclosingComponent, Element element);
+
+    /** 
+     * Generate a unique id following the same scheme that the blueprint container
+     * uses internally
+     */
+    String generateId();
+    
+    /**
+     * Get the default activation setting for the current blueprint file
+     */
+    String getDefaultActivation();
+    
+    /**
+     * Get the default availability setting for the current blueprint file
+     */
+    String getDefaultAvailability();
+    
+    /**
+     * Get the default timeout setting for the current blueprint file
+     */
+    String getDefaultTimeout();
+}
+

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ParserService.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ParserService.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ParserService.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ParserService.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,87 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.aries.blueprint;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+
+public interface ParserService {
+  
+  /**
+   * Parse a single InputStream containing blueprint xml. No validation will be performed. The caller
+   * is responsible for closing the InputStream afterwards.  
+   * @param is           InputStream containing blueprint xml. 
+   * @param clientBundle The client's bundle 
+   * @return             ComponentDefinitionRegistry containing metadata generated by the parser. 
+   * @throws Exception
+   */
+  ComponentDefinitionRegistry parse (InputStream is, Bundle clientBundle) throws Exception;
+  
+  /**
+   * Parse a single InputStream containing blueprint xml. The caller is responsible for 
+   * closing the InputStream afterwards.  
+   * @param is           Input stream containing blueprint xml
+   * @param clientBundle The client's bundle 
+   * @param validate     Indicates whether or not to validate the blueprint xml
+   * @return             ComponentDefinitionRegistry containing metadata generated by the parser. 
+   * @throws Exception
+   */
+  ComponentDefinitionRegistry parse (InputStream is, Bundle clientBundle, boolean validate) throws Exception;
+  
+  /**
+   * Parse blueprint xml referred to by a single URL. No validation will be performed. 
+   * @param url          URL reference to the blueprint xml to parse
+   * @param clientBundle The client's bundle
+   * @return             ComponentDefinitionRegistry containing metadata generated by the parser.
+   * @throws Exception
+   */
+  ComponentDefinitionRegistry parse (URL url, Bundle clientBundle) throws Exception;
+  
+  /**
+   * Parse blueprint xml referred to by a single URL.
+   * @param url          URL reference to the blueprint xml to parse
+   * @param clientBundle The client's bundle
+   * @param validate     Indicates whether or not to validate the blueprint xml
+   * @return             ComponentDefinitionRegistry containing metadata generated by the parser.
+   * @throws Exception
+   */
+  ComponentDefinitionRegistry parse (URL url, Bundle clientBundle, boolean validate) throws Exception;
+  
+  /**
+   * Parse blueprint xml referred to by a list of URLs. No validation will be performed. 
+   * @param urls         URL reference to the blueprint xml to parse
+   * @param clientBundle The client's bundle
+   * @return             ComponentDefinitionRegistry containing metadata generated by the parser.
+   * @throws Exception
+   */
+	ComponentDefinitionRegistry parse (List<URL> urls, Bundle clientBundle) throws Exception;
+	
+  /**
+   * Parse blueprint xml referred to by a list of URLs.
+   * @param urls         URL reference to the blueprint xml to parse
+   * @param clientBundle The client's bundle
+   * @param validate     Indicates whether or not to validate the blueprint xml
+   * @return             ComponentDefinitionRegistry containing metadata generated by the parser.
+   * @throws Exception
+   */
+	ComponentDefinitionRegistry parse (List<URL> urls, Bundle clientBundle, boolean validate) throws Exception;
+	
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/PassThroughMetadata.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/PassThroughMetadata.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/PassThroughMetadata.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/PassThroughMetadata.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint;
+
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+import org.osgi.service.blueprint.reflect.Target;
+
+/**
+ * Metadata used to bypass the creation of the object.
+ * This is mostly usefull when creating custom namespace handlers
+ * that end-up with already instanciated objects.
+ */
+public interface PassThroughMetadata extends ComponentMetadata, Target {
+
+    Object getObject();
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/Processor.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/Processor.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/Processor.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/Processor.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint;
+
+/**
+ * Marker interface for blueprint processors such as <code>BeanProcessor</code> or
+ * <code>ServiceProcessor</code>
+ */
+public interface Processor {}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ServiceProcessor.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ServiceProcessor.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ServiceProcessor.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/ServiceProcessor.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint;
+
+import java.util.Dictionary;
+
+/**
+ */
+public interface ServiceProcessor extends Processor {
+
+    void updateProperties(ServicePropertiesUpdater service, Dictionary properties);
+
+    interface ServicePropertiesUpdater {
+        
+        String getId();
+        
+        void updateProperties(Dictionary properties);
+        
+    }
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,660 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.container;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import net.sf.cglib.proxy.Dispatcher;
+import net.sf.cglib.proxy.Enhancer;
+
+import org.apache.aries.blueprint.BlueprintConstants;
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.ExtendedServiceReferenceMetadata;
+import org.apache.aries.blueprint.di.AbstractRecipe;
+import org.apache.aries.blueprint.di.CollectionRecipe;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.utils.BundleDelegatingClassLoader;
+import org.apache.aries.blueprint.utils.ReflectionUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.container.ReifiedType;
+import org.osgi.service.blueprint.reflect.ReferenceListener;
+import org.osgi.service.blueprint.reflect.ReferenceMetadata;
+import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class for service reference recipes.
+ *
+ * TODO: if we have a single interface (which is the standard behavior), then we should be able to get rid of
+ *       the proxyClassloader and just use this interface classloader to define the proxy
+ *
+ * TODO: it is allowed to have no interface defined at all, which should result in an empty proxy
+ *
+ * @version $Rev: 919741 $, $Date: 2010-03-06 11:02:45 +0000 (Sat, 06 Mar 2010) $
+ */
+public abstract class AbstractServiceReferenceRecipe extends AbstractRecipe implements ServiceListener, SatisfiableRecipe {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractServiceReferenceRecipe.class);
+
+    protected final ExtendedBlueprintContainer blueprintContainer;
+    protected final ServiceReferenceMetadata metadata;
+    protected final CollectionRecipe listenersRecipe;
+    protected final List<Recipe> explicitDependencies;
+    protected final ClassLoader proxyClassLoader;
+    protected final boolean optional;
+    /** The OSGi filter for tracking references */
+    protected final String filter;
+    /** The list of listeners for this reference.  This list will be lazy created */
+    protected List<Listener> listeners;
+
+    private final List<ServiceReference> references = new ArrayList<ServiceReference>();
+    private final AtomicBoolean started = new AtomicBoolean();
+    private final AtomicBoolean satisfied = new AtomicBoolean();
+    private SatisfactionListener satisfactionListener;
+    private volatile ProxyFactory proxyFactory;
+
+    protected AbstractServiceReferenceRecipe(String name,
+                                             ExtendedBlueprintContainer blueprintContainer,
+                                             ServiceReferenceMetadata metadata,
+                                             CollectionRecipe listenersRecipe,
+                                             List<Recipe> explicitDependencies) {
+        super(name);
+        this.prototype = false;
+        this.blueprintContainer = blueprintContainer;
+        this.metadata = metadata;
+        this.listenersRecipe = listenersRecipe;
+        this.explicitDependencies = explicitDependencies;
+        
+        
+        this.proxyClassLoader = makeProxyClassLoader(blueprintContainer, metadata);
+
+        this.optional = (metadata.getAvailability() == ReferenceMetadata.AVAILABILITY_OPTIONAL);
+        this.filter = createOsgiFilter(metadata);
+    }
+
+
+
+    // Create a ClassLoader delegating to the bundle, but also being able to see our bundle classes
+    // so that the created proxy can access cglib classes.
+    // TODO: we should be able to get rid of this classloader when using JDK 1.4 proxies with a single interface
+    //         (the case defined by the spec) and use the interface classloader instead
+    private ClassLoader makeProxyClassLoader(
+        final ExtendedBlueprintContainer blueprintContainer,
+        ServiceReferenceMetadata metadata) {
+      
+      String typeName = metadata.getInterface();
+      
+      if (typeName == null) {
+        return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+          public ClassLoader run() {
+            return new BundleDelegatingClassLoader(blueprintContainer.getBundleContext().getBundle(),
+                AbstractServiceReferenceRecipe.class.getClassLoader());
+          }      
+        });
+      }
+      
+      final ClassLoader interfaceClassLoader;
+      try {
+        Bundle clientBundle = blueprintContainer.getBundleContext().getBundle();
+        interfaceClassLoader = clientBundle.loadClass(typeName).getClassLoader();
+      } catch (ClassNotFoundException cnfe) {
+        throw new ComponentDefinitionException("Unable to load class " + typeName + " from recipe " + this, cnfe);
+      }
+      
+      return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+        public ClassLoader run() {
+          return new DualClassloader(interfaceClassLoader);
+        }      
+      });
+    }
+
+    private static class DualClassloader extends ClassLoader {
+      DualClassloader(ClassLoader parent) {
+        super(parent);
+      }
+      
+      @Override
+      protected Class<?> findClass(String name) throws ClassNotFoundException {
+        return getClass().getClassLoader().loadClass(name);
+      }
+
+      @Override
+      protected URL findResource(String name) {
+        return getClass().getClassLoader().getResource(name);
+      }
+    }
+    
+    public CollectionRecipe getListenersRecipe() {
+        return listenersRecipe;
+    }
+
+    public void start(SatisfactionListener listener) {
+        if (listener == null) throw new NullPointerException("satisfactionListener is null");
+        if (started.compareAndSet(false, true)) {
+            try {
+                satisfactionListener = listener;
+                satisfied.set(optional);
+                // Synchronized block on references so that service events won't interfere with initial references tracking
+                // though this may not be sufficient because we don't control ordering of those events
+                synchronized (references) {
+                    blueprintContainer.getBundleContext().addServiceListener(this, getOsgiFilter());
+                    ServiceReference[] references = blueprintContainer.getBundleContext().getServiceReferences(null, getOsgiFilter());
+                    if (references != null) {
+                        for (ServiceReference reference : references) {
+                            this.references.add(reference);
+                            track(reference);                           
+                        }
+                        satisfied.set(optional || !this.references.isEmpty());
+                    }
+                    LOGGER.debug("Found initial references {} for OSGi service {}", references, getOsgiFilter());
+                }
+            } catch (InvalidSyntaxException e) {
+                throw new ComponentDefinitionException(e);
+            }
+        }
+    }
+
+    public void stop() {
+        if (started.compareAndSet(true, false)) {
+            synchronized (references) {
+                blueprintContainer.getBundleContext().removeServiceListener(this);
+                doStop();
+                for (Iterator<ServiceReference> it = references.iterator(); it.hasNext();) {
+                    ServiceReference ref = it.next();
+                    it.remove();
+                    untrack(ref);
+                }
+                satisfied.set(false);
+            }
+        }
+    }
+
+    protected void doStop() {
+    }
+
+    protected boolean isStarted() {
+        return started.get();
+    }
+
+    public boolean isSatisfied() {
+        return satisfied.get();
+    }
+
+    @Override
+    public List<Recipe> getConstructorDependencies() {
+        List<Recipe> recipes = new ArrayList<Recipe>();
+        if (explicitDependencies != null) {
+            recipes.addAll(explicitDependencies);
+        }
+        return recipes;
+    }
+    
+    public List<Recipe> getDependencies() {
+        List<Recipe> recipes = new ArrayList<Recipe>();
+        if (listenersRecipe != null) {
+            recipes.add(listenersRecipe);
+        }
+        recipes.addAll(getConstructorDependencies());
+        return recipes;
+    }
+
+    public String getOsgiFilter() {
+        return filter;
+    }
+
+    protected void createListeners() {
+        try {
+            if (listenersRecipe != null) {
+                List<Listener> listeners = (List<Listener>) listenersRecipe.create();
+                for (Listener listener : listeners) {
+                    List<Class> cl = new ArrayList<Class>();
+                    if (metadata.getInterface() != null) {
+                        cl.addAll(loadAllClasses(Collections.singletonList(metadata.getInterface())));
+                    } else {
+                        cl.add(Object.class);
+                    }
+                    listener.init(cl);
+                }
+                this.listeners = listeners;
+            } else {
+                this.listeners = Collections.emptyList();
+            }
+        } catch (ClassNotFoundException e) {
+            throw new ComponentDefinitionException(e);
+        }
+    }
+
+    protected List<Class> loadAllClasses(Iterable<String> interfaceNames) throws ClassNotFoundException {
+        List<Class> classes = new ArrayList<Class>();
+        for (String name : interfaceNames) {
+            Class clazz = loadClass(name);
+            classes.add(clazz);
+        }
+        return classes;
+    }
+
+    protected ReifiedType loadType(String typeName, ClassLoader fromClassLoader) {
+        if (typeName == null) {
+            return null;
+        }
+        try {
+            // this method is overriden to use the blueprint container directly
+            // because proxies can be created outside of the recipe creation which
+            // would lead to an exception because the context is not set
+            // TODO: consider having the context as a property on the recipe rather than a thread local
+            return GenericType.parse(typeName, fromClassLoader != null ? fromClassLoader : blueprintContainer);
+        } catch (ClassNotFoundException e) {
+            throw new ComponentDefinitionException("Unable to load class " + typeName + " from recipe " + this, e);
+        }
+    }
+
+
+    protected Object createProxy(final Callable<Object> dispatcher, Iterable<String> interfaces) throws Exception {
+        if (!interfaces.iterator().hasNext()) {
+            return new Object();
+        } else {
+            return getProxyFactory().createProxy(proxyClassLoader, toClassArray(loadAllClasses(interfaces)), dispatcher);
+        }
+    }
+
+    protected synchronized ProxyFactory getProxyFactory() throws ClassNotFoundException {
+        if (proxyFactory == null) {
+            boolean proxyClass = false;
+            if (metadata instanceof ExtendedServiceReferenceMetadata) {
+                proxyClass = (((ExtendedServiceReferenceMetadata) metadata).getProxyMethod() & ExtendedServiceReferenceMetadata.PROXY_METHOD_CLASSES) != 0;
+            }
+            List<Class> classes = loadAllClasses(Collections.singletonList(this.metadata.getInterface()));
+            if (!proxyClass) {
+                for (Class cl : classes) {
+                    if (!cl.isInterface()) {
+                        throw new ComponentDefinitionException("A class " + cl.getName() + " was found in the interfaces list, but class proxying is not allowed by default. The ext:proxy-method='classes' attribute needs to be added to this service reference.");
+                    }
+                }
+            }
+            try {
+                // Try load load a cglib class (to make sure it's actually available
+                // then create the cglib factory
+                getClass().getClassLoader().loadClass("net.sf.cglib.proxy.Enhancer");
+                proxyFactory = new CgLibProxyFactory();
+            } catch (Throwable t) {
+                if (proxyClass) {
+                    throw new ComponentDefinitionException("Class proxying has been enabled but cglib can not be used", t);
+                }
+                proxyFactory = new JdkProxyFactory();
+            }
+        }
+        return proxyFactory;
+    }
+
+    public void serviceChanged(ServiceEvent event) {
+        int eventType = event.getType();
+        ServiceReference ref = event.getServiceReference();
+        switch (eventType) {
+            case ServiceEvent.REGISTERED:
+                serviceAdded(ref);
+                break;
+            case ServiceEvent.MODIFIED:
+                serviceModified(ref);
+                break;
+            case ServiceEvent.UNREGISTERING:
+                serviceRemoved(ref);
+                break;
+        }
+    }
+
+    private void serviceAdded(ServiceReference ref) {
+        LOGGER.debug("Tracking reference {} for OSGi service {}", ref, getOsgiFilter());
+        synchronized (references) {
+            references.add(ref);
+        }
+        track(ref);
+        setSatisfied(true);
+    }
+
+    private void serviceModified(ServiceReference ref) {
+        // ref must be in references and must be satisfied
+        track(ref);
+    }
+
+    private void serviceRemoved(ServiceReference ref) {
+        LOGGER.debug("Untracking reference {} for OSGi service {}", ref, getOsgiFilter());
+        boolean removed;
+        boolean satisfied;
+        synchronized (references) {
+            removed = references.remove(ref);
+            satisfied = optional || !references.isEmpty();
+        }
+        if (removed) {
+            untrack(ref);
+        }
+        setSatisfied(satisfied);
+    }
+
+    protected void setSatisfied(boolean s) {
+        // This check will ensure an atomic comparision and set
+        // so that it will only be true if the value actually changed
+        if (satisfied.getAndSet(s) != s) {
+            LOGGER.debug("Service reference with filter {} satisfied {}", getOsgiFilter(), this.satisfied);
+            this.satisfactionListener.notifySatisfaction(this);
+        }
+    }
+
+    protected abstract void track(ServiceReference reference);
+
+    protected abstract void untrack(ServiceReference reference);
+
+    protected abstract void retrack();
+
+    protected void updateListeners() {  
+        if (references.isEmpty()) {
+            unbind(null, null);
+        } else {
+            retrack();
+        }
+    }
+    
+    protected void bind(ServiceReference reference, Object service) {
+        if (listeners != null) {    
+            for (Listener listener : listeners) {
+                if (listener != null) {
+                    listener.bind(reference, service);
+                }
+            } 
+        }
+    }
+    
+    protected void unbind(ServiceReference reference, Object service) {
+        if (listeners != null) {    
+            for (Listener listener : listeners) {
+                if (listener != null) {
+                    listener.unbind(reference, service);
+                }
+            } 
+        }
+    }
+    
+    public List<ServiceReference> getServiceReferences() {
+        synchronized (references) {
+            return new ArrayList<ServiceReference>(references);
+        }
+    }
+
+    public ServiceReference getBestServiceReference() {
+        synchronized (references) {
+            int length = references.size();
+            if (length == 0) { /* if no service is being tracked */
+                return null;
+            }
+            int index = 0;
+            if (length > 1) { /* if more than one service, select highest ranking */
+                int maxRanking = Integer.MIN_VALUE;
+                long minId = Long.MAX_VALUE;
+                for (int i = 0; i < length; i++) {
+                    Object property = references.get(i).getProperty(Constants.SERVICE_RANKING);
+                    int ranking = (property instanceof Integer) ? (Integer) property : 0;
+                    long id = (Long) references.get(i).getProperty(Constants.SERVICE_ID);
+                    if ((ranking > maxRanking) || (ranking == maxRanking && id < minId)) {
+                        index = i;
+                        maxRanking = ranking;
+                        minId = id;
+                    }
+                }
+            }
+            return references.get(index);
+        }
+    }
+
+    public static class Listener {
+
+        private static final Logger LOGGER = LoggerFactory.getLogger(Listener.class);
+
+        private Object listener;
+        private ReferenceListener metadata;
+        private ExtendedBlueprintContainer blueprintContainer;
+
+        private Set<Method> bindMethodsReference = new HashSet<Method>();
+        private Set<Method> bindMethodsObjectProp = new HashSet<Method>();
+        private Set<Method> bindMethodsObject = new HashSet<Method>();
+        private Set<Method> unbindMethodsReference = new HashSet<Method>();
+        private Set<Method> unbindMethodsObject = new HashSet<Method>();
+        private Set<Method> unbindMethodsObjectProp = new HashSet<Method>();
+
+        public void setListener(Object listener) {
+            this.listener = listener;
+        }
+
+        public void setMetadata(ReferenceListener metadata) {
+            this.metadata = metadata;
+        }
+
+        public void setBlueprintContainer(ExtendedBlueprintContainer blueprintContainer) {
+            this.blueprintContainer = blueprintContainer;
+        }
+        
+        public void init(Collection<Class> classes) {
+            Set<Class> clazzes = new HashSet<Class>(classes);
+            clazzes.add(Object.class);
+            Class listenerClass = listener.getClass();
+            String bindName = metadata.getBindMethod();
+            if (bindName != null) {
+                bindMethodsReference.addAll(ReflectionUtils.findCompatibleMethods(listenerClass, bindName, new Class[] { ServiceReference.class }));
+                for (Class clazz : clazzes) {
+                    bindMethodsObject.addAll(ReflectionUtils.findCompatibleMethods(listenerClass, bindName, new Class[] { clazz }));
+                    bindMethodsObjectProp.addAll(ReflectionUtils.findCompatibleMethods(listenerClass, bindName, new Class[] { clazz, Map.class }));
+                }
+                if (bindMethodsReference.size() + bindMethodsObject.size() + bindMethodsObjectProp.size() == 0) {
+                    throw new ComponentDefinitionException("No matching methods found for listener bind method: " + bindName);
+                }
+            }
+            String unbindName = metadata.getUnbindMethod();
+            if (unbindName != null) {
+                unbindMethodsReference.addAll(ReflectionUtils.findCompatibleMethods(listenerClass, unbindName, new Class[] { ServiceReference.class }));
+                for (Class clazz : clazzes) {
+                    unbindMethodsObject.addAll(ReflectionUtils.findCompatibleMethods(listenerClass, unbindName, new Class[] { clazz }));
+                    unbindMethodsObjectProp.addAll(ReflectionUtils.findCompatibleMethods(listenerClass, unbindName, new Class[] { clazz, Map.class }));
+                }
+                if (unbindMethodsReference.size() + unbindMethodsObject.size() + unbindMethodsObjectProp.size() == 0) {
+                    throw new ComponentDefinitionException("No matching methods found for listener unbind method: " + unbindName);
+                }
+            }
+        }
+
+        public void bind(ServiceReference reference, Object service) {
+            invokeMethods(bindMethodsReference, bindMethodsObject, bindMethodsObjectProp, reference, service);
+        }
+
+        public void unbind(ServiceReference reference, Object service) {
+            invokeMethods(unbindMethodsReference, unbindMethodsObject, unbindMethodsObjectProp, reference, service);
+        }
+
+        private void invokeMethods(Set<Method> referenceMethods, Set<Method> objectMethods, Set<Method> objectPropMethods, ServiceReference reference, Object service) {
+            for (Method method : referenceMethods) {
+                try {
+                    ReflectionUtils.invoke(blueprintContainer.getAccessControlContext(), 
+                                           method, listener, reference);
+                } catch (Exception e) {
+                    LOGGER.error("Error calling listener method " + method, e);
+                }
+            }
+            for (Method method : objectMethods) {
+                try {
+                    ReflectionUtils.invoke(blueprintContainer.getAccessControlContext(), 
+                                           method, listener, service);
+                } catch (Exception e) {
+                    LOGGER.error("Error calling listener method " + method, e);
+                }
+            }
+            Map<String, Object> props = null;
+            for (Method method : objectPropMethods) {
+                if (props == null) {
+                    props = new HashMap<String, Object>();
+                    if (reference != null) {
+                        for (String name : reference.getPropertyKeys()) {
+                            props.put(name, reference.getProperty(name));
+                        }
+                    }
+                }
+                try {
+                    ReflectionUtils.invoke(blueprintContainer.getAccessControlContext(), 
+                                           method, listener, service, props);
+                } catch (Exception e) {
+                    LOGGER.error("Error calling listener method " + method, e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Create the OSGi filter corresponding to the ServiceReferenceMetadata constraints
+     *
+     * @param metadata the service reference metadata
+     * @return the OSGi filter
+     */
+    private static String createOsgiFilter(ServiceReferenceMetadata metadata) {
+        List<String> members = new ArrayList<String>();
+        // Handle filter
+        String flt = metadata.getFilter();
+        if (flt != null && flt.length() > 0) {
+            if (!flt.startsWith("(")) {
+                flt = "(" + flt + ")";
+            }
+            members.add(flt);
+        }
+        // Handle interfaces
+        String interfaceName = metadata.getInterface();
+        if (interfaceName != null && interfaceName.length() > 0) {
+            members.add("(" + Constants.OBJECTCLASS + "=" + interfaceName + ")");
+        }
+        // Handle component name
+        String componentName = metadata.getComponentName();
+        if (componentName != null && componentName.length() > 0) {
+            members.add("(" + BlueprintConstants.COMPONENT_NAME_PROPERTY + "=" + componentName + ")");
+        }
+        // Create filter
+        if (members.isEmpty()) {
+            throw new IllegalStateException("No constraints were specified on the service reference");
+        }
+        if (members.size() == 1) {
+            return members.get(0);
+        }
+        StringBuilder sb = new StringBuilder("(&");
+        for (String member : members) {
+            sb.append(member);
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    private static Class[] getInterfaces(Class[] classes) {
+        List<Class> interfaces = new ArrayList<Class>();
+        for (Class clazz : classes) {
+            if (clazz.isInterface()) {
+                interfaces.add(clazz);
+            }
+        }
+        return toClassArray(interfaces);
+    }
+
+    private static Class[] toClassArray(List<Class> classes) {
+        return classes.toArray(new Class [classes.size()]);
+    }
+
+    public static interface ProxyFactory {
+
+        public Object createProxy(ClassLoader classLoader, Class[] classes, Callable<Object> dispatcher);
+
+    }
+
+    public static class JdkProxyFactory implements ProxyFactory {
+
+        public Object createProxy(final ClassLoader classLoader, final Class[] classes, final Callable<Object> dispatcher) {
+            return Proxy.newProxyInstance(classLoader, getInterfaces(classes), new InvocationHandler() {
+                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                    try {
+                        return method.invoke(dispatcher.call(), args);
+                    } catch (InvocationTargetException ite) {
+                      throw ite.getTargetException();
+                    }
+                }
+            });
+        }
+
+    }
+
+    public static class CgLibProxyFactory implements ProxyFactory {
+
+        public Object createProxy(final ClassLoader classLoader, final Class[] classes, final Callable<Object> dispatcher) {
+            Enhancer e = new Enhancer();
+            e.setClassLoader(classLoader);
+            e.setSuperclass(getTargetClass(classes));
+            e.setInterfaces(getInterfaces(classes));
+            e.setInterceptDuringConstruction(false);
+            e.setCallback(new Dispatcher() {
+                public Object loadObject() throws Exception {
+                    return dispatcher.call();
+                }
+            });
+            e.setUseFactory(false);
+            return e.create();
+        }
+
+        protected Class<?> getTargetClass(Class<?>[] interfaceNames) {
+            // Only allow class proxying if specifically asked to
+            Class<?> root = Object.class;
+            for (Class<?> clazz : interfaceNames) {
+                if (!clazz.isInterface()) {
+                    if (root.isAssignableFrom(clazz)) {
+                        root = clazz;
+                    } else if (clazz.isAssignableFrom(root)) {
+                        //nothing to do, root is correct
+                    } else {
+                        throw new ComponentDefinitionException("Classes " + root.getClass().getName() + " and " + clazz.getName() + " are not in the same hierarchy");
+                    }
+                }
+            }
+            return root;
+        }
+
+    }
+
+}

Added: aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java?rev=1075094&view=auto
==============================================================================
--- aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java (added)
+++ aries/tags/blueprint-0.1-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java Sun Feb 27 17:47:08 2011
@@ -0,0 +1,432 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint.container;
+
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Pattern;
+import java.math.BigInteger;
+import java.math.BigDecimal;
+
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.di.CollectionRecipe;
+import org.apache.aries.blueprint.di.MapRecipe;
+import org.apache.aries.blueprint.utils.ReflectionUtils;
+
+import static org.apache.aries.blueprint.utils.ReflectionUtils.getRealCause;
+import org.osgi.service.blueprint.container.ReifiedType;
+import org.osgi.service.blueprint.container.Converter;
+
+/**
+ * Implementation of the Converter.
+ *
+ * This object contains all the registered Converters which can be registered
+ * by using {@link #registerConverter(Converter)}
+ * and unregistered using {@link #unregisterConverter(Converter)}.
+ *
+ * Each {@link org.osgi.service.blueprint.container.BlueprintContainer} has its own AggregateConverter
+ * used to register converters defined by the related blueprint bundle.
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class AggregateConverter implements Converter {
+
+    /**
+     * Objects implementing this interface will bypass the default conversion rules
+     * and be called directly to transform into the expected type.
+     */
+    public static interface Convertible {
+
+        Object convert(ReifiedType type) throws Exception;
+    }
+
+    private ExtendedBlueprintContainer blueprintContainer;
+    private List<Converter> converters = new ArrayList<Converter>();
+
+    public AggregateConverter(ExtendedBlueprintContainer blueprintContainer) {
+        this.blueprintContainer = blueprintContainer;
+    }
+
+    public void registerConverter(Converter converter) {
+        converters.add(converter);
+    }
+
+    public void unregisterConverter(Converter converter) {
+        converters.remove(converter);
+    }
+
+    public boolean canConvert(final Object fromValue, final ReifiedType toType) {
+        if (fromValue == null) {
+            return true;
+        }
+        if (isAssignable(fromValue, toType)) {
+            return true;
+        }
+        
+        boolean canConvert = false;
+        AccessControlContext acc = blueprintContainer.getAccessControlContext();
+        if (acc == null) {
+            canConvert = canConvertWithConverters(fromValue, toType);
+        } else {
+            canConvert = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return canConvertWithConverters(fromValue, toType);
+                }            
+            }, acc);
+        }
+        if (canConvert) {
+            return true;
+        }
+        
+        // TODO
+        if (fromValue instanceof String) {
+            //
+        }
+        return false;
+    }
+
+    public Object convert(final Object fromValue, final ReifiedType type) throws Exception {
+        // Discard null values
+        if (fromValue == null) {
+            return null;
+        }
+        // First convert service proxies
+        if (fromValue instanceof Convertible) {
+            return ((Convertible) fromValue).convert(type);
+        }
+        // If the object is an instance of the type, just return it
+        if (isAssignable(fromValue, type)) {
+            return fromValue;
+        }
+        Object value = null;
+        AccessControlContext acc = blueprintContainer.getAccessControlContext();
+        if (acc == null) {
+            value = convertWithConverters(fromValue, type);
+        } else {
+            value = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+                public Object run() throws Exception {
+                    return convertWithConverters(fromValue, type);
+                }            
+            }, acc);
+        }
+        if (value == null) {
+            if (fromValue instanceof Number && Number.class.isAssignableFrom(unwrap(toClass(type)))) {
+                return convertToNumber((Number) fromValue, toClass(type));
+            } else if (fromValue instanceof String) {
+                return convertFromString((String) fromValue, toClass(type), blueprintContainer);
+            } else if (toClass(type).isArray() && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
+                return convertToArray(fromValue, type);
+            } else if (Map.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
+                return convertToMap(fromValue, type);
+            } else if (Dictionary.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
+                return convertToDictionary(fromValue, type);
+            } else if (Collection.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
+                return convertToCollection(fromValue, type);
+            } else {
+                throw new Exception("Unable to convert value " + fromValue + " to type " + type);
+            }
+        }
+        return value;
+    }
+
+    private boolean canConvertWithConverters(Object source, ReifiedType type) {
+        for (Converter converter : converters) {
+            if (converter.canConvert(source, type)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    private Object convertWithConverters(Object source, ReifiedType type) throws Exception {
+        Object value = null;
+        for (Converter converter : converters) {
+            if (converter.canConvert(source, type)) {
+                value = converter.convert(source, type);
+                if (value != null) {
+                    return value;
+                }
+            }
+        }
+        return value;
+    }
+
+    public Object convertToNumber(Number value, Class toType) throws Exception {
+        toType = unwrap(toType);
+        if (AtomicInteger.class == toType) {
+            return new AtomicInteger((Integer) convertToNumber(value, Integer.class));
+        } else if (AtomicLong.class == toType) {
+            return new AtomicLong((Long) convertToNumber(value, Long.class));
+        } else if (Integer.class == toType) {
+            return value.intValue();
+        } else if (Short.class == toType) {
+            return value.shortValue();
+        } else if (Long.class == toType) {
+            return value.longValue();
+        } else if (Float.class == toType) {
+            return value.floatValue();
+        } else if (Double.class == toType) {
+            return value.doubleValue();
+        } else if (Byte.class == toType) {
+            return value.byteValue();
+        } else if (BigInteger.class == toType) {
+            return new BigInteger(value.toString());
+        } else if (BigDecimal.class == toType) {
+            return new BigDecimal(value.toString());
+        } else {
+            throw new Exception("Unable to convert number " + value + " to " + toType);
+        }
+    }
+
+    public Object convertFromString(String value, Class toType, Object loader) throws Exception {
+        toType = unwrap(toType);
+        if (ReifiedType.class == toType) {
+            try {
+                return GenericType.parse(value, loader);
+            } catch (ClassNotFoundException e) {
+                throw new Exception("Unable to convert", e);
+            }
+        } else if (Class.class == toType) {
+            try {
+                return GenericType.parse(value, loader).getRawClass();
+            } catch (ClassNotFoundException e) {
+                throw new Exception("Unable to convert", e);
+            }
+        } else if (Locale.class == toType) {
+            String[] tokens = value.split("_");
+            if (tokens.length == 1) {
+                return new Locale(tokens[0]);
+            } else if (tokens.length == 2) {
+                return new Locale(tokens[0], tokens[1]);
+            } else if (tokens.length == 3) {
+                return new Locale(tokens[0], tokens[1], tokens[2]);
+            } else {
+                throw new Exception("Invalid locale string:" + value);
+            }
+        } else if (Pattern.class == toType) {
+            return Pattern.compile(value);
+        } else if (Properties.class == toType) {
+            Properties props = new Properties();
+            ByteArrayInputStream in = new ByteArrayInputStream(value.getBytes("UTF8"));
+            props.load(in);
+            return props;
+        } else if (Boolean.class == toType) {
+            if ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value)) {
+                return Boolean.TRUE;
+            } else if ("no".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value) || "off".equalsIgnoreCase(value)) {
+                return Boolean.FALSE;
+            } else {
+                throw new RuntimeException("Invalid boolean value: " + value);
+            }
+        } else if (Integer.class == toType) {
+            return Integer.valueOf(value);
+        } else if (Short.class == toType) {
+            return Short.valueOf(value);
+        } else if (Long.class == toType) {
+            return Long.valueOf(value);
+        } else if (Float.class == toType) {
+            return Float.valueOf(value);
+        } else if (Double.class == toType) {
+            return Double.valueOf(value);
+        } else if (Character.class == toType) {
+            if (value.length() == 6 && value.startsWith("\\u")) {
+                int code = Integer.parseInt(value.substring(2), 16);
+                return (char)code;
+            } else if (value.length() == 1) {
+                return value.charAt(0);
+            } else {
+                throw new Exception("Invalid value for character type: " + value);
+            }
+        } else if (Byte.class == toType) {
+            return Byte.valueOf(value);
+        } else if (Enum.class.isAssignableFrom(toType)) {
+            return Enum.valueOf((Class<Enum>) toType, value);
+        } else {
+            return createObject(value, toType);
+        }
+    }
+
+    private Object createObject(String value, Class type) throws Exception {
+        if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) {
+            throw new Exception("Unable to convert value " + value + " to type " + type + ". Type " + type + " is an interface or an abstract class");
+        }
+        Constructor constructor = null;
+        try {
+            constructor = type.getConstructor(String.class);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException("Unable to convert to " + type);
+        }
+        try {
+            return ReflectionUtils.newInstance(blueprintContainer.getAccessControlContext(), constructor, value);
+        } catch (Exception e) {
+            throw new Exception("Unable to convert ", getRealCause(e));
+        }
+    }
+    
+    private Object convertToCollection(Object obj, ReifiedType type) throws Exception {
+        ReifiedType valueType = type.getActualTypeArgument(0);
+        Collection newCol = (Collection) ReflectionUtils.newInstance(blueprintContainer.getAccessControlContext(), 
+                                                                     CollectionRecipe.getCollection(toClass(type)));
+        if (obj.getClass().isArray()) {
+            for (int i = 0; i < Array.getLength(obj); i++) {
+                try {
+                    newCol.add(convert(Array.get(obj, i), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
+                }
+            }
+        } else {
+            for (Object item : (Collection) obj) {
+                try {
+                    newCol.add(convert(item, valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting collection entry)", t);
+                }
+            }
+        }
+        return newCol;
+    }
+
+    private Object convertToDictionary(Object obj, ReifiedType type) throws Exception {
+        ReifiedType keyType = type.getActualTypeArgument(0);
+        ReifiedType valueType = type.getActualTypeArgument(1);
+        Dictionary newDic = new Hashtable();
+        if (obj instanceof Dictionary) {
+            Dictionary dic = (Dictionary) obj;
+            for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements();) {
+                Object key = keyEnum.nextElement();
+                try {
+                    newDic.put(convert(key, keyType), convert(dic.get(key), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+                }
+            }
+        } else {
+            for (Map.Entry e : ((Map<Object,Object>) obj).entrySet()) {
+                try {
+                    newDic.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+                }
+            }
+        }
+        return newDic;
+    }
+
+    private Object convertToMap(Object obj, ReifiedType type) throws Exception {
+        ReifiedType keyType = type.getActualTypeArgument(0);
+        ReifiedType valueType = type.getActualTypeArgument(1);
+        Map newMap = (Map) ReflectionUtils.newInstance(blueprintContainer.getAccessControlContext(), 
+                                                       MapRecipe.getMap(toClass(type)));
+        if (obj instanceof Dictionary) {
+            Dictionary dic = (Dictionary) obj;
+            for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements();) {
+                Object key = keyEnum.nextElement();
+                try {
+                    newMap.put(convert(key, keyType), convert(dic.get(key), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+                }
+            }
+        } else {
+            for (Map.Entry e : ((Map<Object,Object>) obj).entrySet()) {
+                try {
+                    newMap.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+                }
+            }
+        }
+        return newMap;
+    }
+
+    private Object convertToArray(Object obj, ReifiedType type) throws Exception {
+        if (obj instanceof Collection) {
+            obj = ((Collection) obj).toArray();
+        }
+        if (!obj.getClass().isArray()) {
+            throw new Exception("Unable to convert from " + obj + " to " + type);
+        }
+        ReifiedType componentType;
+        if (type.size() > 0) {
+            componentType = type.getActualTypeArgument(0);
+        } else {
+            componentType = new GenericType(type.getRawClass().getComponentType());
+        }
+        Object array = Array.newInstance(toClass(componentType), Array.getLength(obj));
+        for (int i = 0; i < Array.getLength(obj); i++) {
+            try {
+                Array.set(array, i, convert(Array.get(obj, i), componentType));
+            } catch (Exception t) {
+                throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
+            }
+        }
+        return array;
+    }
+
+    public static boolean isAssignable(Object source, ReifiedType target) {
+        return source == null
+                || (target.size() == 0
+                    && unwrap(target.getRawClass()).isAssignableFrom(unwrap(source.getClass())));
+    }
+
+    private static Class unwrap(Class c) {
+        Class u = primitives.get(c);
+        return u != null ? u : c;
+    }
+    
+    private static final Map<Class, Class> primitives;
+    static {
+        primitives = new HashMap<Class, Class>();
+        primitives.put(byte.class, Byte.class);
+        primitives.put(short.class, Short.class);
+        primitives.put(char.class, Character.class);
+        primitives.put(int.class, Integer.class);
+        primitives.put(long.class, Long.class);
+        primitives.put(float.class, Float.class);
+        primitives.put(double.class, Double.class);
+        primitives.put(boolean.class, Boolean.class);
+    }
+
+    public Object convert(Object source, Type target) throws Exception {
+        return convert( source, new GenericType(target));
+    }
+
+    private Class toClass(ReifiedType type) {
+        return type.getRawClass();
+    }
+    
+}
\ No newline at end of file



Mime
View raw message