diff options
author | antelder <antelder@13f79535-47bb-0310-9956-ffa450edef68> | 2009-02-05 07:55:03 +0000 |
---|---|---|
committer | antelder <antelder@13f79535-47bb-0310-9956-ffa450edef68> | 2009-02-05 07:55:03 +0000 |
commit | ebb89430400c2cb1d1c74ca18927375ff41601cc (patch) | |
tree | 64b8495da5bc316b6711834f604c2490f556901b /java/sca-contrib/modules/implementation-spring/src | |
parent | 7e3c616f4404088bfdd5b2aefe30291c12486ddd (diff) |
Move the contrib folder out of the sca trunk build as discussed on the ML
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@741038 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/sca-contrib/modules/implementation-spring/src')
22 files changed, 2516 insertions, 0 deletions
diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringBeanNotFoundException.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringBeanNotFoundException.java new file mode 100644 index 0000000000..35df76fabc --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringBeanNotFoundException.java @@ -0,0 +1,39 @@ +/* + * 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; + +/** + * @version $Rev$ $Date$ + */ +public class SpringBeanNotFoundException extends Exception { + + private static final long serialVersionUID = -1157790036638157553L; + + public SpringBeanNotFoundException(String msg) { + super(msg); + } + + public SpringBeanNotFoundException(Throwable e) { + super(e); + } + + public SpringBeanNotFoundException(String msg, Throwable e) { + super(msg,e); + } +} diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java new file mode 100644 index 0000000000..8bf3e5ed3c --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java @@ -0,0 +1,187 @@ +/* + * 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.lang.reflect.Method; +import java.util.Hashtable; +import java.util.List; + +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.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.spring.xml.SpringBeanElement; +import org.apache.tuscany.sca.policy.util.PolicyHandlerTuple; +import org.springframework.core.io.Resource; + +/** + * Represents a Spring implementation. + * + * @version $Rev: 511195 $ $Date: 2007-02-24 02:29:46 +0000 (Sat, 24 Feb 2007) $ + */ +public class SpringImplementation extends ImplementationImpl implements Implementation, Extensible { + + /** The location attribute which points to the Spring application-context XML file **/ + private String location; + /** The application-context file as a Spring Resource **/ + private Resource resource; + /** **/ + private ComponentType componentType; + /** Mapping of Services to Beans **/ + private Hashtable<String, SpringBeanElement> serviceMap; + /** Mapping of property names to Java class **/ + private Hashtable<String, Class> propertyMap; + private List<PolicyHandlerTuple> policyHandlerClassNames = null; + + // Method marked with @Init annotation + private Method initMethod = null; + // Method marked with @Destroy annotation + private Method destroyMethod = null; + // Method marked with @Constructor annotation + private JavaConstructorImpl<?> constructorDefinition = null; + + public SpringImplementation() { + this.location = null; + this.resource = null; + setUnresolved(true); + serviceMap = new Hashtable<String, SpringBeanElement>(); + propertyMap = new Hashtable<String, Class>(); + } + + + /** + * Returns the location attribute for this Spring implementation + * @return URI for the location of the Spring implementation + */ + public String getLocation() { + return location; + } + + /** + * Sets the location attribute for this Spring implementation + * @param location a URI to the Spring application-context file + */ + public void setLocation(String location) { + this.location = location; + return; + } + + /** + * + * @param resource + */ + public void setResource(Resource resource) { + this.resource = resource; + } + + /** + * + * @return + */ + public Resource getResource() { + return resource; + } + + public JavaConstructorImpl<?> getConstructor() { + return constructorDefinition; + } + + /** + * Returns the componentType for this Spring implementation + * @return + */ + public ComponentType getComponentType() { + return componentType; + } + + /** + * Sets the componentType for this Spring implementation + * @param componentType + */ + public void setComponentType(ComponentType componentType) { + this.componentType = componentType; + } + + /** + * 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; + } + + /** + * 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); + } + + @Override + public List<Service> getServices() { + return componentType.getServices(); + } + + @Override + public List<Reference> getReferences() { + return componentType.getReferences(); + } + + @Override + public List<Property> getProperties() { + return componentType.getProperties(); + } + + public List<PolicyHandlerTuple> getPolicyHandlerClassNames() { + return policyHandlerClassNames; + } + + public void setPolicyHandlerClassNames(List<PolicyHandlerTuple> policyHandlerClassNames) { + this.policyHandlerClassNames = policyHandlerClassNames; + } // end method setPolicyHandlerClassNames +} diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProcessor.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProcessor.java new file mode 100644 index 0000000000..1b6ba953c7 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProcessor.java @@ -0,0 +1,232 @@ +/* + * 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 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.PolicyAttachPointProcessor; +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.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.spring.xml.SpringXMLComponentTypeLoader; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +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.PolicyFactory; + +/** + * SpringArtifactProcessor is responsible for processing the XML of an <implementation.spring.../> + * element in an SCA SCDL file. + * + * @version $Rev: 511195 $ $Date: 2007-02-24 02:29:46 +0000 (Sat, 24 Feb 2007) $ + */ +public class SpringImplementationProcessor 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.SCA10_NS, IMPLEMENTATION_SPRING); + private static final String MSG_LOCATION_MISSING = "Reading implementation.spring - location attribute missing"; + + private AssemblyFactory assemblyFactory; + private JavaInterfaceFactory javaFactory; + private JavaImplementationFactory javaImplementationFactory; + private PolicyFactory policyFactory; + private PolicyAttachPointProcessor policyProcessor; + private Monitor monitor; + + public SpringImplementationProcessor(FactoryExtensionPoint modelFactories, Monitor monitor) { + this.assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + this.javaFactory = modelFactories.getFactory(JavaInterfaceFactory.class); + this.javaImplementationFactory = modelFactories.getFactory(JavaImplementationFactory.class); + this.policyFactory = modelFactories.getFactory(PolicyFactory.class); + this.policyProcessor = new PolicyAttachPointProcessor(policyFactory); + this.monitor = monitor; + } + + /** + * Report a exception. + * + * @param problems + * @param message + * @param model + */ + private void error(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(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 METAINF/spring directory. + */ + public SpringImplementation read(XMLStreamReader reader) throws ContributionReadException, XMLStreamException { + + // Create the Spring implementation + SpringImplementation springImplementation = null; + + // Read the location attribute for the spring implementation + String springLocation = reader.getAttributeValue(null, LOCATION); + if (springLocation != null) { + springImplementation = new SpringImplementation(); + springImplementation.setLocation(springLocation); + springImplementation.setUnresolved(true); + processComponentType(springImplementation); + } else { + error("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) throws ContributionWriteException, XMLStreamException { + + // Write <implementation.spring> + policyProcessor.writePolicyPrefixes(springImplementation, writer); + writer.writeStartElement(Constants.SCA10_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) + throws ContributionResolveException { + + if (springImplementation == null) + return; + + /* Load the Spring component type by reading the Spring application context */ + SpringXMLComponentTypeLoader springLoader = + new SpringXMLComponentTypeLoader(assemblyFactory, javaFactory, javaImplementationFactory, policyFactory); + try { + // Load the Spring Implementation information from its application context file... + springLoader.load(springImplementation); + } catch (ContributionReadException e) { + ContributionResolveException ce = new ContributionResolveException(e); + error("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); + if (componentType.isUnresolved()) { + error("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/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java new file mode 100644 index 0000000000..6e0987791b --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java @@ -0,0 +1,151 @@ +/*
+ * 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.processor;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+
+import org.springframework.util.Assert;
+import org.springframework.beans.BeanUtils;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.FatalBeanException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+import org.oasisopen.sca.annotation.ComponentName;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+
+public class ComponentNameAnnotationProcessor implements BeanPostProcessor {
+
+ private Class<? extends Annotation> componentNameAnnotationType = ComponentName.class;
+
+ private RuntimeComponent component;
+
+ public ComponentNameAnnotationProcessor (RuntimeComponent component) {
+ this.component = component;
+ }
+
+ /**
+ * Gets componentName annotation type.
+ */
+ protected Class<? extends Annotation> getComponentNameAnnotationType() {
+ return this.componentNameAnnotationType;
+ }
+
+ /**
+ * Sets componentName annotation type.
+ */
+ public void setComponentNameAnnotationType(Class<? extends Annotation> componentNameAnnotationType) {
+ Assert.notNull(componentNameAnnotationType, "'componentNameAnnotationType' type must not be null.");
+ this.componentNameAnnotationType = componentNameAnnotationType;
+ }
+
+ /**
+ * This method is used to execute before a bean's initialization callback.
+ *
+ * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
+ */
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ processAnnotation(bean);
+ return bean;
+ }
+
+ /**
+ * This method is used to execute after a bean's initialization callback.
+ *
+ * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
+ */
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ return bean;
+ }
+
+ /**
+ * <p>Processes a beans fields for injection if it has a {@link Reference} annotation.</p>
+ */
+ protected void processAnnotation(final Object bean) {
+
+ final Class<?> clazz = bean.getClass();
+
+ ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
+ public void doWith(Field field) {
+ Annotation annotation = field.getAnnotation(getComponentNameAnnotationType());
+
+ if (annotation != null) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ throw new IllegalStateException("ComponentName annotation is not supported on static fields");
+ }
+
+ if (Modifier.isPrivate(field.getModifiers())) {
+ throw new IllegalStateException("ComponentName annotation is not supported on private fields");
+ }
+
+ ReflectionUtils.makeAccessible(field);
+
+ if (field.getType().getName().equals("java.lang.String")) {
+ Object nameObj = component.getName();
+ if (nameObj != null)
+ ReflectionUtils.setField(field, bean, nameObj);
+ } else {
+ throw new IllegalStateException("ComponentName annotation is supported only on java.lang.String field type.");
+ }
+ }
+ }
+ });
+
+ ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
+ public void doWith(Method method) {
+ Annotation annotation = method.getAnnotation(getComponentNameAnnotationType());
+
+ if (annotation != null) {
+ if (Modifier.isStatic(method.getModifiers())) {
+ throw new IllegalStateException("ComponentName annotation is not supported on static methods");
+ }
+
+ if (Modifier.isPrivate(method.getModifiers())) {
+ throw new IllegalStateException("ComponentName annotation is not supported on private methods");
+ }
+
+ if (method.getParameterTypes().length == 0) {
+ throw new IllegalStateException("ComponentName annotation requires at least one argument: " + method);
+ }
+
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+
+ if (pd.getPropertyType().getName().equals("java.lang.String")) {
+ Object nameObj = component.getName();
+ if (nameObj != null) {
+ try {
+ pd.getWriteMethod().invoke(bean, new Object[] { nameObj });
+ } catch (Throwable e) {
+ throw new FatalBeanException("Problem injecting reference: " + e.getMessage(), e);
+ }
+ }
+ } else {
+ throw new IllegalStateException("ComponentName annotation is supported only on java.lang.String field type.");
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java new file mode 100644 index 0000000000..689ac27f0f --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java @@ -0,0 +1,119 @@ +/*
+ * 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.processor;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Constructor;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.util.Assert;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class ConstructorAnnotationProcessor extends InstantiationAwareBeanPostProcessorAdapter {
+
+ private Class<? extends Annotation> constructorAnnotationType
+ = org.oasisopen.sca.annotation.Constructor.class;
+
+ private Class<? extends Annotation> autowiredAnnotationType = Autowired.class;
+
+ public ConstructorAnnotationProcessor () {
+ // Default constructor.
+ }
+
+ /**
+ * Set the 'autowired' annotation type, to be used on constructors, fields,
+ * setter methods and arbitrary config methods.
+ */
+ public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnnotationType) {
+ Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null");
+ this.autowiredAnnotationType = autowiredAnnotationType;
+ }
+
+ /**
+ * Return the 'autowired' annotation type.
+ */
+ protected Class<? extends Annotation> getAutowiredAnnotationType() {
+ return this.autowiredAnnotationType;
+ }
+
+ /**
+ * Return the 'constructor' annotation type.
+ */
+ protected Class<? extends Annotation> getConstructorAnnotationType() {
+ return this.constructorAnnotationType;
+ }
+
+ /**
+ * Sets the 'constructor' annotation type.
+ */
+ public void setConstructorAnnotationType(Class<? extends Annotation> constructorAnnotationType) {
+ Assert.notNull(constructorAnnotationType, "'constructorAnnotationType' type must not be null.");
+ this.constructorAnnotationType = constructorAnnotationType;
+ }
+
+ /**
+ * This method is used to execute before a bean's initialization callback.
+ *
+ * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
+ */
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ return bean;
+ }
+
+ /**
+ * This method is used to execute after a bean's initialization callback.
+ *
+ * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
+ */
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ return bean;
+ }
+
+ public Constructor[] determineCandidateConstructors(Class beanClass, String beanName) throws BeansException {
+ /*Constructor[] declaredConstructors = beanClass.getDeclaredConstructors();
+ Method[] declaredMethods = beanClass.getDeclaredMethods();
+ List candidates = new ArrayList(declaredConstructors.length);
+
+ for (int i = 0; i < declaredMethods.length; i++) {
+ Method method = declaredMethods[i];
+ Annotation annotation = method.getAnnotation(getConstructorAnnotationType());
+ if (annotation != null) {
+ if (Modifier.isStatic(method.getModifiers())) {
+ throw new IllegalStateException("Constructor annotation is not supported on static methods");
+ }
+
+ if (candidates.size() == 1) {
+ throw new IllegalStateException("Only one method is allowed to have constructor annotation in a bean: " + method);
+ }
+
+ candidates.add(method);
+ }
+ }
+
+ return (Constructor[]) candidates.toArray(new Constructor[candidates.size()]);*/
+ return null;
+ }
+}
diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java new file mode 100644 index 0000000000..129a15e72e --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java @@ -0,0 +1,72 @@ +/*
+ * 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.processor;
+
+import java.lang.annotation.Annotation;
+import org.oasisopen.sca.annotation.Init;
+import org.oasisopen.sca.annotation.Destroy;
+import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
+import org.springframework.util.Assert;
+
+public class InitDestroyAnnotationProcessor extends InitDestroyAnnotationBeanPostProcessor {
+
+ private static final long serialVersionUID = 0;
+
+ private Class<? extends Annotation> initAnnotationType = Init.class;
+
+ private Class<? extends Annotation> destroyAnnotationType = Destroy.class;
+
+ /**
+ * Gets init annotation type.
+ */
+ protected Class<? extends Annotation> getInitAnnotationType() {
+ return this.initAnnotationType;
+ }
+
+ /**
+ * Sets init annotation type.
+ */
+ /*public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
+ Assert.notNull(initAnnotationType, "Init annotation type must not be null.");
+ this.initAnnotationType = initAnnotationType;
+ }*/
+
+ /**
+ * Gets destroy annotation type.
+ */
+ protected Class<? extends Annotation> getDestroyAnnotationType() {
+ return this.destroyAnnotationType;
+ }
+
+ /**
+ * Sets destroy annotation type.
+ */
+ /*public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
+ Assert.notNull(destroyAnnotationType, "Destroy annotation type must not be null.");
+ this.destroyAnnotationType = destroyAnnotationType;
+ }*/
+
+ public InitDestroyAnnotationProcessor () {
+ // Set the @Init annotation type
+ setInitAnnotationType(initAnnotationType);
+
+ // Set the @Destroy annotation type
+ setDestroyAnnotationType(destroyAnnotationType);
+ }
+}
diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java new file mode 100644 index 0000000000..fbc0e2b36f --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java @@ -0,0 +1,220 @@ +/*
+ * 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.processor;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+import org.springframework.util.Assert;
+import org.springframework.beans.BeanUtils;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.FatalBeanException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+import org.oasisopen.sca.annotation.Property;
+import org.apache.tuscany.sca.assembly.ComponentProperty;
+import org.apache.tuscany.sca.core.factory.ObjectFactory;
+import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+
+public class PropertyAnnotationProcessor implements BeanPostProcessor {
+
+ private Class<? extends Annotation> propertyAnnotationType = Property.class;
+
+ private RuntimeComponent component;
+
+ private JavaPropertyValueObjectFactory propertyFactory;
+
+ public PropertyAnnotationProcessor (JavaPropertyValueObjectFactory propertyFactory,
+ RuntimeComponent component) {
+ this.propertyFactory = propertyFactory;
+ this.component = component;
+ }
+
+ /**
+ * Gets property annotation type.
+ */
+ protected Class<? extends Annotation> getPropertyAnnotationType() {
+ return this.propertyAnnotationType;
+ }
+
+ /**
+ * Sets property annotation type.
+ */
+ public void setPropertyAnnotationType(Class<? extends Annotation> propertyAnnotationType) {
+ Assert.notNull(propertyAnnotationType, "'propertyAnnotationType' type must not be null.");
+ this.propertyAnnotationType = propertyAnnotationType;
+ }
+
+ /**
+ * This method is used to execute before a bean's initialization callback.
+ *
+ * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
+ */
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ processAnnotation(bean);
+ return bean;
+ }
+
+ /**
+ * This method is used to execute after a bean's initialization callback.
+ *
+ * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
+ */
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ return bean;
+ }
+
+ /**
+ * <p>Processes a beans fields for injection if it has a {@link Property} annotation.</p>
+ */
+ protected void processAnnotation(final Object bean) {
+
+ final Class<?> clazz = bean.getClass();
+
+ ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
+ public void doWith(Method method) {
+ //Annotation annotation = method.getAnnotation(getPropertyAnnotationType());
+ Property annotation = (Property) method.getAnnotation(getPropertyAnnotationType());
+
+ if (annotation != null) {
+ if (Modifier.isStatic(method.getModifiers())) {
+ throw new IllegalStateException("Property annotation is not supported on static methods");
+ }
+
+ if (Modifier.isPrivate(method.getModifiers())) {
+ throw new IllegalStateException("Property annotation is not supported on private methods");
+ }
+
+ if (method.getParameterTypes().length == 0) {
+ throw new IllegalStateException("Property annotation requires at least one argument: " + method);
+ }
+
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd != null) {
+ String propName = annotation.name();
+ if ("".equals(propName)) {
+ injectProperty(bean, pd, getPropertyObj(pd.getPropertyType(), pd.getName()));
+ } else {
+ injectProperty(bean, pd, getPropertyObj(pd.getPropertyType(), propName));
+ }
+ }
+ }
+ }
+ });
+
+ ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
+ public void doWith(Field field) {
+ //Annotation annotation = field.getAnnotation(getPropertyAnnotationType());
+ Property annotation = (Property) field.getAnnotation(getPropertyAnnotationType());
+
+ if (annotation != null) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ throw new IllegalStateException("Property annotation is not supported on static fields");
+ }
+
+ if (Modifier.isPrivate(field.getModifiers())) {
+ throw new IllegalStateException("Property annotation is not supported on private fields");
+ }
+
+ ReflectionUtils.makeAccessible(field);
+
+ Object propertyObj = null;
+ String propName = annotation.name();
+ if ("".equals(propName)) {
+ propertyObj = getPropertyObj(field.getType(), field.getName());
+ } else {
+ propertyObj = getPropertyObj(field.getType(), propName);
+ }
+
+ if (propertyObj != null)
+ ReflectionUtils.setField(field, bean, propertyObj);
+ }
+ }
+ });
+ }
+
+ /**
+ * Processes a property descriptor to inject a service.
+ */
+ public Object getPropertyObj(Class requiredType, String name) {
+
+ Object propertyObj = null;
+
+ List<ComponentProperty> props = component.getProperties();
+ for (ComponentProperty prop : props) {
+ if (prop.getName().equals(name)) {
+ // On finding the property, create a factory for it and create a Bean using
+ // the factory
+ ObjectFactory factory = propertyFactory.createValueFactory(prop, prop.getValue(), requiredType);
+ propertyObj = factory.getInstance();
+ } // end if
+ } // end for
+
+ return propertyObj;
+ }
+
+
+ public void injectProperty(Object bean, PropertyDescriptor pd, Object propertyObj) {
+
+ if (propertyObj != null) {
+ try {
+ pd.getWriteMethod().invoke(bean, new Object[] { propertyObj });
+ } catch (Throwable e) {
+ throw new FatalBeanException("Problem injecting property: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Processes a property descriptor to inject a service.
+ */
+ /*public void injectMethod(Object bean, Method method) {
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+
+ if (pd != null) {
+ Object propertyObj = null;
+
+ List<ComponentProperty> props = component.getProperties();
+ for (ComponentProperty prop : props) {
+ if (prop.getName().equals(pd.getName())) {
+ // On finding the property, create a factory for it and create a Bean using
+ // the factory
+ ObjectFactory factory = propertyFactory.createValueFactory(prop, prop.getValue(), pd.getPropertyType());
+ propertyObj = factory.getInstance();
+ } // end if
+ } // end for
+
+ if (propertyObj != null) {
+ try {
+ pd.getWriteMethod().invoke(bean, new Object[] { propertyObj });
+ } catch (Throwable e) {
+ throw new FatalBeanException("Problem injecting property: " + e.getMessage(), e);
+ }
+ }
+ }
+ }*/
+}
diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java new file mode 100644 index 0000000000..48c727baab --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java @@ -0,0 +1,186 @@ +/*
+ * 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.processor;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+
+import org.springframework.util.Assert;
+import org.springframework.beans.BeanUtils;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.FatalBeanException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+import org.oasisopen.sca.annotation.Reference;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+
+public class ReferenceAnnotationProcessor implements BeanPostProcessor {
+
+ private Class<? extends Annotation> referenceAnnotationType = Reference.class;
+
+ private RuntimeComponent component;
+
+ public ReferenceAnnotationProcessor (RuntimeComponent component) {
+ this.component = component;
+ }
+
+ /**
+ * Gets referece annotation type.
+ */
+ protected Class<? extends Annotation> getReferenceAnnotationType() {
+ return this.referenceAnnotationType;
+ }
+
+ /**
+ * Sets referece annotation type.
+ */
+ public void setReferenceAnnotationType(Class<? extends Annotation> referenceAnnotationType) {
+ Assert.notNull(referenceAnnotationType, "'referenceAnnotationType' type must not be null.");
+ this.referenceAnnotationType = referenceAnnotationType;
+ }
+
+ /**
+ * This method is used to execute before a bean's initialization callback.
+ *
+ * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
+ */
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ processAnnotation(bean);
+ return bean;
+ }
+
+ /**
+ * This method is used to execute after a bean's initialization callback.
+ *
+ * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
+ */
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ return bean;
+ }
+
+ /**
+ * <p>Processes a beans fields for injection if it has a {@link Reference} annotation.</p>
+ */
+ protected void processAnnotation(final Object bean) {
+
+ final Class<?> clazz = bean.getClass();
+
+ ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
+ public void doWith(Method method) {
+ //Annotation annotation = method.getAnnotation(getReferenceAnnotationType());
+ Reference annotation = (Reference) method.getAnnotation(getReferenceAnnotationType());
+
+ if (annotation != null) {
+ if (Modifier.isStatic(method.getModifiers())) {
+ throw new IllegalStateException("Reference annotation is not supported on static methods");
+ }
+
+ if (Modifier.isPrivate(method.getModifiers())) {
+ throw new IllegalStateException("Reference annotation is not supported on private methods");
+ }
+
+ if (method.getParameterTypes().length == 0) {
+ throw new IllegalStateException("Reference annotation requires at least one argument: " + method);
+ }
+
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd != null) {
+ String refName = annotation.name();
+ if ("".equals(refName)) {
+ injectReference(bean, pd, pd.getName());
+ } else {
+ injectReference(bean, pd, refName);
+ }
+ }
+ }
+ }
+ });
+
+ ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
+ public void doWith(Field field) {
+ //Annotation annotation = field.getAnnotation(getReferenceAnnotationType());
+ Reference annotation = (Reference) field.getAnnotation(getReferenceAnnotationType());
+
+ if (annotation != null) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ throw new IllegalStateException("Reference annotation is not supported on static fields");
+ }
+
+ if (Modifier.isPrivate(field.getModifiers())) {
+ throw new IllegalStateException("Reference annotation is not supported on private fields");
+ }
+
+ ReflectionUtils.makeAccessible(field);
+
+ Object referenceObj = null;
+ String refName = annotation.name();
+ if ("".equals(refName)) {
+ referenceObj = component.getComponentContext().getService(field.getType(), field.getName());
+ } else {
+ referenceObj = component.getComponentContext().getService(field.getType(), refName);
+ }
+
+ if (referenceObj != null)
+ ReflectionUtils.setField(field, bean, referenceObj);
+ }
+ }
+ });
+ }
+
+ /**
+ * Processes a property descriptor to inject a service.
+ */
+ public void injectReference(Object bean, PropertyDescriptor pd, String name) {
+
+ Object referenceObj = component.getComponentContext().getService(pd.getPropertyType(), name);
+
+ if (referenceObj != null) {
+ try {
+ pd.getWriteMethod().invoke(bean, new Object[] { referenceObj });
+ } catch (Throwable e) {
+ throw new FatalBeanException("Problem injecting reference: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Processes a property descriptor to inject a service.
+ */
+ /*public void injectMethod(Object bean, Method method) {
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+
+ if (pd != null) {
+ Object referenceObj = component.getComponentContext().getService(pd.getPropertyType(), pd.getName());
+
+ if (referenceObj != null) {
+ try {
+ pd.getWriteMethod().invoke(bean, new Object[] { referenceObj });
+ } catch (Throwable e) {
+ throw new FatalBeanException("Problem injecting reference: " + e.getMessage(), e);
+ }
+ }
+ }
+ }*/
+}
diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/Constants.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/Constants.java new file mode 100644 index 0000000000..92f980fdfe --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/Constants.java @@ -0,0 +1,64 @@ +/*
+ * 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 javax.xml.namespace.QName;
+
+/**
+ * Constants used in Spring Application Context XML files.
+ */
+public interface Constants {
+
+ String SCA_NS = "http://www.springframework.org/schema/sca";
+ String SPRING_NS = "http://www.springframework.org/schema/beans";
+
+ String PROPERTY = "property";
+ QName SCAPROPERTY_ELEMENT = new QName(SCA_NS, PROPERTY);
+ QName PROPERTY_ELEMENT = new QName(SPRING_NS, PROPERTY);
+
+ String SERVICE = "service";
+ QName SERVICE_ELEMENT = new QName(SCA_NS, SERVICE);
+
+ String REFERENCE = "reference";
+ QName REFERENCE_ELEMENT = new QName(SCA_NS, REFERENCE);
+
+ 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 VALUE = "value";
+ QName VALUE_ELEMENT = new QName(SPRING_NS, VALUE);
+
+ String REF = "ref";
+ QName REF_ELEMENT = new QName(SPRING_NS, REF);
+
+ String APPLICATION_CONTEXT = "application-context.xml";
+}
diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanElement.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanElement.java new file mode 100644 index 0000000000..f9a9fee58f --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanElement.java @@ -0,0 +1,67 @@ +/* + * 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.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: 512919 $ $Date: 2007-02-28 19:32:56 +0000 (Wed, 28 Feb 2007) $ + */ +public class SpringBeanElement { + + private String id; + private String className; + private List<SpringPropertyElement> properties = new ArrayList<SpringPropertyElement>(); + private List<SpringConstructorArgElement> constructorargs = new ArrayList<SpringConstructorArgElement>(); + + public SpringBeanElement(String id, String className) { + this.id = id; + this.className = className; + } + + public String getClassName() { + return className; + } + + public String getId() { + return 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); + } + +} // end class SpringBeanElement diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java new file mode 100644 index 0000000000..e5f8030b90 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java @@ -0,0 +1,108 @@ +/* + * 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.util.Map; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.contribution.processor.ContributionResolveException; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.policy.PolicyFactory; +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: 512919 $ $Date: 2007-02-28 19:32:56 +0000 (Wed, 28 Feb 2007) $ + */ +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(AssemblyFactory assemblyFactory, + JavaInterfaceFactory javaFactory, + JavaImplementationFactory javaImplementationFactory, + PolicyFactory policyFactory) { + + this.javaImplementationFactory = javaImplementationFactory; + + } // 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 Map<String, JavaElementImpl> introspectBean(Class<?> beanClass, ComponentType componentType, + SpringImplementation springImplementation) 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(); + + 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()); + + springImplementation.setInitMethod(javaImplementation.getInitMethod()); + springImplementation.setDestroyMethod(javaImplementation.getDestroyMethod()); + springImplementation.setConstructor(javaImplementation.getConstructor()); + + } catch (IntrospectionException e) { + throw new ContributionResolveException(e); + } // end try + + //List<Service> services = javaImplementation.getServices(); + //for (Service service : services) { + //String name = service.getName(); + //System.out.println("Spring Bean: found service with name: " + name); + //} // end for + + return javaImplementation.getPropertyMembers(); + + } // end method introspectBean + +} // end class SpringBeanIntrospector diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringConstructorArgElement.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringConstructorArgElement.java new file mode 100644 index 0000000000..57f4a26ba3 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringConstructorArgElement.java @@ -0,0 +1,60 @@ +/*
+ * 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.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a <constructor-arg> element in a Spring application-context
+ * - this has ref attribute
+ *
+ * @version $Rev: 512919 $ $Date: 2007-02-28 19:32:56 +0000 (Wed, 28 Feb 2007) $
+ */
+public class SpringConstructorArgElement {
+
+ private String ref;
+ private String type;
+ private List<String> values = new ArrayList<String>();
+
+ public SpringConstructorArgElement(String ref, String type) {
+ this.ref = ref;
+ this.type = type;
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ public String getRef() {
+ return this.ref;
+ }
+
+ public void setRef(String ref) {
+ this.ref = ref;
+ }
+
+ public List<String> getValues() {
+ return this.values;
+ }
+
+ public void addValue(String value) {
+ this.values.add(value);
+ }
+}
diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringPropertyElement.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringPropertyElement.java new file mode 100644 index 0000000000..39e1286f32 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringPropertyElement.java @@ -0,0 +1,61 @@ +/* + * 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.util.ArrayList; +import java.util.List; + +/** + * Represents a <property> element in a Spring application-context + * - this has name and ref attributes + * + * @version $Rev: 512919 $ $Date: 2007-02-28 19:32:56 +0000 (Wed, 28 Feb 2007) $ + */ +public class SpringPropertyElement { + + private String name; + private String ref; + private List<String> values = new ArrayList<String>(); + + public SpringPropertyElement(String name, String ref) { + this.name = name; + this.ref = ref; + } + + public String getName() { + return name; + } + + public String getRef() { + return ref; + } + + public void setRef(String ref) { + this.ref = ref; + } + + public List<String> getProperties() { + return values; + } + + public void addProperty(String value) { + values.add(value); + } + +} // end class SpringPropertyElement diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAPropertyElement.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAPropertyElement.java new file mode 100644 index 0000000000..2f37ab6504 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAPropertyElement.java @@ -0,0 +1,52 @@ +/* + * 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; + +/** + * Represents an <sca:property> element in a Spring application-context + * - this has name and type attributes + * @version $Rev: 511195 $ $Date: 2007-02-24 02:29:46 +0000 (Sat, 24 Feb 2007) $ + */ +public class SpringSCAPropertyElement { + + private String name; + private String type; + + 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; + } + +} // end class SpringPropertyElement diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAReferenceElement.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAReferenceElement.java new file mode 100644 index 0000000000..b3f45415fd --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAReferenceElement.java @@ -0,0 +1,54 @@ +/* + * 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; + +/** + * 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: 512919 $ $Date: 2007-02-28 19:32:56 +0000 (Wed, 28 Feb 2007) $ + */ +public class SpringSCAReferenceElement { + + private String name; + private String type; + + 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; + } + +} // end class SpringSCAReferenceElement diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAServiceElement.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAServiceElement.java new file mode 100644 index 0000000000..2eb5686270 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringSCAServiceElement.java @@ -0,0 +1,64 @@ +/* + * 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; + +/** + * 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: 512919 $ $Date: 2007-02-28 19:32:56 +0000 (Wed, 28 Feb 2007) $ + */ +public class SpringSCAServiceElement { + + private String name; + private String type; + private String target; + + public SpringSCAServiceElement(String name, String type, String target) { + this.name = name; + this.type = type; + 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; + } + +} // end class SpringSCAServiceElement diff --git a/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java new file mode 100644 index 0000000000..d7d1d55cbf --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java @@ -0,0 +1,637 @@ +/* + * 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 static javax.xml.stream.XMLStreamConstants.START_ELEMENT; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +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.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ContributionResolveException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.spring.SpringImplementation; +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.policy.PolicyFactory; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; + +/** + * Introspects a Spring XML application-context configuration file to create <implementation-spring../> + * component type information. + * + * + * @version $Rev: 512919 $ $Date: 2007-02-28 19:32:56 +0000 (Wed, 28 Feb 2007) $ + */ +public class SpringXMLComponentTypeLoader { + + private AssemblyFactory assemblyFactory; + private JavaInterfaceFactory javaFactory; + private ClassLoader cl; + + private SpringBeanIntrospector beanIntrospector; + + public SpringXMLComponentTypeLoader(AssemblyFactory assemblyFactory, + JavaInterfaceFactory javaFactory, + JavaImplementationFactory javaImplementationFactory, + PolicyFactory policyFactory) { + super(); + this.assemblyFactory = assemblyFactory; + this.javaFactory = javaFactory; + beanIntrospector = + new SpringBeanIntrospector(assemblyFactory, javaFactory, javaImplementationFactory, policyFactory); + } + + 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) 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); + if (!componentType.isUnresolved()) + implementation.setUnresolved(false); + } // end if + //System.out.println("Spring TypeLoader - load method complete"); + } // end method load + + /** + * 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) throws ContributionReadException { + XMLStreamReader reader; + List<SpringBeanElement> beans = new ArrayList<SpringBeanElement>(); + List<SpringSCAServiceElement> services = new ArrayList<SpringSCAServiceElement>(); + List<SpringSCAReferenceElement> references = new ArrayList<SpringSCAReferenceElement>(); + List<SpringSCAPropertyElement> scaproperties = new ArrayList<SpringSCAPropertyElement>(); + + Resource resource; + + String location = implementation.getLocation(); + + try { + // FIXME - is the ContextClassLoader the right place to start the search? + cl = Thread.currentThread().getContextClassLoader(); + + resource = getApplicationContextResource(location, cl); + implementation.setResource(resource); + // The URI is used to uniquely identify the Implementation + implementation.setURI(resource.getURL().toString()); + // FIXME - need a better way to handle the XMLInputFactory than allocating a new one every time + XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); + reader = xmlFactory.createXMLStreamReader(resource.getInputStream()); + + // System.out.println("Spring TypeLoader - starting to read context file"); + readBeanDefinition(reader, beans, services, references, scaproperties); + + } catch (IOException e) { + throw new ContributionReadException(e); + } catch (XMLStreamException 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, beans, services, references, scaproperties); + + return; + } // end method loadFromXML + + /** + * Method which returns the XMLStreamReader for the Spring application-context.xml file + * specified in the location attribute + */ + private XMLStreamReader getApplicationContextReader (String location) throws ContributionReadException { + + try { + // FIXME - is the ContextClassLoader the right place to start the search? + cl = Thread.currentThread().getContextClassLoader(); + Resource resource = getApplicationContextResource(location, cl); + // FIXME - need a better way to handle the XMLInputFactory than allocating a new one every time + XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); + XMLStreamReader reader = xmlFactory.createXMLStreamReader(resource.getInputStream()); + return reader; + } catch (IOException e) { + throw new ContributionReadException(e); + } catch (XMLStreamException e) { + throw new ContributionReadException(e); + } + } + + /** + * Method which reads the bean definitions from Spring application-context.xml file and identifies + * the defined beans, properties, services and references + */ + private void readBeanDefinition(XMLStreamReader reader, + List<SpringBeanElement> beans, + List<SpringSCAServiceElement> services, + List<SpringSCAReferenceElement> references, + List<SpringSCAPropertyElement> scaproperties) throws ContributionReadException { + + SpringBeanElement bean = null; + SpringPropertyElement property = null; + SpringConstructorArgElement constructorArg = null; + + try { + boolean completed = false; + while (!completed) { + switch (reader.next()) { + case START_ELEMENT: + QName qname = reader.getName(); + //System.out.println("Spring TypeLoader - found element with name: " + qname.toString()); + if (Constants.IMPORT_ELEMENT.equals(qname)) { + //FIXME - put the sequence of code below which gets the ireader into a subsidiary method + String location = reader.getAttributeValue(null, "resource"); + if (location != null) { + XMLStreamReader ireader = getApplicationContextReader(location); + // Read the bean definition for the identified imported resource + readBeanDefinition(ireader, beans, services, references, scaproperties); + } + } else if (Constants.SERVICE_ELEMENT.equals(qname)) { + SpringSCAServiceElement service = + new SpringSCAServiceElement(reader.getAttributeValue(null, "name"), reader + .getAttributeValue(null, "type"), reader.getAttributeValue(null, "target")); + services.add(service); + } else if (Constants.REFERENCE_ELEMENT.equals(qname)) { + SpringSCAReferenceElement reference = + new SpringSCAReferenceElement(reader.getAttributeValue(null, "name"), reader + .getAttributeValue(null, "type")); + references.add(reference); + } else if (Constants.SCAPROPERTY_ELEMENT.equals(qname)) { + SpringSCAPropertyElement scaproperty = + new SpringSCAPropertyElement(reader.getAttributeValue(null, "name"), reader + .getAttributeValue(null, "type")); + scaproperties.add(scaproperty); + } else if (Constants.BEAN_ELEMENT.equals(qname)) { + bean = new SpringBeanElement(reader.getAttributeValue(null, "id"), reader + .getAttributeValue(null, "class")); + //beans.add(bean); + } else if (Constants.PROPERTY_ELEMENT.equals(qname)) { + property = new SpringPropertyElement(reader.getAttributeValue(null, "name"), reader + .getAttributeValue(null, "ref")); + //bean.addProperty(property); + } else if (Constants.CONSTRUCTORARG_ELEMENT.equals(qname)) { + constructorArg = new SpringConstructorArgElement(reader.getAttributeValue(null, "ref"), + reader.getAttributeValue(null, "type")); + } else if (Constants.REF_ELEMENT.equals(qname)) { + String ref = reader.getAttributeValue(null, "bean"); + // Check if the parent element is a property + if (property != null) property.setRef(ref); + // Check if the parent element is a constructor-arg + if (constructorArg != null) constructorArg.setRef(ref); + } else if (Constants.VALUE_ELEMENT.equals(qname)) { + String value = reader.getElementText(); + // Check if the parent element is a constructor-arg + if (constructorArg != null) { + constructorArg.addValue(value); + // Identify the XML resource specified for the constructor-arg element + if ((value.indexOf(".xml") != -1)) { + if ((bean.getClassName().indexOf(".ClassPathXmlApplicationContext") != -1) || + (bean.getClassName().indexOf(".FileSystemXmlApplicationContext") != -1)) { + XMLStreamReader creader = getApplicationContextReader(value); + // Read the bean definition for the constructor-arg resources + readBeanDefinition(creader, beans, services, references, scaproperties); + } + } + } + } // end if + break; + case END_ELEMENT: + if (Constants.BEANS_ELEMENT.equals(reader.getName())) { + //System.out.println("Spring TypeLoader - finished read of context file"); + completed = true; + break; + } else if (Constants.BEAN_ELEMENT.equals(reader.getName())) { + beans.add(bean); + bean = null; + } else if (Constants.PROPERTY_ELEMENT.equals(reader.getName())) { + bean.addProperty(property); + property = null; + } else if (Constants.CONSTRUCTORARG_ELEMENT.equals(reader.getName())) { + bean.addCustructorArgs(constructorArg); + constructorArg = null; + } // end if + } // end switch + } // end while + } catch (XMLStreamException e) { + throw new ContributionReadException(e); + } + } + + /** + * 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, + List<SpringBeanElement> beans, + List<SpringSCAServiceElement> services, + List<SpringSCAReferenceElement> references, + List<SpringSCAPropertyElement> scaproperties) throws ContributionReadException { + /* + * 1. Each service becomes a service in the component type + * 2. Each reference becomes a reference in the component type + * 3. IF there are no explicit service elements, each bean becomes a service + * 4. 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 + * 5. Each scaproperty becomes a property in the component type + * 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 + */ + + ComponentType componentType = implementation.getComponentType(); + + try { + // Deal with the services first.... + Iterator<SpringSCAServiceElement> its = services.iterator(); + while (its.hasNext()) { + SpringSCAServiceElement serviceElement = its.next(); + Class<?> interfaze = cl.loadClass(serviceElement.getType()); + Service theService = createService(interfaze, serviceElement.getName()); + componentType.getServices().add(theService); + // Add this service to the Service / Bean map + String beanName = serviceElement.getTarget(); + for (SpringBeanElement beanElement : beans) { + if (beanName.equals(beanElement.getId())) { + implementation.setBeanForService(theService, beanElement); + } + } // end for + } // end while + + // Next handle the references + Iterator<SpringSCAReferenceElement> itr = references.iterator(); + while (itr.hasNext()) { + SpringSCAReferenceElement referenceElement = itr.next(); + Class<?> interfaze = cl.loadClass(referenceElement.getType()); + Reference theReference = createReference(interfaze, referenceElement.getName()); + componentType.getReferences().add(theReference); + } // 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(); + // Load the Spring bean class + Class<?> beanClass = cl.loadClass(beanElement.getClassName()); + // Introspect the bean + ComponentType beanComponentType = assemblyFactory.createComponentType(); + beanIntrospector.introspectBean(beanClass, beanComponentType, implementation); + // 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); + } + } // end while + } // end if + // Now check to see if there are any more references from beans that are not satisfied + itb = beans.iterator(); + while (itb.hasNext()) { + SpringBeanElement beanElement = itb.next(); + boolean unresolvedProperties = false; + if (!beanElement.getProperties().isEmpty()) { + // Scan through the properties + Iterator<SpringPropertyElement> itp = beanElement.getProperties().iterator(); + while (itp.hasNext()) { + SpringPropertyElement propertyElement = itp.next(); + if (propertyRefUnresolved(propertyElement.getRef(), beans, references, scaproperties)) { + // This means an unresolved reference from the spring bean... + unresolvedProperties = true; + } // end if + } // end while + // If there are unresolved properties, then find which ones are references + if (unresolvedProperties) { + Class<?> beanClass = cl.loadClass(beanElement.getClassName()); + // Introspect the bean + ComponentType beanComponentType = assemblyFactory.createComponentType(); + Map<String, JavaElementImpl> propertyMap = + beanIntrospector.introspectBean(beanClass, beanComponentType, implementation); + // 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(); + itp = beanElement.getProperties().iterator(); + while (itp.hasNext()) { + SpringPropertyElement propertyElement = itp.next(); + if (propertyRefUnresolved(propertyElement.getRef(), beans, references, scaproperties)) { + boolean resolved = false; + // This means an unresolved reference from the spring bean...add it to + // the references for the Spring application context + 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(propertyElement.getRef()); + componentType.getReferences().add(reference); + resolved = true; + } // end if + } // end for + if (!resolved) { + // If the bean property is not already resolved as a reference + // then it must be an SCA property... + 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.... + scaproperty.setName(propertyElement.getRef()); + componentType.getProperties().add(scaproperty); + // Fetch and store the type of the property + implementation.setPropertyClass(scaproperty.getName(), propertyMap + .get(scaproperty.getName()).getType()); + resolved = true; + } // end if + } // end for + } // end if + } // end if + } // end while + } // end if + } // end if + + } // end while + + 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)); + componentType.getProperties().add(theProperty); + // Remember the Java Class (ie the type) for this property + implementation.setPropertyClass(theProperty.getName(), propType); + } // end if + } // 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); + } catch (ContributionResolveException 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 + + /** + * 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 Resource getApplicationContextResource(String locationAttr, ClassLoader cl) + throws ContributionReadException { + File manifestFile = null; + File appXmlFile; + File locationFile = null; + + URL url = cl.getResource(locationAttr); + if (url != null) { + String path = url.getPath(); + locationFile = new File(path); + } else { + throw new ContributionReadException( + "SpringXMLLoader getApplicationContextResource: " + "unable to find resource file " + + locationAttr); + } + + 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) { + appXmlFile = new File(locationFile, appCtxPath); + if (appXmlFile.exists()) { + return new UrlResource(appXmlFile.toURL()); + } + } + } + // no manifest-specified Spring context, use default + appXmlFile = new File(locationFile, "META-INF" + File.separator + "spring" + + File.separator + Constants.APPLICATION_CONTEXT); + if (appXmlFile.exists()) { + return new UrlResource(appXmlFile.toURL()); + } + } catch (IOException e) { + throw new ContributionReadException("Error reading manifest " + manifestFile); + } + } else { + if (locationFile.isFile() && locationFile.getName().indexOf(".jar") < 0) { + return new UrlResource(url); + } + else { + 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) { + je = jf.getJarEntry(appCtxPath); + if (je != null) { + // TODO return a Spring specific Resource type for jars + return new UrlResource(new URL("jar:" + locationFile.toURI().toURL() + "!/" + appCtxPath)); + } + } + } + je = jf.getJarEntry("META-INF" + File.separator + "spring" + + File.separator + Constants.APPLICATION_CONTEXT); + if (je != null) { + return new UrlResource(new URL("jar:" + locationFile.toURI().toURL() + "!/" + Constants.APPLICATION_CONTEXT)); + } + } catch (IOException e) { + // bad archive + // TODO: create a more appropriate exception type + throw new ContributionReadException( + "SpringXMLLoader getApplicationContextResource: " + " IO exception reading context file.", + e); + } + } + } + + throw new ContributionReadException("SpringXMLLoader getApplicationContextResource: " + + "META-INF/spring/" + Constants.APPLICATION_CONTEXT + "not found"); + } // 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; + } +} // end class SpringXMLComponentTypeLoader diff --git a/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor b/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor new file mode 100644 index 0000000000..4b71cef6c4 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor @@ -0,0 +1,19 @@ +# 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.SpringImplementationProcessor;qname=http://www.osoa.org/xmlns/sca/1.0#implementation.spring,model=org.apache.tuscany.sca.implementation.spring.SpringImplementation diff --git a/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/spring.handlers b/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/spring.handlers new file mode 100644 index 0000000000..7f9a7b17b0 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://www.springframework.org/schema/sca=org.apache.tuscany.sca.implementation.spring.ScaNamespaceHandler diff --git a/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/spring.schemas b/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/spring.schemas new file mode 100644 index 0000000000..249cc21c13 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/resources/META-INF/spring.schemas @@ -0,0 +1 @@ +http\://www.osoa.org/xmlns/sca/1.0/spring-sca.xsd=org/springframework/sca/xml/spring-sca.xsd diff --git a/java/sca-contrib/modules/implementation-spring/src/main/resources/impl-spring-validation-messages.properties b/java/sca-contrib/modules/implementation-spring/src/main/resources/impl-spring-validation-messages.properties new file mode 100644 index 0000000000..6fce02664a --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/resources/impl-spring-validation-messages.properties @@ -0,0 +1,23 @@ +# +# +# 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
\ No newline at end of file diff --git a/java/sca-contrib/modules/implementation-spring/src/main/resources/org/springframework/sca/xml/spring-sca.xsd b/java/sca-contrib/modules/implementation-spring/src/main/resources/org/springframework/sca/xml/spring-sca.xsd new file mode 100644 index 0000000000..e20f4e8158 --- /dev/null +++ b/java/sca-contrib/modules/implementation-spring/src/main/resources/org/springframework/sca/xml/spring-sca.xsd @@ -0,0 +1,99 @@ +<?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. +--> +<xsd:schema xmlns="http://www.springframework.org/schema/sca" xmlns:xsd="http://www.w3.org/2001/XMLSchema" + attributeFormDefault="unqualified" elementFormDefault="qualified" + targetNamespace="http://www.springframework.org/schema/sca"> + + <xsd:element name="composite"> + <xsd:complexType> + <xsd:attribute name="component" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="sca-adapter-class" use="optional"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:element name="reference"> + <xsd:complexType> + <xsd:attribute name="name" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="type" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="default" use="optional"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:element name="property"> + <xsd:complexType> + <xsd:attribute name="id" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="name" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="type" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:element name="service"> + <xsd:complexType> + <xsd:attribute name="name" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="type" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="target" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string" /> + </xsd:simpleType> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + +</xsd:schema> |