diff options
Diffstat (limited to 'sandbox/sebastien/java/extend/modules/implementation-spring/src')
18 files changed, 2427 insertions, 0 deletions
diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringBeanElement.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringBeanElement.java new file mode 100644 index 0000000000..64b36a0a44 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringBeanElement.java @@ -0,0 +1,132 @@ +/* + * 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.tuscany.sca.implementation.spring; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a <bean> element in a Spring application-context + * - this has id and className attributes + * - plus zero or more property elements as children + * + * @version $Rev$ $Date$ + */ +public class SpringBeanElement { + + private String id; + private String className = null; + private boolean innerBean = false; + private boolean abstractBean = false; + private boolean parentAttribute = false; + private boolean factoryBeanAttribute = false; + private boolean factoryMethodAttribute = false; + + private List<SpringPropertyElement> properties = new ArrayList<SpringPropertyElement>(); + private List<SpringConstructorArgElement> constructorargs = new ArrayList<SpringConstructorArgElement>(); + + public SpringBeanElement() { + } + + public SpringBeanElement(String id, String className) { + this.id = id; + this.className = className; + } + + public String getClassName() { + return className; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public List<SpringPropertyElement> getProperties() { + return properties; + } + + public void addProperty(SpringPropertyElement property) { + properties.add(property); + } + + public List<SpringConstructorArgElement> getCustructorArgs() { + return constructorargs; + } + + public void addCustructorArgs(SpringConstructorArgElement args) { + constructorargs.add(args); + } + + public boolean isInnerBean() { + return innerBean; + } + + public void setInnerBean(boolean innerBean) { + this.innerBean = innerBean; + } + + public boolean isAbstractBean() { + return abstractBean; + } + + public void setAbstractBean(boolean abstractBean) { + this.abstractBean = abstractBean; + } + + public boolean hasParentAttribute() { + return parentAttribute; + } + + public void setParentAttribute(boolean parentAttribute) { + this.parentAttribute = parentAttribute; + } + + public boolean hasFactoryBeanAttribute() { + return factoryBeanAttribute; + } + + public void setFactoryBeanAttribute(boolean factoryBeanAttribute) { + this.factoryBeanAttribute = factoryBeanAttribute; + } + + public boolean hasFactoryMethodAttribute() { + return factoryMethodAttribute; + } + + public void setFactoryMethodAttribute(boolean factoryMethodAttribute) { + this.factoryMethodAttribute = factoryMethodAttribute; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SpringBeanElement [id=").append(id).append(", className=").append(className) + .append(", innerBean=").append(innerBean).append(", abstractBean=").append(abstractBean) + .append(", parentAttribute=").append(parentAttribute).append(", factoryBeanAttribute=") + .append(factoryBeanAttribute).append(", factoryMethodAttribute=").append(factoryMethodAttribute) + .append(", properties=").append(properties).append(", constructorargs=").append(constructorargs) + .append("]"); + return builder.toString(); + } + +} // end class SpringBeanElement diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringConstructorArgElement.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringConstructorArgElement.java new file mode 100644 index 0000000000..1de0595d60 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringConstructorArgElement.java @@ -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.tuscany.sca.implementation.spring; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a <constructor-arg> element in a Spring application-context + * - this has ref attribute + * + * @version $Rev$ $Date$ + */ +public class SpringConstructorArgElement { + + private String type; + private int autoIndex = -1; + private int index = -1; + private List<String> refs = new ArrayList<String>(); + private List<String> values = new ArrayList<String>(); + + public SpringConstructorArgElement() { + + } + + public SpringConstructorArgElement(String type) { + this.type = type; + } + + public String getType() { + return this.type; + } + + public List<String> getRefs() { + return this.refs; + } + + public void addRef(String ref) { + this.refs.add(ref); + } + + public int getIndex() { + return this.index; + } + + public void setIndex(int index) { + this.index = index; + } + + public int getAutoIndex() { + return this.autoIndex; + } + + public void setAutoIndex(int index) { + this.autoIndex = index; + } + + public List<String> getValues() { + return this.values; + } + + public void addValue(String value) { + this.values.add(value); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SpringConstructorArgElement [type=").append(type).append(", autoIndex=").append(autoIndex) + .append(", index=").append(index).append(", refs=").append(refs).append(", values=").append(values) + .append("]"); + return builder.toString(); + } +} diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java new file mode 100644 index 0000000000..a5d4adb1bb --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java @@ -0,0 +1,259 @@ +/* + * 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.tuscany.sca.implementation.spring; + +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.Extensible; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.impl.ImplementationImpl; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; + +/** + * Represents a Spring implementation. + * + * @version $Rev$ $Date$ + */ +public class SpringImplementation extends ImplementationImpl implements Implementation, Extensible { + public final static QName TYPE = new QName(SCA11_NS, "implementation.spring"); + // The location attribute which points to the Spring application-context XML file + private String location; + // The application-context file as a Spring Resource + private List<URL> resource; + private ComponentType componentType; + // Mapping of Services to Beans + private Map<String, SpringBeanElement> serviceMap; + // Mapping of property names to Java class + private Map<String, Class<?>> propertyMap; + // List of unresolved bean property references + private Map<String, Reference> unresolvedBeanRef; + private ClassLoader classLoader; + + public SpringImplementation() { + super(TYPE); + this.location = null; + this.resource = null; + setUnresolved(true); + serviceMap = new HashMap<String, SpringBeanElement>(); + propertyMap = new HashMap<String, Class<?>>(); + unresolvedBeanRef = new HashMap<String, Reference>(); + } // end method SpringImplementation + + /* Returns the location attribute for this Spring implementation */ + public String getLocation() { + return location; + } + + /** + * Sets the location attribute for this Spring implementation + * location - a URI to the Spring application-context file + */ + public void setLocation(String location) { + this.location = location; + return; + } + + public void setResource(List<URL> resource) { + this.resource = resource; + } + + public List<URL> getResource() { + return resource; + } + + /* + * Returns the componentType for this Spring implementation + */ + public ComponentType getComponentType() { + return componentType; + } + + /* + * Sets the componentType for this Spring implementation + */ + public void setComponentType(ComponentType componentType) { + this.componentType = componentType; + } + + @Override + public List<Service> getServices() { + return componentType.getServices(); + } + + @Override + public List<Reference> getReferences() { + return componentType.getReferences(); + } + + @Override + public List<Property> getProperties() { + return componentType.getProperties(); + } + + /** + * Returns the Spring Bean which implements a particular service + * @param service the service + * @return the bean which implements the service, as a SpringBeanElement + */ + public SpringBeanElement getBeanFromService(Service service) { + SpringBeanElement theBean = serviceMap.get(service.getName()); + return theBean; + } + + /** + * Sets the mapping from a service to the Spring Bean that implements the service + * @param service the service + * @param theBean a SpringBeanElement for the Bean implementing the service + */ + public void setBeanForService(Service service, SpringBeanElement theBean) { + serviceMap.put(service.getName(), theBean); + } + + /** + * Add a mapping from a SCA property name to a Java class for the property + * @param propertyName + * @param propertyClass + */ + public void setPropertyClass(String propertyName, Class<?> propertyClass) { + if (propertyName == null || propertyClass == null) + return; + propertyMap.put(propertyName, propertyClass); + return; + } // end method setPropertyClass + + /** + * Gets the Java Class for an SCA property + * @param propertyName - the property name + * @return - a Class object for the type of the property + */ + public Class<?> getPropertyClass(String propertyName) { + return propertyMap.get(propertyName); + } // end method getPropertyClass + + public void setUnresolvedBeanRef(String refName, Reference reference) { + if (refName == null || reference == null) + return; + unresolvedBeanRef.put(refName, reference); + return; + } // end method setUnresolvedBeanRef + + public Reference getUnresolvedBeanRef(String refName) { + return unresolvedBeanRef.get(refName); + } // end method getUnresolvedBeanRef + + /** + * Use preProcess to validate and map the references and properties dynamically + */ + public void build(Component component) { + + for (Reference reference : component.getReferences()) { + if (unresolvedBeanRef.containsKey(reference.getName())) { + Reference ref = unresolvedBeanRef.get(reference.getName()); + componentType.getReferences().add(createReference(reference, ref.getInterfaceContract())); + unresolvedBeanRef.remove(reference.getName()); + } + } + + for (Property property : component.getProperties()) { + if (unresolvedBeanRef.containsKey(property.getName())) { + componentType.getProperties().add(createProperty(property)); + this.setPropertyClass(property.getName(), property.getClass()); + unresolvedBeanRef.remove(property.getName()); + } + } + } + + protected Reference createReference(Reference reference, InterfaceContract interfaze) { + Reference newReference; + try { + newReference = (Reference)reference.clone(); + if (newReference.getInterfaceContract() == null) + newReference.setInterfaceContract(interfaze); + } catch (CloneNotSupportedException e) { + throw new AssertionError(e); // should not ever happen + } + return newReference; + } + + protected Property createProperty(Property property) { + Property newProperty; + try { + newProperty = (Property)property.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(e); // should not ever happen + } + return newProperty; + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((location == null) ? 0 : location.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (!(obj instanceof SpringImplementation)) { + return false; + } + SpringImplementation other = (SpringImplementation)obj; + if (location == null) { + if (other.location != null) { + return false; + } + } else if (!location.equals(other.location)) { + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SpringImplementation [location=").append(location).append(", resource=").append(resource) + .append("]"); + return builder.toString(); + } +} diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationBuilder.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationBuilder.java new file mode 100644 index 0000000000..1a246fa03a --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationBuilder.java @@ -0,0 +1,41 @@ +/* + * 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.tuscany.sca.implementation.spring; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.ImplementationBuilder; + +/** + * + */ +public class SpringImplementationBuilder implements ImplementationBuilder<SpringImplementation> { + + public void build(Component component, SpringImplementation implmentation, BuilderContext context) { + implmentation.build(component); + } + + public QName getImplementationType() { + return SpringImplementation.TYPE; + } + +} diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationConstants.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationConstants.java new file mode 100644 index 0000000000..27c09c1f18 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationConstants.java @@ -0,0 +1,73 @@ +/* + * 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.tuscany.sca.implementation.spring; + +import javax.xml.namespace.QName; + +/** + * Constants used in Spring Application Context XML files. + */ +public interface SpringImplementationConstants { + + String SCA_NS = "http://www.springframework.org/schema/sca"; + String SPRING_NS = "http://www.springframework.org/schema/beans"; + + String PROPERTY = "property"; + QName SCA_PROPERTY_ELEMENT = new QName(SCA_NS, PROPERTY); + QName PROPERTY_ELEMENT = new QName(SPRING_NS, PROPERTY); + + String SCASERVICE = "service"; + QName SCA_SERVICE_ELEMENT = new QName(SCA_NS, SCASERVICE); + + String SCAREFERENCE = "reference"; + QName SCA_REFERENCE_ELEMENT = new QName(SCA_NS, SCAREFERENCE); + + String BEANS = "beans"; + QName BEANS_ELEMENT = new QName(SPRING_NS, BEANS); + + String IMPORT = "import"; + QName IMPORT_ELEMENT = new QName(SPRING_NS, IMPORT); + + String BEAN = "bean"; + QName BEAN_ELEMENT = new QName(SPRING_NS, BEAN); + + String CONSTRUCTORARG = "constructor-arg"; + QName CONSTRUCTORARG_ELEMENT = new QName(SPRING_NS, CONSTRUCTORARG); + + String LIST = "list"; + QName LIST_ELEMENT = new QName(SPRING_NS, LIST); + + String SET = "set"; + QName SET_ELEMENT = new QName(SPRING_NS, SET); + + String MAP = "map"; + QName MAP_ELEMENT = new QName(SPRING_NS, MAP); + + String VALUE = "value"; + QName VALUE_ELEMENT = new QName(SPRING_NS, VALUE); + + String REF = "ref"; + QName REF_ELEMENT = new QName(SPRING_NS, REF); + + String ENTRY = "entry"; + QName ENTRY_ELEMENT = new QName(SPRING_NS, ENTRY); + + String APPLICATION_CONTEXT = "application-context.xml"; +} diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringPropertyElement.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringPropertyElement.java new file mode 100644 index 0000000000..8de3a4cbe1 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringPropertyElement.java @@ -0,0 +1,71 @@ +/* + * 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.tuscany.sca.implementation.spring; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a <property> element in a Spring application-context + * - this has name and ref attributes + * + * @version $Rev$ $Date$ + */ +public class SpringPropertyElement { + + private String name; + private List<String> refs = new ArrayList<String>(); + private List<String> values = new ArrayList<String>(); + + public SpringPropertyElement() { + } + + public SpringPropertyElement(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public List<String> getRefs() { + return this.refs; + } + + public void addRef(String ref) { + this.refs.add(ref); + } + + public List<String> getValues() { + return this.values; + } + + public void addValue(String value) { + this.values.add(value); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SpringPropertyElement [name=").append(name).append(", refs=").append(refs).append(", values=") + .append(values).append("]"); + return builder.toString(); + } + +} // end class SpringPropertyElement diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAPropertyElement.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAPropertyElement.java new file mode 100644 index 0000000000..f27506f28b --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAPropertyElement.java @@ -0,0 +1,63 @@ +/* + * 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.tuscany.sca.implementation.spring; + +/** + * Represents an <sca:property> element in a Spring application-context + * - this has name and type attributes + * @version $Rev$ $Date$ + */ +public class SpringSCAPropertyElement { + + private String name; + private String type; + + public SpringSCAPropertyElement() { + super(); + } + + public SpringSCAPropertyElement(String name, String type) { + this.name = name; + this.type = type; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SpringSCAPropertyElement [name=").append(name).append(", type=").append(type).append("]"); + return builder.toString(); + } + +} // end class SpringPropertyElement diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAReferenceElement.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAReferenceElement.java new file mode 100644 index 0000000000..f06f05a46a --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAReferenceElement.java @@ -0,0 +1,106 @@ +/* + * 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.tuscany.sca.implementation.spring; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; + +/** + * Represents a <sca:reference> element in a Spring application-context + * - this has id and className attributes + * - plus zero or more property elements as children + * + * @version $Rev$ $Date$ + */ +public class SpringSCAReferenceElement { + + private String name; + private String type; + private String defaultBean; + private List<Intent> intents = new ArrayList<Intent>(); + private List<PolicySet> policySets = new ArrayList<PolicySet>(); + + private List<QName> intentNames = new ArrayList<QName>(); + private List<QName> policySetNames = new ArrayList<QName>(); + + public SpringSCAReferenceElement() { + + } + + public SpringSCAReferenceElement(String name, String type) { + this.name = name; + this.type = type; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public void setDefaultBean(String defaultBean) { + this.defaultBean = defaultBean; + } + + public String getDefaultBean() { + return defaultBean; + } + + public List<Intent> getRequiredIntents() { + return intents; + } + + public List<PolicySet> getPolicySets() { + return policySets; + } + + public List<QName> getIntentNames() { + return intentNames; + } + + public List<QName> getPolicySetNames() { + return policySetNames; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SpringSCAReferenceElement [name=").append(name).append(", type=").append(type) + .append(", defaultBean=").append(defaultBean).append(", intents=").append(intents).append(", policySets=") + .append(policySets).append(", intentNames=").append(intentNames).append(", policySetNames=") + .append(policySetNames).append("]"); + return builder.toString(); + } + +} // end class SpringSCAReferenceElement diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAServiceElement.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAServiceElement.java new file mode 100644 index 0000000000..38c124c3b4 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringSCAServiceElement.java @@ -0,0 +1,105 @@ +/* + * 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.tuscany.sca.implementation.spring; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; + +/** + * Represents a <sca:service> element in a Spring application-context + * - this has id and className attributes + * - plus zero or more property elements as children + * + * @version $Rev$ $Date$ + */ +public class SpringSCAServiceElement { + + private String name; + private String type; + private String target; + private List<Intent> intents = new ArrayList<Intent>(); + private List<PolicySet> policySets = new ArrayList<PolicySet>(); + private List<QName> intentNames = new ArrayList<QName>(); + private List<QName> policySetNames = new ArrayList<QName>(); + + public SpringSCAServiceElement() { + + } + + public SpringSCAServiceElement(String name, String target) { + this.name = name; + this.target = target; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public void setTarget(String target) { + this.target = target; + } + + public String getTarget() { + return target; + } + + public List<Intent> getRequiredIntents() { + return intents; + } + + public List<PolicySet> getPolicySets() { + return policySets; + } + + public List<QName> getIntentNames() { + return intentNames; + } + + public List<QName> getPolicySetNames() { + return policySetNames; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SpringSCAServiceElement [name=").append(name).append(", type=").append(type) + .append(", target=").append(target).append(", intents=").append(intents).append(", policySets=") + .append(policySets).append(", intentNames=").append(intentNames).append(", policySetNames=") + .append(policySetNames).append("]"); + return builder.toString(); + } + +} // end class SpringSCAServiceElement diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/introspect/SpringBeanIntrospector.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/introspect/SpringBeanIntrospector.java new file mode 100644 index 0000000000..5eaf27ab81 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/introspect/SpringBeanIntrospector.java @@ -0,0 +1,95 @@ +/* + * 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.tuscany.sca.implementation.spring.introspect; + +import java.util.List; + +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.contribution.processor.ContributionResolveException; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.spring.SpringConstructorArgElement; +import org.apache.tuscany.sca.implementation.spring.SpringImplementation; + +/** + * Provides introspection functions for Spring beans + * This version leans heavily on the implementation-java classes + * + * @version $Rev$ $Date$ + */ +public class SpringBeanIntrospector { + + private JavaImplementationFactory javaImplementationFactory; + + /** + * The constructor sets up the various visitor elements that will be used to introspect + * the Spring bean and extract SCA information. + * + * @param assemblyFactory The Assembly Factory to use + * @param javaFactory The Java Interface Factory to use + * @param policyFactory The Policy Factory to use. + */ + public SpringBeanIntrospector(ExtensionPointRegistry registry, List<SpringConstructorArgElement> conArgs) { + + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + javaImplementationFactory = factories.getFactory(JavaImplementationFactory.class); + } // end constructor + + /** + * Introspect a Spring Bean and extract the features important to SCA + * @param beanClass the Spring Bean class to introspect + * @param componentType the componentType that is filled in through the introspection + * process (assumed empty on invocation, filled on return + * @return a Map of property names to JavaElementImpl + * @throws ContributionResolveException - if there was a problem resolving the + * Spring Bean or its componentType + * + */ + public JavaImplementation introspectBean(Class<?> beanClass, ComponentType componentType) + throws ContributionResolveException { + if (componentType == null) + throw new ContributionResolveException("Introspect Spring bean: supplied componentType is null"); + + // Create a Java implementation ready for the introspection + JavaImplementation javaImplementation = javaImplementationFactory.createJavaImplementation(); + // Set the type to be implementation.spring to avoid heuristic introspection + javaImplementation.setType(SpringImplementation.TYPE); + + try { + // Introspect the bean...the results of the introspection are placed into the Java implementation + javaImplementationFactory.createJavaImplementation(javaImplementation, beanClass); + + // Extract the services, references & properties found through introspection + // put the services, references and properties into the component type + componentType.getServices().addAll(javaImplementation.getServices()); + componentType.getReferences().addAll(javaImplementation.getReferences()); + componentType.getProperties().addAll(javaImplementation.getProperties()); + + } catch (IntrospectionException e) { + throw new ContributionResolveException(e); + } // end try + + return javaImplementation; + + } // end method introspectBean + +} // end class SpringBeanIntrospector diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/introspect/SpringXMLComponentTypeLoader.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/introspect/SpringXMLComponentTypeLoader.java new file mode 100644 index 0000000000..cca7586734 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/introspect/SpringXMLComponentTypeLoader.java @@ -0,0 +1,985 @@ +/* + * 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.tuscany.sca.implementation.spring.introspect; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.contribution.Artifact; +import org.apache.tuscany.sca.contribution.ContributionFactory; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.resolver.ClassReference; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.implementation.java.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.spring.SpringBeanElement; +import org.apache.tuscany.sca.implementation.spring.SpringConstructorArgElement; +import org.apache.tuscany.sca.implementation.spring.SpringImplementation; +import org.apache.tuscany.sca.implementation.spring.SpringPropertyElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAPropertyElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAReferenceElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAServiceElement; +import org.apache.tuscany.sca.implementation.spring.xml.SpringXMLBeanDefinitionLoader; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicyFactory; +import org.apache.tuscany.sca.policy.PolicySet; + +/** + * Introspects a Spring XML application-context configuration file to create <implementation-spring../> + * component type information. + * + * @version $Rev$ $Date$ + */ +public class SpringXMLComponentTypeLoader { + private final static Logger log = Logger.getLogger(SpringXMLComponentTypeLoader.class.getName()); + + private ExtensionPointRegistry registry; + private ContributionFactory contributionFactory; + private AssemblyFactory assemblyFactory; + private PolicyFactory policyFactory; + private JavaInterfaceFactory javaFactory; + private SpringBeanIntrospector beanIntrospector; + + private SpringXMLBeanDefinitionLoader xmlBeanDefinitionLoader; + + public SpringXMLComponentTypeLoader(ExtensionPointRegistry registry) { + super(); + this.registry = registry; + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factories.getFactory(AssemblyFactory.class); + this.policyFactory = factories.getFactory(PolicyFactory.class); + this.javaFactory = factories.getFactory(JavaInterfaceFactory.class); + this.contributionFactory = factories.getFactory(ContributionFactory.class); + this.xmlBeanDefinitionLoader = + registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(SpringXMLBeanDefinitionLoader.class); + } + + /** + * Report a error. + * + * @param problems + * @param message + * @param model + */ + private void error(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + "impl-spring-validation-messages", + Severity.ERROR, + model, + message, + (Object[])messageParameters); + monitor.problem(problem); + } + } + /** + * Report a error. + * + * @param problems + * @param message + * @param model + */ + private void warning(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + "impl-spring-validation-messages", + Severity.WARNING, + model, + message, + (Object[])messageParameters); + monitor.problem(problem); + } + } + protected Class<SpringImplementation> getImplementationClass() { + return SpringImplementation.class; + } + + /** + * Base method which loads the component type from the application-context attached to the + * Spring implementation + * + */ + public void load(SpringImplementation implementation, ModelResolver resolver, ProcessorContext context) + throws ContributionReadException { + //System.out.println("Spring TypeLoader - load method start"); + ComponentType componentType = implementation.getComponentType(); + /* Check that there is a component type object already set */ + if (componentType == null) { + throw new ContributionReadException("SpringXMLLoader load: implementation has no ComponentType object"); + } + if (componentType.isUnresolved()) { + /* Fetch the location of the application-context file from the implementation */ + loadFromXML(implementation, resolver, context); + if (!componentType.isUnresolved()) + implementation.setUnresolved(false); + } // end if + //System.out.println("Spring TypeLoader - load method complete"); + } // end method load + + private Class<?> resolveClass(ModelResolver resolver, String className, ProcessorContext context) + throws ClassNotFoundException { + ClassReference classReference = new ClassReference(className); + classReference = resolver.resolveModel(ClassReference.class, classReference, context); + if (classReference.isUnresolved()) { + throw new ClassNotFoundException(className); + } + Class<?> javaClass = classReference.getJavaClass(); + return javaClass; + } + + /** + * Method which fills out the component type for a Spring implementation by reading the + * Spring application-context.xml file. + * + * @param implementation SpringImplementation into which to load the component type information + * @throws ContributionReadException Failed to read the contribution + */ + private void loadFromXML(SpringImplementation implementation, ModelResolver resolver, ProcessorContext context) + throws ContributionReadException { + List<SpringBeanElement> beans = new ArrayList<SpringBeanElement>(); + List<SpringSCAServiceElement> services = new ArrayList<SpringSCAServiceElement>(); + List<SpringSCAReferenceElement> references = new ArrayList<SpringSCAReferenceElement>(); + List<SpringSCAPropertyElement> scaproperties = new ArrayList<SpringSCAPropertyElement>(); + + URL resource; + List<URL> contextResources = new ArrayList<URL>(); + String contextPath = implementation.getLocation(); + + try { + resource = resolveLocation(resolver, contextPath, context); + contextResources = getApplicationContextResource(resource); + + implementation.setClassLoader(new ContextClassLoader(resolver, context)); + implementation.setResource(contextResources); + // The URI is used to uniquely identify the Implementation + implementation.setURI(resource.toString()); + + List<SpringBeanElement> appCxtBeans = new ArrayList<SpringBeanElement>(); + List<SpringSCAServiceElement> appCxtServices = new ArrayList<SpringSCAServiceElement>(); + List<SpringSCAReferenceElement> appCxtReferences = new ArrayList<SpringSCAReferenceElement>(); + List<SpringSCAPropertyElement> appCxtProperties = new ArrayList<SpringSCAPropertyElement>(); + + if (xmlBeanDefinitionLoader != null) { + xmlBeanDefinitionLoader.load(contextResources, + appCxtServices, + appCxtReferences, + appCxtProperties, + appCxtBeans, + context); + populatePolicies(appCxtServices, appCxtReferences); + } + // Validate the beans from individual application context for uniqueness + validateBeans(appCxtBeans, appCxtServices, appCxtReferences, appCxtProperties, context.getMonitor()); + // Add all the validated beans to the generic list + beans.addAll(appCxtBeans); + services.addAll(appCxtServices); + references.addAll(appCxtReferences); + scaproperties.addAll(appCxtProperties); + } catch (Throwable e) { + throw new ContributionReadException(e); + } + + /* At this point, the complete application-context.xml file has been read and its contents */ + /* stored in the lists of beans, services, references. These are now used to generate */ + /* the implied componentType for the application context */ + generateComponentType(implementation, resolver, beans, services, references, scaproperties, context); + + return; + } // end method loadFromXML + + public void populatePolicies(List<SpringSCAServiceElement> appCxtServices, + List<SpringSCAReferenceElement> appCxtReferences) { + for (SpringSCAReferenceElement e : appCxtReferences) { + for (QName qn : e.getIntentNames()) { + Intent intent = policyFactory.createIntent(); + intent.setName(qn); + e.getRequiredIntents().add(intent); + } + for (QName qn : e.getPolicySetNames()) { + PolicySet ps = policyFactory.createPolicySet(); + ps.setName(qn); + e.getPolicySets().add(ps); + } + } + + for (SpringSCAServiceElement e : appCxtServices) { + for (QName qn : e.getIntentNames()) { + Intent intent = policyFactory.createIntent(); + intent.setName(qn); + e.getRequiredIntents().add(intent); + } + for (QName qn : e.getPolicySetNames()) { + PolicySet ps = policyFactory.createPolicySet(); + ps.setName(qn); + e.getPolicySets().add(ps); + } + } + } + + private URL resolveLocation(ModelResolver resolver, String contextPath, ProcessorContext context) + throws MalformedURLException, ContributionReadException { + URL resource = null; + URI uri = URI.create(contextPath); + if (!uri.isAbsolute()) { + Artifact parent = context.getArtifact(); + if (parent != null && parent.getURI() != null) { + URI base = URI.create("/" + parent.getURI()); + uri = base.resolve(uri); + // Remove the leading / to make artifact resolver happy + if (uri.toString().startsWith("/")) { + uri = URI.create(uri.toString().substring(1)); + } + } + Artifact artifact = contributionFactory.createArtifact(); + artifact.setUnresolved(true); + artifact.setURI(uri.toString()); + artifact = resolver.resolveModel(Artifact.class, artifact, context); + if (!artifact.isUnresolved()) { + resource = new URL(artifact.getLocation()); + } else { + throw new ContributionReadException("Location cannot be resloved: " + contextPath); + } + } else { + resource = new URL(contextPath); + } + return resource; + } + + /** + * Generates the Spring implementation component type from the configuration contained in the + * lists of beans, services, references and scaproperties derived from the application context + */ + private void generateComponentType(SpringImplementation implementation, + ModelResolver resolver, + List<SpringBeanElement> beans, + List<SpringSCAServiceElement> services, + List<SpringSCAReferenceElement> references, + List<SpringSCAPropertyElement> scaproperties, + ProcessorContext context) throws ContributionReadException { + /* + * 1. Each sca:service becomes a service in the component type + * 2. Each sca:reference becomes a reference in the component type + * 3. Each sca:property becomes a property in the component type + * 4. IF there are no explicit service elements, each bean becomes a service + * 5. Each bean property which is a reference not pointing at another bean in the + * application context becomes a reference unless it is pointing at one of the references + * 6. Each bean property which is not a reference and which is not pointing + * at another bean in the application context becomes a property in the component type + */ + + JavaImplementation javaImplementation = null; + ComponentType componentType = implementation.getComponentType(); + + try { + // Deal with the services first.... + Iterator<SpringSCAServiceElement> its = services.iterator(); + while (its.hasNext()) { + SpringSCAServiceElement serviceElement = its.next(); + Class<?> interfaze = resolveClass(resolver, serviceElement.getType(), context); + Service theService = createService(interfaze, serviceElement.getName()); + // Spring allows duplication of bean definitions in multiple context scenario, + // in such cases, the latest bean definition overrides the older ones, hence + // we will remove any older definition and use the latest. + Service duplicate = null; + for (Service service : componentType.getServices()) { + if (service.getName().equals(theService.getName())) + duplicate = service; + } + if (duplicate != null) + componentType.getServices().remove(duplicate); + + componentType.getServices().add(theService); + // Add this service to the Service / Bean map + String beanName = serviceElement.getTarget(); + boolean found = false; + for (SpringBeanElement beanElement : beans) { + if (beanName.equals(beanElement.getId())) { + if (isValidBeanForService(beanElement)) { + // add the required intents and policySets for the service + theService.getRequiredIntents().addAll(serviceElement.getRequiredIntents()); + theService.getPolicySets().addAll(serviceElement.getPolicySets()); + implementation.setBeanForService(theService, beanElement); + found = true; + break; + } + } + } // end for + + if (!found) { + // REVIEW: Adding a SpringBeanElement "proxy" so that the bean id can be used at runtime to look + // up the bean instance from the parent context + implementation.setBeanForService(theService, + new SpringBeanElement(serviceElement.getTarget(), null)); + } + } // end while + + // Next handle the references + Iterator<SpringSCAReferenceElement> itr = references.iterator(); + while (itr.hasNext()) { + SpringSCAReferenceElement referenceElement = itr.next(); + Class<?> interfaze = resolveClass(resolver, referenceElement.getType(), context); + Reference theReference = createReference(interfaze, referenceElement.getName()); + // Override the older bean definition with the latest ones + // for the duplicate definitions found. + Reference duplicate = null; + for (Reference reference : componentType.getReferences()) { + if (reference.getName().equals(theReference.getName())) + duplicate = reference; + } + if (duplicate != null) + componentType.getReferences().remove(duplicate); + + // add the required intents and policySets for this reference + theReference.getRequiredIntents().addAll(referenceElement.getRequiredIntents()); + theReference.getPolicySets().addAll(referenceElement.getPolicySets()); + componentType.getReferences().add(theReference); + } // end while + + // Next handle the properties + Iterator<SpringSCAPropertyElement> itsp = scaproperties.iterator(); + while (itsp.hasNext()) { + SpringSCAPropertyElement scaproperty = itsp.next(); + // Create a component type property if the SCA property element has a name + // and a type declared... + if (scaproperty.getType() != null && scaproperty.getName() != null) { + Property theProperty = assemblyFactory.createProperty(); + theProperty.setName(scaproperty.getName()); + // Get the Java class and then an XSD element type for the property + Class<?> propType = Class.forName(scaproperty.getType()); + theProperty.setXSDType(JavaXMLMapper.getXMLType(propType)); + // Override the older bean definition with the latest ones + // for the duplicate definitions found. + Property duplicate = null; + for (Property property : componentType.getProperties()) { + if (property.getName().equals(theProperty.getName())) + duplicate = property; + } + if (duplicate != null) + componentType.getProperties().remove(duplicate); + + componentType.getProperties().add(theProperty); + // Remember the Java Class (ie the type) for this property + implementation.setPropertyClass(theProperty.getName(), propType); + } // end if + } // end while + + // Finally deal with the beans + Iterator<SpringBeanElement> itb; + // If there are no explicit service elements, then expose all the beans + if (services.isEmpty()) { + itb = beans.iterator(); + // Loop through all the beans found + while (itb.hasNext()) { + SpringBeanElement beanElement = itb.next(); + + // If its not a valid bean for service, ignore it + if (!isValidBeanForService(beanElement)) { + continue; + } + try { + // Load the Spring bean class + Class<?> beanClass = resolveClass(resolver, beanElement.getClassName(), context); + // Introspect the bean + beanIntrospector = new SpringBeanIntrospector(registry, beanElement.getCustructorArgs()); + ComponentType beanComponentType = assemblyFactory.createComponentType(); + javaImplementation = beanIntrospector.introspectBean(beanClass, beanComponentType); + // Set the service name as bean name + for (Service componentService : beanComponentType.getServices()) { + componentService.setName(beanElement.getId()); + } + // Get the service interface defined by this Spring Bean and add to + // the component type of the Spring Assembly + List<Service> beanServices = beanComponentType.getServices(); + componentType.getServices().addAll(beanServices); + // Add these services to the Service / Bean map + for (Service beanService : beanServices) { + implementation.setBeanForService(beanService, beanElement); + } + } catch (Throwable e) { + // [rfeng] FIXME: Some Spring beans have constructors that take pararemters injected by Spring and + // Tuscany is not happy with that during the introspection + log.log(Level.SEVERE, e.getMessage(), e); + } + } // end while + } // end if + + itb = beans.iterator(); + while (itb.hasNext()) { + SpringBeanElement beanElement = itb.next(); + + // If its not a valid bean for service, ignore it + if (!isValidBeanForService(beanElement)) { + continue; + } + // Ignore if the bean has no properties and constructor arguments + if (beanElement.getProperties().isEmpty() && beanElement.getCustructorArgs().isEmpty()) + continue; + + ComponentType beanComponentType = assemblyFactory.createComponentType(); + + try { + Class<?> beanClass = resolveClass(resolver, beanElement.getClassName(), context); + // Introspect the bean + beanIntrospector = new SpringBeanIntrospector(registry, beanElement.getCustructorArgs()); + javaImplementation = beanIntrospector.introspectBean(beanClass, beanComponentType); + } catch (Exception e) { + // [rfeng] FIXME: Some Spring beans have constructors that take pararemters injected by Spring and + // Tuscany is not happy with that during the introspection + log.log(Level.SEVERE, e.getMessage(), e); + continue; + } + Map<String, JavaElementImpl> propertyMap = javaImplementation.getPropertyMembers(); + JavaConstructorImpl constructor = javaImplementation.getConstructor(); + // Get the references by this Spring Bean and add the unresolved ones to + // the component type of the Spring Assembly + List<Reference> beanReferences = beanComponentType.getReferences(); + List<Property> beanProperties = beanComponentType.getProperties(); + + Set<String> excludedNames = new HashSet<String>(); + Iterator<SpringPropertyElement> itp = beanElement.getProperties().iterator(); + while (itp.hasNext()) { + SpringPropertyElement propertyElement = itp.next(); + // Exclude the reference that is also known as a spring property + excludedNames.add(propertyElement.getName()); + for (String propertyRef : propertyElement.getRefs()) { + if (propertyRefUnresolved(propertyRef, beans, references, scaproperties)) { + // This means an unresolved reference from the spring bean... + for (Reference reference : beanReferences) { + if (propertyElement.getName().equals(reference.getName())) { + // The name of the reference in this case is the string in + // the @ref attribute of the Spring property element, NOT the + // name of the field in the Spring bean.... + reference.setName(propertyRef); + componentType.getReferences().add(reference); + break; + } // end if + } // end for + + // Store the unresolved references as unresolvedBeanRef in the Spring Implementation type + for (Property scaproperty : beanProperties) { + if (propertyElement.getName().equals(scaproperty.getName())) { + // The name of the reference in this case is the string in + // the @ref attribute of the Spring property element, NOT the + // name of the field in the Spring bean.... + Class<?> interfaze = + resolveClass(resolver, + (propertyMap.get(propertyElement.getName()).getType()).getName(), + context); + Reference theReference = createReference(interfaze, propertyRef); + implementation.setUnresolvedBeanRef(propertyRef, theReference); + break; + } // end if + } // end for + } // end if + } // end for + } // end while + + Iterator<SpringConstructorArgElement> itcr = beanElement.getCustructorArgs().iterator(); + while (itcr.hasNext()) { + SpringConstructorArgElement conArgElement = itcr.next(); + for (String constructorArgRef : conArgElement.getRefs()) { + if (propertyRefUnresolved(constructorArgRef, beans, references, scaproperties)) { + for (JavaParameterImpl parameter : constructor.getParameters()) { + String paramType = parameter.getType().getName(); + Class<?> interfaze = resolveClass(resolver, paramType, context); + // Create a component type reference/property if the constructor-arg element has a + // type attribute OR index attribute declared... + if ((conArgElement.getType() != null && paramType.equals(conArgElement.getType())) || (conArgElement + .getIndex() != -1 && (conArgElement.getIndex() == parameter.getIndex()))) { + // [rfeng] Commenting out the following code as the constructor parameter based SCA + // references are added already + /* + if (parameter.getClassifer() == org.oasisopen.sca.annotation.Reference.class) { + Reference theReference = createReference(interfaze, constructorArgRef); + componentType.getReferences().add(theReference); + } + */ + if (parameter.getClassifer() == org.oasisopen.sca.annotation.Property.class) { + // Store the unresolved references as unresolvedBeanRef in the Spring Implementation type + // we might need to verify with the component definition later. + Reference theReference = createReference(interfaze, constructorArgRef); + implementation.setUnresolvedBeanRef(constructorArgRef, theReference); + } + } + } // end for + } // end if + } // end for + } // end while + + // [rfeng] Add the remaining introspected references (w/ @Reference but without Spring property ref) + for (Reference ref : beanReferences) { + if (!excludedNames.contains(ref.getName()) && componentType.getReference(ref.getName()) == null) { + // Only add the ones that not listed by sca:reference + componentType.getReferences().add(ref); + } + } + + } // end while + + } catch (ClassNotFoundException e) { + // Means that either an interface class, property class or a bean was not found + throw new ContributionReadException(e); + } catch (InvalidInterfaceException e) { + throw new ContributionReadException(e); + } // end try + + // If we get here, the Spring assembly component type is resolved + componentType.setUnresolved(false); + implementation.setComponentType(componentType); + return; + } // end method generateComponentType + + /* + * Determines whether a reference attribute of a Spring property element is resolved either + * by a bean in the application context or by an SCA reference element or by an SCA property + * element + * @param ref - a String containing the name of the reference - may be null + * @param beans - a List of SpringBean elements + * @param references - a List of SCA reference elements + * @return true if the property is not resolved, false if it is resolved + */ + private boolean propertyRefUnresolved(String ref, + List<SpringBeanElement> beans, + List<SpringSCAReferenceElement> references, + List<SpringSCAPropertyElement> scaproperties) { + boolean unresolved = true; + + if (ref != null) { + // Scan over the beans looking for a match + Iterator<SpringBeanElement> itb = beans.iterator(); + while (itb.hasNext()) { + SpringBeanElement beanElement = itb.next(); + // Does the bean name match the ref? + if (ref.equals(beanElement.getId())) { + unresolved = false; + break; + } // end if + } // end while + // Scan over the SCA reference elements looking for a match + if (unresolved) { + Iterator<SpringSCAReferenceElement> itr = references.iterator(); + while (itr.hasNext()) { + SpringSCAReferenceElement referenceElement = itr.next(); + if (ref.equals(referenceElement.getName())) { + unresolved = false; + break; + } // end if + } // end while + } // end if + // Scan over the SCA property elements looking for a match + if (unresolved) { + Iterator<SpringSCAPropertyElement> itsp = scaproperties.iterator(); + while (itsp.hasNext()) { + SpringSCAPropertyElement propertyElement = itsp.next(); + if (ref.equals(propertyElement.getName())) { + unresolved = false; + break; + } // end if + } // end while + } // end if + } else { + // In the case where ref = null, the property is not going to be a reference of any + // kind and can be ignored + unresolved = false; + } // end if + + return unresolved; + + } // end method propertyRefUnresolved + + /** + * Validates whether the <sca:service>, <sca:reference> and <sca:property> elements + * has unique names within the application context. + */ + private void validateBeans(List<SpringBeanElement> beans, + List<SpringSCAServiceElement> services, + List<SpringSCAReferenceElement> references, + List<SpringSCAPropertyElement> scaproperties, + Monitor monitor) throws ContributionReadException { + + // The @target attribute of a <service/> subelement of a <beans/> element + // MUST have the value of the @name attribute of one of the <bean/> + // subelements of the <beans/> element. + Iterator<SpringSCAServiceElement> its = services.iterator(); + while (its.hasNext()) { + SpringSCAServiceElement serviceElement = its.next(); + boolean targetBeanExists = false; + Iterator<SpringBeanElement> itb = beans.iterator(); + while (itb.hasNext()) { + SpringBeanElement beanElement = itb.next(); + if (serviceElement.getTarget().equals(beanElement.getId())) + targetBeanExists = true; + } + if (!targetBeanExists) { + // REVIEW: [rfeng] The target bean can exist in the parent Spring application context which we don't know + // until runtime + warning(monitor, "TargetBeanDoesNotExist", beans); + } + } // end while + + // The value of the @name attribute of an <sca:reference/> subelement of a <beans/> + // element MUST be unique amongst the @name attributes of the <sca:property/> + // subelements and the <bean/> subelements of the <beans/> element. + // AND + // The @default attribute of a <sca:reference/> subelement of a <beans/> + // element MUST have the value of the @name attribute of one of the <bean/> + // subelements of the <beans/> element. + Iterator<SpringSCAReferenceElement> itr = references.iterator(); + while (itr.hasNext()) { + SpringSCAReferenceElement referenceElement = itr.next(); + boolean defaultBeanExists = true; + boolean isUniqueReferenceName = true; + Iterator<SpringBeanElement> itb = beans.iterator(); + while (itb.hasNext()) { + SpringBeanElement beanElement = itb.next(); + if (referenceElement.getDefaultBean() != null) + if (referenceElement.getDefaultBean().equals(beanElement.getId())) + defaultBeanExists = false; + if (referenceElement.getName().equals(beanElement.getId())) + isUniqueReferenceName = false; + } + Iterator<SpringSCAPropertyElement> itp = scaproperties.iterator(); + while (itp.hasNext()) { + SpringSCAPropertyElement propertyElement = itp.next(); + if (referenceElement.getName().equals(propertyElement.getName())) + isUniqueReferenceName = false; + } + if (!defaultBeanExists) + error(monitor, "DefaultBeanDoesNotExist", beans); + if (!isUniqueReferenceName) + error(monitor, "ScaReferenceNameNotUnique", beans); + } // end while + + // The value of the @name attribute of an <sca:property/> subelement of a <beans/> + // element MUST be unique amongst the @name attributes of the <sca:reference/> + // subelements and the <bean/> subelements of the <beans/> element. + Iterator<SpringSCAPropertyElement> itp = scaproperties.iterator(); + while (itp.hasNext()) { + SpringSCAPropertyElement propertyElement = itp.next(); + boolean isUniquePropertyName = true; + Iterator<SpringBeanElement> itb = beans.iterator(); + while (itb.hasNext()) { + SpringBeanElement beanElement = itb.next(); + if (propertyElement.getName().equals(beanElement.getId())) + isUniquePropertyName = false; + } + Iterator<SpringSCAReferenceElement> itrp = references.iterator(); + while (itrp.hasNext()) { + SpringSCAReferenceElement referenceElement = itrp.next(); + if (propertyElement.getName().equals(referenceElement.getName())) + isUniquePropertyName = false; + } + if (!isUniquePropertyName) + error(monitor, "ScaPropertyNameNotUnique", beans); + } // end while + } + + /** + * Validates whether a bean definition is valid for exposing as service. + */ + private boolean isValidBeanForService(SpringBeanElement beanElement) { + + if (beanElement.isInnerBean()) + return false; + if (beanElement.hasParentAttribute()) + return false; + if (beanElement.hasFactoryMethodAttribute()) + return false; + if (beanElement.hasFactoryBeanAttribute()) + return false; + if (beanElement.getClassName() == null) + return false; + if (beanElement.getClassName().startsWith("org.springframework")) + return false; + // return true otherwise + return true; + } + + /** + * Gets hold of the application-context.xml file as a Spring resource + * @param locationAttr - the location attribute from the <implementation.spring../> element + * @param cl - the ClassLoader for the Spring implementation + */ + protected List<URL> getApplicationContextResource(URL url) throws ContributionReadException { + File manifestFile = null; + File appXmlFile; + File appXmlFolder; + File locationFile = null; + List<URL> appCtxResources = new ArrayList<URL>(); + + if (url != null) { + String path = url.getPath(); + locationFile = new File(path); + } else { + throw new ContributionReadException( + "SpringXMLComponentTypeLoader getApplicationContextResource: " + "unable to find resource file " + + url); + } + + if (locationFile.isDirectory()) { + try { + manifestFile = new File(locationFile, "META-INF" + File.separator + "MANIFEST.MF"); + if (manifestFile.exists()) { + Manifest mf = new Manifest(new FileInputStream(manifestFile)); + Attributes mainAttrs = mf.getMainAttributes(); + String appCtxPath = mainAttrs.getValue("Spring-Context"); + if (appCtxPath != null) { + String[] cxtPaths = appCtxPath.split(";"); + for (String path : cxtPaths) { + appXmlFile = new File(locationFile, path.trim()); + if (appXmlFile.exists()) { + appCtxResources.add(appXmlFile.toURI().toURL()); + } + } + return appCtxResources; + } + } + // No MANIFEST.MF file OR no manifest-specified Spring context , then read all the + // xml files available in the META-INF/spring folder. + appXmlFolder = new File(locationFile, "META-INF" + File.separator + "spring"); + if (appXmlFolder.exists()) { + File[] files = appXmlFolder.listFiles(); + for (File appFile : files) { + if (appFile.getName().endsWith(".xml")) { + appCtxResources.add(appFile.toURI().toURL()); + } + } + return appCtxResources; + } + } catch (IOException e) { + throw new ContributionReadException("Error reading manifest " + manifestFile); + } + } else { + if (locationFile.isFile() && locationFile.getName().endsWith(".jar")) { + try { + JarFile jf = new JarFile(locationFile); + JarEntry je; + Manifest mf = jf.getManifest(); + if (mf != null) { + Attributes mainAttrs = mf.getMainAttributes(); + String appCtxPath = mainAttrs.getValue("Spring-Context"); + if (appCtxPath != null) { + String[] cxtPaths = appCtxPath.split(";"); + for (String path : cxtPaths) { + je = jf.getJarEntry(path.trim()); + if (je != null) + appCtxResources.add(new URL("jar:" + locationFile.toURI().toURL() + + "!/" + + appCtxPath)); + } + return appCtxResources; + } + } + // No MANIFEST.MF file OR no manifest-specified Spring context , then read all the + // .xml files available in the META-INF/spring folder. + Enumeration<JarEntry> entries = jf.entries(); + while (entries.hasMoreElements()) { + je = entries.nextElement(); + if (je.getName().startsWith("META-INF/spring/") && je.getName().endsWith(".xml")) { + appCtxResources.add(new URL("jar:" + locationFile.toURI().toURL() + "!/" + je.getName())); + } + } + return appCtxResources; + } catch (IOException e) { + // TODO: create a more appropriate exception type + throw new ContributionReadException( + "SpringXMLComponentTypeLoader getApplicationContextResource: " + " IO exception reading context file.", + e); + } + } else { + if (locationFile.getName().endsWith(".xml")) { + appCtxResources.add(url); + return appCtxResources; + } else { + // Deal with the directory inside a jar file, in case the contribution itself is a JAR file. + try { + if (locationFile.getPath().indexOf(".jar") > 0) { + String jarPath = url.getPath().substring(5, url.getPath().indexOf("!")); + JarFile jf = new JarFile(jarPath); + JarEntry je = + jf.getJarEntry(url.getPath().substring(url.getPath().indexOf("!/") + 2) + "/" + + "META-INF" + + "/" + + "MANIFEST.MF"); + if (je != null) { + Manifest mf = new Manifest(jf.getInputStream(je)); + Attributes mainAttrs = mf.getMainAttributes(); + String appCtxPath = mainAttrs.getValue("Spring-Context"); + if (appCtxPath != null) { + String[] cxtPaths = appCtxPath.split(";"); + for (String path : cxtPaths) { + je = + jf.getJarEntry(url.getPath().substring(url.getPath().indexOf("!/") + 2) + "/" + + path.trim()); + if (je != null) { + appCtxResources.add(new URL("jar:" + url.getPath() + "/" + path.trim())); + } + } + return appCtxResources; + } + } + // No MANIFEST.MF file OR no manifest-specified Spring context , then read all the + // .xml files available in the META-INF/spring folder. + Enumeration<JarEntry> entries = jf.entries(); + while (entries.hasMoreElements()) { + je = entries.nextElement(); + if (je.getName().startsWith("META-INF/spring/") && je.getName().endsWith(".xml")) { + appCtxResources.add(new URL("jar:" + url.getPath() + "/" + je.getName())); + } + } + return appCtxResources; + } + } catch (IOException e) { + throw new ContributionReadException("Error reading manifest " + manifestFile); + } + } + } + } + + throw new ContributionReadException( + "SpringXMLComponentTypeLoader getApplicationContextResource: " + "unable to read resource file " + + url); + } // end method getApplicationContextResource + + /** + * Creates a Service for the component type based on its name and Java interface + */ + public Service createService(Class<?> interfaze, String name) throws InvalidInterfaceException { + Service service = assemblyFactory.createService(); + JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); + service.setInterfaceContract(interfaceContract); + + // Set the name for the service + service.setName(name); + + // Set the call interface and, if present, the callback interface + JavaInterface callInterface = javaFactory.createJavaInterface(interfaze); + service.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); + service.getInterfaceContract().setCallbackInterface(callbackInterface); + } + return service; + } // end method createService + + /** + * Creates a Reference for the component type based on its name and Java interface + */ + private org.apache.tuscany.sca.assembly.Reference createReference(Class<?> interfaze, String name) + throws InvalidInterfaceException { + org.apache.tuscany.sca.assembly.Reference reference = assemblyFactory.createReference(); + JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); + reference.setInterfaceContract(interfaceContract); + + // Set the name of the reference to the supplied name and the multiplicity of the reference + // to 1..1 - for Spring implementations, this is the only multiplicity supported + reference.setName(name); + reference.setMultiplicity(Multiplicity.ONE_ONE); + + // Set the call interface and, if present, the callback interface + JavaInterface callInterface = javaFactory.createJavaInterface(interfaze); + reference.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); + reference.getInterfaceContract().setCallbackInterface(callbackInterface); + } + + return reference; + } + + private class ContextClassLoader extends ClassLoader { + public ContextClassLoader(ModelResolver resolver, ProcessorContext context) { + super(); + this.resolver = resolver; + this.context = context; + } + + private ModelResolver resolver; + private ProcessorContext context; + + @Override + protected Class<?> findClass(String name) throws ClassNotFoundException { + return SpringXMLComponentTypeLoader.this.resolveClass(resolver, name, context); + } + + @Override + protected URL findResource(String name) { + try { + return resolveLocation(resolver, name, context); + } catch (Exception e) { + return null; + } + } + + @Override + protected Enumeration<URL> findResources(String name) throws IOException { + URL url = findResource(name); + if (url != null) { + return Collections.enumeration(Arrays.asList(url)); + } else { + Collection<URL> urls = Collections.emptyList(); + return Collections.enumeration(urls); + } + } + } +} // end class SpringXMLComponentTypeLoader diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringImplementationProcessor.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringImplementationProcessor.java new file mode 100644 index 0000000000..4b4144f0c8 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringImplementationProcessor.java @@ -0,0 +1,244 @@ +/* + * 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.tuscany.sca.implementation.spring.xml; + +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.xml.Constants; +import org.apache.tuscany.sca.assembly.xml.PolicySubjectProcessor; +import org.apache.tuscany.sca.contribution.processor.BaseStAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ContributionResolveException; +import org.apache.tuscany.sca.contribution.processor.ContributionWriteException; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.implementation.spring.SpringImplementation; +import org.apache.tuscany.sca.implementation.spring.introspect.SpringXMLComponentTypeLoader; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; + +/** + * SpringArtifactProcessor is responsible for processing the XML of an <implementation.spring.../> + * element in an SCA SCDL file. + * + * @version $Rev$ $Date$ + */ +public class SpringImplementationProcessor extends BaseStAXArtifactProcessor implements + StAXArtifactProcessor<SpringImplementation> { + + private static final String LOCATION = "location"; + private static final String IMPLEMENTATION_SPRING = "implementation.spring"; + private static final QName IMPLEMENTATION_SPRING_QNAME = new QName(Constants.SCA11_NS, IMPLEMENTATION_SPRING); + private static final String MSG_LOCATION_MISSING = "Reading implementation.spring - location attribute missing"; + + private ExtensionPointRegistry registry; + private AssemblyFactory assemblyFactory; + private PolicySubjectProcessor policyProcessor; + + private FactoryExtensionPoint factories; + + public SpringImplementationProcessor(ExtensionPointRegistry registry) { + this.registry = registry; + this.factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factories.getFactory(AssemblyFactory.class); + this.policyProcessor = new PolicySubjectProcessor(registry); + } + + /** + * Report a exception. + * + * @param problems + * @param message + * @param model + */ + private void error(Monitor monitor, String message, Object model, Exception ex) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + "impl-spring-validation-messages", + Severity.ERROR, + model, + message, + ex); + monitor.problem(problem); + } + } + + /** + * Report a error. + * + * @param problems + * @param message + * @param model + */ + private void error(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + "impl-spring-validation-messages", + Severity.ERROR, + model, + message, + (Object[])messageParameters); + monitor.problem(problem); + } + } + + /* + * Read the XML and parse out the attributes. + * + * <implementation.spring.../> has a single required attribute: + * "location" - which is the target URI of of an archive file or a directory that contains the Spring + * application context files. + * If the resource identified by the location attribute is an archive file, then the file + * META-INF/MANIFEST.MF is read from the archive. + * If the location URI identifies a directory, then META-INF/MANIFEST.MF must exist + * underneath that directory. + * If the manifest file contains a header "Spring-Context" of the format: + * Spring-Context ::= path ( ';' path )* + * + * Where path is a relative path with respect to the location URI, then the set of paths + * specified in the header identify the context configuration files. + * If there is no MANIFEST.MF file or no Spring-Context header within that file, + * then the default behaviour is to build an application context using all the *.xml files + * in the META-INF/spring directory. + */ + public SpringImplementation read(XMLStreamReader reader, ProcessorContext context) + throws ContributionReadException, XMLStreamException { + + // Create the Spring implementation + SpringImplementation springImplementation = null; + + // Read the location attribute for the spring implementation + String springLocation = getURIString(reader, LOCATION); + if (springLocation != null) { + springImplementation = new SpringImplementation(); + springImplementation.setLocation(springLocation); + springImplementation.setUnresolved(true); + processComponentType(springImplementation); + } else { + error(context.getMonitor(), "LocationAttributeMissing", reader); + //throw new ContributionReadException(MSG_LOCATION_MISSING); + } + + // Read policies + policyProcessor.readPolicies(springImplementation, reader); + + // Skip to end element + while (reader.hasNext()) { + if (reader.next() == END_ELEMENT && IMPLEMENTATION_SPRING_QNAME.equals(reader.getName())) { + break; + } + } // end while + + return springImplementation; + } // end read + + /* + * Handles the component type for the Spring implementation + * @param springImplementation - a Spring implementation. The component type information + * is created for this implementation + * + */ + private void processComponentType(SpringImplementation springImplementation) { + + // Create a ComponentType and mark it unresolved + ComponentType componentType = assemblyFactory.createComponentType(); + componentType.setUnresolved(true); + springImplementation.setComponentType(componentType); + } // end processComponentType + + /* + * Write out the XML representation of the Spring implementation + * <implementation.spring location="..." /> + */ + public void write(SpringImplementation springImplementation, XMLStreamWriter writer, ProcessorContext context) + throws ContributionWriteException, XMLStreamException { + + // Write <implementation.spring> + writer.writeStartElement(Constants.SCA11_NS, IMPLEMENTATION_SPRING); + policyProcessor.writePolicyAttributes(springImplementation, writer); + + if (springImplementation.getLocation() != null) { + writer.writeAttribute(LOCATION, springImplementation.getLocation()); + } + + writer.writeEndElement(); + + } // end write + + /** + * Resolves the Spring implementation - loads the Spring application-context XML and + * derives the spring implementation componentType from it + */ + public void resolve(SpringImplementation springImplementation, ModelResolver resolver, ProcessorContext context) + throws ContributionResolveException { + + if (springImplementation == null) + return; + + Monitor monitor = context.getMonitor(); + /* Load the Spring component type by reading the Spring application context */ + SpringXMLComponentTypeLoader springLoader = new SpringXMLComponentTypeLoader(registry); + try { + // Load the Spring Implementation information from its application context file... + springLoader.load(springImplementation, resolver, context); + } catch (ContributionReadException e) { + ContributionResolveException ce = new ContributionResolveException(e); + error(monitor, "ContributionResolveException", resolver, ce); + throw ce; + } + + ComponentType ct = springImplementation.getComponentType(); + if (ct.isUnresolved()) { + // If the introspection fails to resolve, try to find a side file... + ComponentType componentType = resolver.resolveModel(ComponentType.class, ct, context); + if (componentType.isUnresolved()) { + error(monitor, "UnableToResolveComponentType", resolver); + //throw new ContributionResolveException("SpringArtifactProcessor: unable to resolve componentType for Spring component"); + } else { + springImplementation.setComponentType(componentType); + springImplementation.setUnresolved(false); + } + + } // end if + + } // end method resolve + + public QName getArtifactType() { + return IMPLEMENTATION_SPRING_QNAME; + } + + public Class<SpringImplementation> getModelType() { + return SpringImplementation.class; + } + +} // end class SpringArtifactProcessor diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLBeanDefinitionLoader.java b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLBeanDefinitionLoader.java new file mode 100644 index 0000000000..a3dc353ffc --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLBeanDefinitionLoader.java @@ -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.tuscany.sca.implementation.spring.xml; + +import java.net.URL; +import java.util.List; + +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.implementation.spring.SpringBeanElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAPropertyElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAReferenceElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAServiceElement; + +/** + * The utility interface to load Spring XML bean definitions into an application context + */ +public interface SpringXMLBeanDefinitionLoader { + /** + * @param resources + * @param serviceElements + * @param referenceElements + * @param propertyElements + * @param beanElements + * @param context + * @return + */ + Object load(List<URL> resources, + List<SpringSCAServiceElement> serviceElements, + List<SpringSCAReferenceElement> referenceElements, + List<SpringSCAPropertyElement> propertyElements, + List<SpringBeanElement> beanElements, + ProcessorContext context); +} diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.builder.ImplementationBuilder b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.builder.ImplementationBuilder new file mode 100644 index 0000000000..7ea615051e --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.builder.ImplementationBuilder @@ -0,0 +1,18 @@ +# 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.
+org.apache.tuscany.sca.implementation.spring.SpringImplementationBuilder;qname=http://docs.oasis-open.org/ns/opencsa/sca/200912#implementation.spring
+
diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor new file mode 100644 index 0000000000..880d6fade0 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor @@ -0,0 +1,20 @@ +# 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.
+
+# Implementation class for the artifact processor extension
+org.apache.tuscany.sca.implementation.spring.xml.SpringImplementationProcessor;qname=http://docs.oasis-open.org/ns/opencsa/sca/200912#implementation.spring,model=org.apache.tuscany.sca.implementation.spring.SpringImplementation
+
diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.definitions.xml.Definitions b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.definitions.xml.Definitions new file mode 100644 index 0000000000..4a9270d094 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.definitions.xml.Definitions @@ -0,0 +1,17 @@ +# 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.
+org/apache/tuscany/sca/implementation/spring/definitions.xml
diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/impl-spring-validation-messages.properties b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/impl-spring-validation-messages.properties new file mode 100644 index 0000000000..28bd31ca11 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/impl-spring-validation-messages.properties @@ -0,0 +1,28 @@ +# +# +# 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. +# +# +LocationAttributeMissing = Reading implementation.spring - location attribute missing +ContributionResolveException = ContributionResolveException occured due to: +UnableToResolveComponentType = SpringArtifactProcessor: unable to resolve componentType for Spring component +ScaServiceNameNotUnique = The value of the @name attribute of an <sca:service/> element MUST be unique amongst the <sca:service/> subelements of the <beans/> element +ScaReferenceNameNotUnique = The value of the @name attribute of an <sca:reference/> element MUST be unique amongst the <sca:reference/> subelements of the <beans/> element +ScaPropertyNameNotUnique = The value of the @name attribute of an <sca:property/> element MUST be unique amongst the <sca:property/> subelements of the <beans/> element +DefaultBeanDoesNotExist = The @default attribute of a <sca:reference/> element MUST have the value of the @name attribute of one of the <bean/> subelements of the <beans/> element. +TargetBeanDoesNotExist = The @target attribute of a <sca:service/> element MUST have the value of the @name attribute of one of the <bean/> subelements of the <beans/> element. diff --git a/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/org/apache/tuscany/sca/implementation/spring/definitions.xml b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/org/apache/tuscany/sca/implementation/spring/definitions.xml new file mode 100644 index 0000000000..18e7b1e60a --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/implementation-spring/src/main/resources/org/apache/tuscany/sca/implementation/spring/definitions.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> + +<!-- $Rev$ $Date$ --> + +<sca:definitions xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" + xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912" + xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"> + + <sca:implementationType type="sca:implementation.spring" mayProvide="" alwaysProvides=""/> + + </sca:definitions> |