| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.tuscany.sca.implementation.spring.introspect; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Enumeration; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.jar.Attributes; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| import java.util.jar.Manifest; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.apache.tuscany.sca.assembly.AssemblyFactory; |
| import org.apache.tuscany.sca.assembly.ComponentType; |
| import org.apache.tuscany.sca.assembly.Multiplicity; |
| import org.apache.tuscany.sca.assembly.Property; |
| import org.apache.tuscany.sca.assembly.Reference; |
| import org.apache.tuscany.sca.assembly.Service; |
| import org.apache.tuscany.sca.contribution.Artifact; |
| import org.apache.tuscany.sca.contribution.ContributionFactory; |
| import org.apache.tuscany.sca.contribution.processor.ContributionReadException; |
| import org.apache.tuscany.sca.contribution.processor.ProcessorContext; |
| import org.apache.tuscany.sca.contribution.resolver.ClassReference; |
| import org.apache.tuscany.sca.contribution.resolver.ModelResolver; |
| import org.apache.tuscany.sca.core.ExtensionPointRegistry; |
| import org.apache.tuscany.sca.core.FactoryExtensionPoint; |
| import org.apache.tuscany.sca.core.UtilityExtensionPoint; |
| import org.apache.tuscany.sca.implementation.java.JavaConstructorImpl; |
| import org.apache.tuscany.sca.implementation.java.JavaElementImpl; |
| import org.apache.tuscany.sca.implementation.java.JavaImplementation; |
| import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; |
| import org.apache.tuscany.sca.implementation.spring.SpringBeanElement; |
| import org.apache.tuscany.sca.implementation.spring.SpringConstructorArgElement; |
| import org.apache.tuscany.sca.implementation.spring.SpringImplementation; |
| import org.apache.tuscany.sca.implementation.spring.SpringPropertyElement; |
| import org.apache.tuscany.sca.implementation.spring.SpringSCAPropertyElement; |
| import org.apache.tuscany.sca.implementation.spring.SpringSCAReferenceElement; |
| import org.apache.tuscany.sca.implementation.spring.SpringSCAServiceElement; |
| import org.apache.tuscany.sca.implementation.spring.xml.SpringXMLBeanDefinitionLoader; |
| import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; |
| import org.apache.tuscany.sca.interfacedef.java.JavaInterface; |
| import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; |
| import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; |
| import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper; |
| import org.apache.tuscany.sca.monitor.Monitor; |
| import org.apache.tuscany.sca.monitor.Problem; |
| import org.apache.tuscany.sca.monitor.Problem.Severity; |
| import org.apache.tuscany.sca.policy.Intent; |
| import org.apache.tuscany.sca.policy.PolicyFactory; |
| import org.apache.tuscany.sca.policy.PolicySet; |
| |
| /** |
| * Introspects a Spring XML application-context configuration file to create <implementation-spring../> |
| * component type information. |
| * |
| * @version $Rev$ $Date$ |
| */ |
| public class SpringXMLComponentTypeLoader { |
| private final static Logger log = Logger.getLogger(SpringXMLComponentTypeLoader.class.getName()); |
| |
| private ExtensionPointRegistry registry; |
| private ContributionFactory contributionFactory; |
| private AssemblyFactory assemblyFactory; |
| private PolicyFactory policyFactory; |
| private JavaInterfaceFactory javaFactory; |
| private SpringBeanIntrospector beanIntrospector; |
| |
| private SpringXMLBeanDefinitionLoader xmlBeanDefinitionLoader; |
| |
| public SpringXMLComponentTypeLoader(ExtensionPointRegistry registry) { |
| super(); |
| this.registry = registry; |
| FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); |
| this.assemblyFactory = factories.getFactory(AssemblyFactory.class); |
| this.policyFactory = factories.getFactory(PolicyFactory.class); |
| this.javaFactory = factories.getFactory(JavaInterfaceFactory.class); |
| this.contributionFactory = factories.getFactory(ContributionFactory.class); |
| this.xmlBeanDefinitionLoader = |
| registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(SpringXMLBeanDefinitionLoader.class); |
| } |
| |
| /** |
| * Report a error. |
| * |
| * @param problems |
| * @param message |
| * @param model |
| */ |
| private void error(Monitor monitor, String message, Object model, Object... messageParameters) { |
| if (monitor != null) { |
| Problem problem = |
| monitor.createProblem(this.getClass().getName(), |
| "impl-spring-validation-messages", |
| Severity.ERROR, |
| model, |
| message, |
| (Object[])messageParameters); |
| monitor.problem(problem); |
| } |
| } |
| /** |
| * Report a error. |
| * |
| * @param problems |
| * @param message |
| * @param model |
| */ |
| private void warning(Monitor monitor, String message, Object model, Object... messageParameters) { |
| if (monitor != null) { |
| Problem problem = |
| monitor.createProblem(this.getClass().getName(), |
| "impl-spring-validation-messages", |
| Severity.WARNING, |
| model, |
| message, |
| (Object[])messageParameters); |
| monitor.problem(problem); |
| } |
| } |
| protected Class<SpringImplementation> getImplementationClass() { |
| return SpringImplementation.class; |
| } |
| |
| /** |
| * Base method which loads the component type from the application-context attached to the |
| * Spring implementation |
| * |
| */ |
| public void load(SpringImplementation implementation, ModelResolver resolver, ProcessorContext context) |
| throws ContributionReadException { |
| //System.out.println("Spring TypeLoader - load method start"); |
| ComponentType componentType = implementation.getComponentType(); |
| /* Check that there is a component type object already set */ |
| if (componentType == null) { |
| throw new ContributionReadException("SpringXMLLoader load: implementation has no ComponentType object"); |
| } |
| if (componentType.isUnresolved()) { |
| /* Fetch the location of the application-context file from the implementation */ |
| loadFromXML(implementation, resolver, context); |
| if (!componentType.isUnresolved()) |
| implementation.setUnresolved(false); |
| } // end if |
| //System.out.println("Spring TypeLoader - load method complete"); |
| } // end method load |
| |
| private Class<?> resolveClass(ModelResolver resolver, String className, ProcessorContext context) |
| throws ClassNotFoundException { |
| ClassReference classReference = new ClassReference(className); |
| classReference = resolver.resolveModel(ClassReference.class, classReference, context); |
| if (classReference.isUnresolved()) { |
| throw new ClassNotFoundException(className); |
| } |
| Class<?> javaClass = classReference.getJavaClass(); |
| return javaClass; |
| } |
| |
| /** |
| * Method which fills out the component type for a Spring implementation by reading the |
| * Spring application-context.xml file. |
| * |
| * @param implementation SpringImplementation into which to load the component type information |
| * @throws ContributionReadException Failed to read the contribution |
| */ |
| private void loadFromXML(SpringImplementation implementation, ModelResolver resolver, ProcessorContext context) |
| throws ContributionReadException { |
| List<SpringBeanElement> beans = new ArrayList<SpringBeanElement>(); |
| List<SpringSCAServiceElement> services = new ArrayList<SpringSCAServiceElement>(); |
| List<SpringSCAReferenceElement> references = new ArrayList<SpringSCAReferenceElement>(); |
| List<SpringSCAPropertyElement> scaproperties = new ArrayList<SpringSCAPropertyElement>(); |
| |
| URL resource; |
| List<URL> contextResources = new ArrayList<URL>(); |
| String contextPath = implementation.getLocation(); |
| |
| try { |
| resource = resolveLocation(resolver, contextPath, context); |
| contextResources = getApplicationContextResource(resource); |
| |
| implementation.setClassLoader(new ContextClassLoader(resolver, context)); |
| implementation.setResource(contextResources); |
| // The URI is used to uniquely identify the Implementation |
| implementation.setURI(resource.toString()); |
| |
| List<SpringBeanElement> appCxtBeans = new ArrayList<SpringBeanElement>(); |
| List<SpringSCAServiceElement> appCxtServices = new ArrayList<SpringSCAServiceElement>(); |
| List<SpringSCAReferenceElement> appCxtReferences = new ArrayList<SpringSCAReferenceElement>(); |
| List<SpringSCAPropertyElement> appCxtProperties = new ArrayList<SpringSCAPropertyElement>(); |
| |
| if (xmlBeanDefinitionLoader != null) { |
| xmlBeanDefinitionLoader.load(contextResources, |
| appCxtServices, |
| appCxtReferences, |
| appCxtProperties, |
| appCxtBeans, |
| context); |
| populatePolicies(appCxtServices, appCxtReferences); |
| } |
| // Validate the beans from individual application context for uniqueness |
| validateBeans(appCxtBeans, appCxtServices, appCxtReferences, appCxtProperties, context.getMonitor()); |
| // Add all the validated beans to the generic list |
| beans.addAll(appCxtBeans); |
| services.addAll(appCxtServices); |
| references.addAll(appCxtReferences); |
| scaproperties.addAll(appCxtProperties); |
| } catch (Throwable e) { |
| throw new ContributionReadException(e); |
| } |
| |
| /* At this point, the complete application-context.xml file has been read and its contents */ |
| /* stored in the lists of beans, services, references. These are now used to generate */ |
| /* the implied componentType for the application context */ |
| generateComponentType(implementation, resolver, beans, services, references, scaproperties, context); |
| |
| return; |
| } // end method loadFromXML |
| |
| public void populatePolicies(List<SpringSCAServiceElement> appCxtServices, |
| List<SpringSCAReferenceElement> appCxtReferences) { |
| for (SpringSCAReferenceElement e : appCxtReferences) { |
| for (QName qn : e.getIntentNames()) { |
| Intent intent = policyFactory.createIntent(); |
| intent.setName(qn); |
| e.getRequiredIntents().add(intent); |
| } |
| for (QName qn : e.getPolicySetNames()) { |
| PolicySet ps = policyFactory.createPolicySet(); |
| ps.setName(qn); |
| e.getPolicySets().add(ps); |
| } |
| } |
| |
| for (SpringSCAServiceElement e : appCxtServices) { |
| for (QName qn : e.getIntentNames()) { |
| Intent intent = policyFactory.createIntent(); |
| intent.setName(qn); |
| e.getRequiredIntents().add(intent); |
| } |
| for (QName qn : e.getPolicySetNames()) { |
| PolicySet ps = policyFactory.createPolicySet(); |
| ps.setName(qn); |
| e.getPolicySets().add(ps); |
| } |
| } |
| } |
| |
| private URL resolveLocation(ModelResolver resolver, String contextPath, ProcessorContext context) |
| throws MalformedURLException, ContributionReadException { |
| URL resource = null; |
| URI uri = URI.create(contextPath); |
| if (!uri.isAbsolute()) { |
| Artifact parent = context.getArtifact(); |
| if (parent != null && parent.getURI() != null) { |
| URI base = URI.create("/" + parent.getURI()); |
| uri = base.resolve(uri); |
| // Remove the leading / to make artifact resolver happy |
| if (uri.toString().startsWith("/")) { |
| uri = URI.create(uri.toString().substring(1)); |
| } |
| } |
| Artifact artifact = contributionFactory.createArtifact(); |
| artifact.setUnresolved(true); |
| artifact.setURI(uri.toString()); |
| artifact = resolver.resolveModel(Artifact.class, artifact, context); |
| if (!artifact.isUnresolved()) { |
| resource = new URL(artifact.getLocation()); |
| } else { |
| // The resource can be out of scope of the contribution root |
| if (parent != null && parent.getLocation() != null) { |
| resource = new URL(new URL(parent.getLocation()), contextPath); |
| return resource; |
| } |
| throw new ContributionReadException("Location cannot be resloved: " + contextPath); |
| } |
| } else { |
| resource = new URL(contextPath); |
| } |
| return resource; |
| } |
| |
| /** |
| * Generates the Spring implementation component type from the configuration contained in the |
| * lists of beans, services, references and scaproperties derived from the application context |
| */ |
| private void generateComponentType(SpringImplementation implementation, |
| ModelResolver resolver, |
| List<SpringBeanElement> beans, |
| List<SpringSCAServiceElement> services, |
| List<SpringSCAReferenceElement> references, |
| List<SpringSCAPropertyElement> scaproperties, |
| ProcessorContext context) throws ContributionReadException { |
| /* |
| * 1. Each sca:service becomes a service in the component type |
| * 2. Each sca:reference becomes a reference in the component type |
| * 3. Each sca:property becomes a property in the component type |
| * 4. IF there are no explicit service elements, each bean becomes a service |
| * 5. Each bean property which is a reference not pointing at another bean in the |
| * application context becomes a reference unless it is pointing at one of the references |
| * 6. Each bean property which is not a reference and which is not pointing |
| * at another bean in the application context becomes a property in the component type |
| */ |
| |
| JavaImplementation javaImplementation = null; |
| ComponentType componentType = implementation.getComponentType(); |
| |
| try { |
| // Deal with the services first.... |
| Iterator<SpringSCAServiceElement> its = services.iterator(); |
| while (its.hasNext()) { |
| SpringSCAServiceElement serviceElement = its.next(); |
| Class<?> interfaze = resolveClass(resolver, serviceElement.getType(), context); |
| Service theService = createService(interfaze, serviceElement.getName()); |
| // Spring allows duplication of bean definitions in multiple context scenario, |
| // in such cases, the latest bean definition overrides the older ones, hence |
| // we will remove any older definition and use the latest. |
| Service duplicate = null; |
| for (Service service : componentType.getServices()) { |
| if (service.getName().equals(theService.getName())) |
| duplicate = service; |
| } |
| if (duplicate != null) |
| componentType.getServices().remove(duplicate); |
| |
| componentType.getServices().add(theService); |
| // Add this service to the Service / Bean map |
| String beanName = serviceElement.getTarget(); |
| boolean found = false; |
| for (SpringBeanElement beanElement : beans) { |
| if (beanName.equals(beanElement.getId())) { |
| if (isValidBeanForService(beanElement)) { |
| // add the required intents and policySets for the service |
| theService.getRequiredIntents().addAll(serviceElement.getRequiredIntents()); |
| theService.getPolicySets().addAll(serviceElement.getPolicySets()); |
| implementation.setBeanForService(theService, beanElement); |
| found = true; |
| break; |
| } |
| } |
| } // end for |
| |
| if (!found) { |
| // REVIEW: Adding a SpringBeanElement "proxy" so that the bean id can be used at runtime to look |
| // up the bean instance from the parent context |
| implementation.setBeanForService(theService, |
| new SpringBeanElement(serviceElement.getTarget(), null)); |
| } |
| } // end while |
| |
| // Next handle the references |
| Iterator<SpringSCAReferenceElement> itr = references.iterator(); |
| while (itr.hasNext()) { |
| SpringSCAReferenceElement referenceElement = itr.next(); |
| Class<?> interfaze = resolveClass(resolver, referenceElement.getType(), context); |
| Reference theReference = createReference(interfaze, referenceElement.getName()); |
| // Override the older bean definition with the latest ones |
| // for the duplicate definitions found. |
| Reference duplicate = null; |
| for (Reference reference : componentType.getReferences()) { |
| if (reference.getName().equals(theReference.getName())) |
| duplicate = reference; |
| } |
| if (duplicate != null) |
| componentType.getReferences().remove(duplicate); |
| |
| // add the required intents and policySets for this reference |
| theReference.getRequiredIntents().addAll(referenceElement.getRequiredIntents()); |
| theReference.getPolicySets().addAll(referenceElement.getPolicySets()); |
| componentType.getReferences().add(theReference); |
| } // end while |
| |
| // Next handle the properties |
| Iterator<SpringSCAPropertyElement> itsp = scaproperties.iterator(); |
| while (itsp.hasNext()) { |
| SpringSCAPropertyElement scaproperty = itsp.next(); |
| // Create a component type property if the SCA property element has a name |
| // and a type declared... |
| if (scaproperty.getType() != null && scaproperty.getName() != null) { |
| Property theProperty = assemblyFactory.createProperty(); |
| theProperty.setName(scaproperty.getName()); |
| // Get the Java class and then an XSD element type for the property |
| Class<?> propType = Class.forName(scaproperty.getType()); |
| theProperty.setXSDType(JavaXMLMapper.getXMLType(propType)); |
| // Override the older bean definition with the latest ones |
| // for the duplicate definitions found. |
| Property duplicate = null; |
| for (Property property : componentType.getProperties()) { |
| if (property.getName().equals(theProperty.getName())) |
| duplicate = property; |
| } |
| if (duplicate != null) |
| componentType.getProperties().remove(duplicate); |
| |
| componentType.getProperties().add(theProperty); |
| // Remember the Java Class (ie the type) for this property |
| implementation.setPropertyClass(theProperty.getName(), propType); |
| } // end if |
| } // end while |
| |
| // Finally deal with the beans |
| Iterator<SpringBeanElement> itb; |
| // If there are no explicit service elements, then expose all the beans |
| if (services.isEmpty()) { |
| itb = beans.iterator(); |
| // Loop through all the beans found |
| while (itb.hasNext()) { |
| SpringBeanElement beanElement = itb.next(); |
| |
| // If its not a valid bean for service, ignore it |
| if (!isValidBeanForService(beanElement)) { |
| continue; |
| } |
| try { |
| // Load the Spring bean class |
| Class<?> beanClass = resolveClass(resolver, beanElement.getClassName(), context); |
| // Introspect the bean |
| beanIntrospector = new SpringBeanIntrospector(registry, beanElement.getCustructorArgs()); |
| ComponentType beanComponentType = assemblyFactory.createComponentType(); |
| javaImplementation = beanIntrospector.introspectBean(beanClass, beanComponentType); |
| // Set the service name as bean name |
| for (Service componentService : beanComponentType.getServices()) { |
| componentService.setName(beanElement.getId()); |
| } |
| // Get the service interface defined by this Spring Bean and add to |
| // the component type of the Spring Assembly |
| List<Service> beanServices = beanComponentType.getServices(); |
| componentType.getServices().addAll(beanServices); |
| // Add these services to the Service / Bean map |
| for (Service beanService : beanServices) { |
| implementation.setBeanForService(beanService, beanElement); |
| } |
| } catch (Throwable e) { |
| // [rfeng] FIXME: Some Spring beans have constructors that take pararemters injected by Spring and |
| // Tuscany is not happy with that during the introspection |
| log.log(Level.SEVERE, e.getMessage(), e); |
| } |
| } // end while |
| } // end if |
| |
| itb = beans.iterator(); |
| while (itb.hasNext()) { |
| SpringBeanElement beanElement = itb.next(); |
| |
| // If its not a valid bean for service, ignore it |
| if (!isValidBeanForService(beanElement)) { |
| continue; |
| } |
| // Ignore if the bean has no properties and constructor arguments |
| if (beanElement.getProperties().isEmpty() && beanElement.getCustructorArgs().isEmpty()) |
| continue; |
| |
| ComponentType beanComponentType = assemblyFactory.createComponentType(); |
| |
| try { |
| Class<?> beanClass = resolveClass(resolver, beanElement.getClassName(), context); |
| // Introspect the bean |
| beanIntrospector = new SpringBeanIntrospector(registry, beanElement.getCustructorArgs()); |
| javaImplementation = beanIntrospector.introspectBean(beanClass, beanComponentType); |
| } catch (Exception e) { |
| // [rfeng] FIXME: Some Spring beans have constructors that take pararemters injected by Spring and |
| // Tuscany is not happy with that during the introspection |
| log.log(Level.SEVERE, e.getMessage(), e); |
| continue; |
| } |
| Map<String, JavaElementImpl> propertyMap = javaImplementation.getPropertyMembers(); |
| JavaConstructorImpl constructor = javaImplementation.getConstructor(); |
| // Get the references by this Spring Bean and add the unresolved ones to |
| // the component type of the Spring Assembly |
| List<Reference> beanReferences = beanComponentType.getReferences(); |
| List<Property> beanProperties = beanComponentType.getProperties(); |
| |
| Set<String> excludedNames = new HashSet<String>(); |
| Iterator<SpringPropertyElement> itp = beanElement.getProperties().iterator(); |
| while (itp.hasNext()) { |
| SpringPropertyElement propertyElement = itp.next(); |
| // Exclude the reference that is also known as a spring property |
| excludedNames.add(propertyElement.getName()); |
| for (String propertyRef : propertyElement.getRefs()) { |
| if (propertyRefUnresolved(propertyRef, beans, references, scaproperties)) { |
| // This means an unresolved reference from the spring bean... |
| for (Reference reference : beanReferences) { |
| if (propertyElement.getName().equals(reference.getName())) { |
| // The name of the reference in this case is the string in |
| // the @ref attribute of the Spring property element, NOT the |
| // name of the field in the Spring bean.... |
| reference.setName(propertyRef); |
| componentType.getReferences().add(reference); |
| break; |
| } // end if |
| } // end for |
| |
| // Store the unresolved references as unresolvedBeanRef in the Spring Implementation type |
| for (Property scaproperty : beanProperties) { |
| if (propertyElement.getName().equals(scaproperty.getName())) { |
| // The name of the reference in this case is the string in |
| // the @ref attribute of the Spring property element, NOT the |
| // name of the field in the Spring bean.... |
| Class<?> interfaze = |
| resolveClass(resolver, |
| (propertyMap.get(propertyElement.getName()).getType()).getName(), |
| context); |
| Reference theReference = createReference(interfaze, propertyRef); |
| implementation.setUnresolvedBeanRef(propertyRef, theReference); |
| break; |
| } // end if |
| } // end for |
| } // end if |
| } // end for |
| } // end while |
| |
| Iterator<SpringConstructorArgElement> itcr = beanElement.getCustructorArgs().iterator(); |
| while (itcr.hasNext()) { |
| SpringConstructorArgElement conArgElement = itcr.next(); |
| for (String constructorArgRef : conArgElement.getRefs()) { |
| if (propertyRefUnresolved(constructorArgRef, beans, references, scaproperties)) { |
| for (JavaParameterImpl parameter : constructor.getParameters()) { |
| String paramType = parameter.getType().getName(); |
| Class<?> interfaze = resolveClass(resolver, paramType, context); |
| // Create a component type reference/property if the constructor-arg element has a |
| // type attribute OR index attribute declared... |
| if ((conArgElement.getType() != null && paramType.equals(conArgElement.getType())) || (conArgElement |
| .getIndex() != -1 && (conArgElement.getIndex() == parameter.getIndex()))) { |
| // [rfeng] Commenting out the following code as the constructor parameter based SCA |
| // references are added already |
| /* |
| if (parameter.getClassifer() == org.oasisopen.sca.annotation.Reference.class) { |
| Reference theReference = createReference(interfaze, constructorArgRef); |
| componentType.getReferences().add(theReference); |
| } |
| */ |
| if (parameter.getClassifer() == org.oasisopen.sca.annotation.Property.class) { |
| // Store the unresolved references as unresolvedBeanRef in the Spring Implementation type |
| // we might need to verify with the component definition later. |
| Reference theReference = createReference(interfaze, constructorArgRef); |
| implementation.setUnresolvedBeanRef(constructorArgRef, theReference); |
| } |
| } |
| } // end for |
| } // end if |
| } // end for |
| } // end while |
| |
| // [rfeng] Add the remaining introspected references (w/ @Reference but without Spring property ref) |
| for (Reference ref : beanReferences) { |
| if (!excludedNames.contains(ref.getName()) && componentType.getReference(ref.getName()) == null) { |
| // Only add the ones that not listed by sca:reference |
| componentType.getReferences().add(ref); |
| } |
| } |
| |
| } // end while |
| |
| } catch (ClassNotFoundException e) { |
| // Means that either an interface class, property class or a bean was not found |
| throw new ContributionReadException(e); |
| } catch (InvalidInterfaceException e) { |
| throw new ContributionReadException(e); |
| } // end try |
| |
| // If we get here, the Spring assembly component type is resolved |
| componentType.setUnresolved(false); |
| implementation.setComponentType(componentType); |
| return; |
| } // end method generateComponentType |
| |
| /* |
| * Determines whether a reference attribute of a Spring property element is resolved either |
| * by a bean in the application context or by an SCA reference element or by an SCA property |
| * element |
| * @param ref - a String containing the name of the reference - may be null |
| * @param beans - a List of SpringBean elements |
| * @param references - a List of SCA reference elements |
| * @return true if the property is not resolved, false if it is resolved |
| */ |
| private boolean propertyRefUnresolved(String ref, |
| List<SpringBeanElement> beans, |
| List<SpringSCAReferenceElement> references, |
| List<SpringSCAPropertyElement> scaproperties) { |
| boolean unresolved = true; |
| |
| if (ref != null) { |
| // Scan over the beans looking for a match |
| Iterator<SpringBeanElement> itb = beans.iterator(); |
| while (itb.hasNext()) { |
| SpringBeanElement beanElement = itb.next(); |
| // Does the bean name match the ref? |
| if (ref.equals(beanElement.getId())) { |
| unresolved = false; |
| break; |
| } // end if |
| } // end while |
| // Scan over the SCA reference elements looking for a match |
| if (unresolved) { |
| Iterator<SpringSCAReferenceElement> itr = references.iterator(); |
| while (itr.hasNext()) { |
| SpringSCAReferenceElement referenceElement = itr.next(); |
| if (ref.equals(referenceElement.getName())) { |
| unresolved = false; |
| break; |
| } // end if |
| } // end while |
| } // end if |
| // Scan over the SCA property elements looking for a match |
| if (unresolved) { |
| Iterator<SpringSCAPropertyElement> itsp = scaproperties.iterator(); |
| while (itsp.hasNext()) { |
| SpringSCAPropertyElement propertyElement = itsp.next(); |
| if (ref.equals(propertyElement.getName())) { |
| unresolved = false; |
| break; |
| } // end if |
| } // end while |
| } // end if |
| } else { |
| // In the case where ref = null, the property is not going to be a reference of any |
| // kind and can be ignored |
| unresolved = false; |
| } // end if |
| |
| return unresolved; |
| |
| } // end method propertyRefUnresolved |
| |
| /** |
| * Validates whether the <sca:service>, <sca:reference> and <sca:property> elements |
| * has unique names within the application context. |
| */ |
| private void validateBeans(List<SpringBeanElement> beans, |
| List<SpringSCAServiceElement> services, |
| List<SpringSCAReferenceElement> references, |
| List<SpringSCAPropertyElement> scaproperties, |
| Monitor monitor) throws ContributionReadException { |
| |
| // The @target attribute of a <service/> subelement of a <beans/> element |
| // MUST have the value of the @name attribute of one of the <bean/> |
| // subelements of the <beans/> element. |
| Iterator<SpringSCAServiceElement> its = services.iterator(); |
| while (its.hasNext()) { |
| SpringSCAServiceElement serviceElement = its.next(); |
| boolean targetBeanExists = false; |
| Iterator<SpringBeanElement> itb = beans.iterator(); |
| while (itb.hasNext()) { |
| SpringBeanElement beanElement = itb.next(); |
| if (serviceElement.getTarget().equals(beanElement.getId())) |
| targetBeanExists = true; |
| } |
| if (!targetBeanExists) { |
| // REVIEW: [rfeng] The target bean can exist in the parent Spring application context which we don't know |
| // until runtime |
| warning(monitor, "TargetBeanDoesNotExist", beans); |
| } |
| } // end while |
| |
| // The value of the @name attribute of an <sca:reference/> subelement of a <beans/> |
| // element MUST be unique amongst the @name attributes of the <sca:property/> |
| // subelements and the <bean/> subelements of the <beans/> element. |
| // AND |
| // The @default attribute of a <sca:reference/> subelement of a <beans/> |
| // element MUST have the value of the @name attribute of one of the <bean/> |
| // subelements of the <beans/> element. |
| Iterator<SpringSCAReferenceElement> itr = references.iterator(); |
| while (itr.hasNext()) { |
| SpringSCAReferenceElement referenceElement = itr.next(); |
| boolean defaultBeanExists = true; |
| boolean isUniqueReferenceName = true; |
| Iterator<SpringBeanElement> itb = beans.iterator(); |
| while (itb.hasNext()) { |
| SpringBeanElement beanElement = itb.next(); |
| if (referenceElement.getDefaultBean() != null) |
| if (referenceElement.getDefaultBean().equals(beanElement.getId())) |
| defaultBeanExists = false; |
| if (referenceElement.getName().equals(beanElement.getId())) |
| isUniqueReferenceName = false; |
| } |
| Iterator<SpringSCAPropertyElement> itp = scaproperties.iterator(); |
| while (itp.hasNext()) { |
| SpringSCAPropertyElement propertyElement = itp.next(); |
| if (referenceElement.getName().equals(propertyElement.getName())) |
| isUniqueReferenceName = false; |
| } |
| if (!defaultBeanExists) |
| error(monitor, "DefaultBeanDoesNotExist", beans); |
| if (!isUniqueReferenceName) |
| error(monitor, "ScaReferenceNameNotUnique", beans); |
| } // end while |
| |
| // The value of the @name attribute of an <sca:property/> subelement of a <beans/> |
| // element MUST be unique amongst the @name attributes of the <sca:reference/> |
| // subelements and the <bean/> subelements of the <beans/> element. |
| Iterator<SpringSCAPropertyElement> itp = scaproperties.iterator(); |
| while (itp.hasNext()) { |
| SpringSCAPropertyElement propertyElement = itp.next(); |
| boolean isUniquePropertyName = true; |
| Iterator<SpringBeanElement> itb = beans.iterator(); |
| while (itb.hasNext()) { |
| SpringBeanElement beanElement = itb.next(); |
| if (propertyElement.getName().equals(beanElement.getId())) |
| isUniquePropertyName = false; |
| } |
| Iterator<SpringSCAReferenceElement> itrp = references.iterator(); |
| while (itrp.hasNext()) { |
| SpringSCAReferenceElement referenceElement = itrp.next(); |
| if (propertyElement.getName().equals(referenceElement.getName())) |
| isUniquePropertyName = false; |
| } |
| if (!isUniquePropertyName) |
| error(monitor, "ScaPropertyNameNotUnique", beans); |
| } // end while |
| } |
| |
| /** |
| * Validates whether a bean definition is valid for exposing as service. |
| */ |
| private boolean isValidBeanForService(SpringBeanElement beanElement) { |
| |
| if (beanElement.isInnerBean()) |
| return false; |
| if (beanElement.hasParentAttribute()) |
| return false; |
| if (beanElement.hasFactoryMethodAttribute()) |
| return false; |
| if (beanElement.hasFactoryBeanAttribute()) |
| return false; |
| if (beanElement.getClassName() == null) |
| return false; |
| if (beanElement.getClassName().startsWith("org.springframework")) |
| return false; |
| // return true otherwise |
| return true; |
| } |
| |
| /** |
| * Gets hold of the application-context.xml file as a Spring resource |
| * @param locationAttr - the location attribute from the <implementation.spring../> element |
| * @param cl - the ClassLoader for the Spring implementation |
| */ |
| protected List<URL> getApplicationContextResource(URL url) throws ContributionReadException { |
| File manifestFile = null; |
| File appXmlFile; |
| File appXmlFolder; |
| File locationFile = null; |
| List<URL> appCtxResources = new ArrayList<URL>(); |
| |
| if (url != null) { |
| String path = url.getPath(); |
| locationFile = new File(path); |
| } else { |
| throw new ContributionReadException( |
| "SpringXMLComponentTypeLoader getApplicationContextResource: " + "unable to find resource file " |
| + url); |
| } |
| |
| if (locationFile.isDirectory()) { |
| try { |
| manifestFile = new File(locationFile, "META-INF" + File.separator + "MANIFEST.MF"); |
| if (manifestFile.exists()) { |
| Manifest mf = new Manifest(new FileInputStream(manifestFile)); |
| Attributes mainAttrs = mf.getMainAttributes(); |
| String appCtxPath = mainAttrs.getValue("Spring-Context"); |
| if (appCtxPath != null) { |
| String[] cxtPaths = appCtxPath.split(";"); |
| for (String path : cxtPaths) { |
| appXmlFile = new File(locationFile, path.trim()); |
| if (appXmlFile.exists()) { |
| appCtxResources.add(appXmlFile.toURI().toURL()); |
| } |
| } |
| return appCtxResources; |
| } |
| } |
| // No MANIFEST.MF file OR no manifest-specified Spring context , then read all the |
| // xml files available in the META-INF/spring folder. |
| appXmlFolder = new File(locationFile, "META-INF" + File.separator + "spring"); |
| if (appXmlFolder.exists()) { |
| File[] files = appXmlFolder.listFiles(); |
| for (File appFile : files) { |
| if (appFile.getName().endsWith(".xml")) { |
| appCtxResources.add(appFile.toURI().toURL()); |
| } |
| } |
| return appCtxResources; |
| } |
| } catch (IOException e) { |
| throw new ContributionReadException("Error reading manifest " + manifestFile); |
| } |
| } else { |
| if (locationFile.isFile() && locationFile.getName().endsWith(".jar")) { |
| try { |
| JarFile jf = new JarFile(locationFile); |
| JarEntry je; |
| Manifest mf = jf.getManifest(); |
| if (mf != null) { |
| Attributes mainAttrs = mf.getMainAttributes(); |
| String appCtxPath = mainAttrs.getValue("Spring-Context"); |
| if (appCtxPath != null) { |
| String[] cxtPaths = appCtxPath.split(";"); |
| for (String path : cxtPaths) { |
| je = jf.getJarEntry(path.trim()); |
| if (je != null) |
| appCtxResources.add(new URL("jar:" + locationFile.toURI().toURL() |
| + "!/" |
| + appCtxPath)); |
| } |
| return appCtxResources; |
| } |
| } |
| // No MANIFEST.MF file OR no manifest-specified Spring context , then read all the |
| // .xml files available in the META-INF/spring folder. |
| Enumeration<JarEntry> entries = jf.entries(); |
| while (entries.hasMoreElements()) { |
| je = entries.nextElement(); |
| if (je.getName().startsWith("META-INF/spring/") && je.getName().endsWith(".xml")) { |
| appCtxResources.add(new URL("jar:" + locationFile.toURI().toURL() + "!/" + je.getName())); |
| } |
| } |
| return appCtxResources; |
| } catch (IOException e) { |
| // TODO: create a more appropriate exception type |
| throw new ContributionReadException( |
| "SpringXMLComponentTypeLoader getApplicationContextResource: " + " IO exception reading context file.", |
| e); |
| } |
| } else { |
| if (locationFile.getName().endsWith(".xml")) { |
| appCtxResources.add(url); |
| return appCtxResources; |
| } else { |
| // Deal with the directory inside a jar file, in case the contribution itself is a JAR file. |
| try { |
| if (locationFile.getPath().indexOf(".jar") > 0) { |
| String jarPath = url.getPath().substring(5, url.getPath().indexOf("!")); |
| JarFile jf = new JarFile(jarPath); |
| JarEntry je = |
| jf.getJarEntry(url.getPath().substring(url.getPath().indexOf("!/") + 2) + "/" |
| + "META-INF" |
| + "/" |
| + "MANIFEST.MF"); |
| if (je != null) { |
| Manifest mf = new Manifest(jf.getInputStream(je)); |
| Attributes mainAttrs = mf.getMainAttributes(); |
| String appCtxPath = mainAttrs.getValue("Spring-Context"); |
| if (appCtxPath != null) { |
| String[] cxtPaths = appCtxPath.split(";"); |
| for (String path : cxtPaths) { |
| je = |
| jf.getJarEntry(url.getPath().substring(url.getPath().indexOf("!/") + 2) + "/" |
| + path.trim()); |
| if (je != null) { |
| appCtxResources.add(new URL("jar:" + url.getPath() + "/" + path.trim())); |
| } |
| } |
| return appCtxResources; |
| } |
| } |
| // No MANIFEST.MF file OR no manifest-specified Spring context , then read all the |
| // .xml files available in the META-INF/spring folder. |
| Enumeration<JarEntry> entries = jf.entries(); |
| while (entries.hasMoreElements()) { |
| je = entries.nextElement(); |
| if (je.getName().startsWith("META-INF/spring/") && je.getName().endsWith(".xml")) { |
| appCtxResources.add(new URL("jar:" + url.getPath() + "/" + je.getName())); |
| } |
| } |
| return appCtxResources; |
| } |
| } catch (IOException e) { |
| throw new ContributionReadException("Error reading manifest " + manifestFile); |
| } |
| } |
| } |
| } |
| |
| throw new ContributionReadException( |
| "SpringXMLComponentTypeLoader getApplicationContextResource: " + "unable to read resource file " |
| + url); |
| } // end method getApplicationContextResource |
| |
| /** |
| * Creates a Service for the component type based on its name and Java interface |
| */ |
| public Service createService(Class<?> interfaze, String name) throws InvalidInterfaceException { |
| Service service = assemblyFactory.createService(); |
| JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); |
| service.setInterfaceContract(interfaceContract); |
| |
| // Set the name for the service |
| service.setName(name); |
| |
| // Set the call interface and, if present, the callback interface |
| JavaInterface callInterface = javaFactory.createJavaInterface(interfaze); |
| service.getInterfaceContract().setInterface(callInterface); |
| if (callInterface.getCallbackClass() != null) { |
| JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); |
| service.getInterfaceContract().setCallbackInterface(callbackInterface); |
| } |
| return service; |
| } // end method createService |
| |
| /** |
| * Creates a Reference for the component type based on its name and Java interface |
| */ |
| private org.apache.tuscany.sca.assembly.Reference createReference(Class<?> interfaze, String name) |
| throws InvalidInterfaceException { |
| org.apache.tuscany.sca.assembly.Reference reference = assemblyFactory.createReference(); |
| JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); |
| reference.setInterfaceContract(interfaceContract); |
| |
| // Set the name of the reference to the supplied name and the multiplicity of the reference |
| // to 1..1 - for Spring implementations, this is the only multiplicity supported |
| reference.setName(name); |
| reference.setMultiplicity(Multiplicity.ONE_ONE); |
| |
| // Set the call interface and, if present, the callback interface |
| JavaInterface callInterface = javaFactory.createJavaInterface(interfaze); |
| reference.getInterfaceContract().setInterface(callInterface); |
| if (callInterface.getCallbackClass() != null) { |
| JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); |
| reference.getInterfaceContract().setCallbackInterface(callbackInterface); |
| } |
| |
| return reference; |
| } |
| |
| private class ContextClassLoader extends ClassLoader { |
| public ContextClassLoader(ModelResolver resolver, ProcessorContext context) { |
| super(); |
| this.resolver = resolver; |
| this.context = context; |
| } |
| |
| private ModelResolver resolver; |
| private ProcessorContext context; |
| |
| @Override |
| protected Class<?> findClass(String name) throws ClassNotFoundException { |
| return SpringXMLComponentTypeLoader.this.resolveClass(resolver, name, context); |
| } |
| |
| @Override |
| protected URL findResource(String name) { |
| try { |
| return resolveLocation(resolver, name, context); |
| } catch (Exception e) { |
| return null; |
| } |
| } |
| |
| @Override |
| protected Enumeration<URL> findResources(String name) throws IOException { |
| URL url = findResource(name); |
| if (url != null) { |
| return Collections.enumeration(Arrays.asList(url)); |
| } else { |
| Collection<URL> urls = Collections.emptyList(); |
| return Collections.enumeration(urls); |
| } |
| } |
| } |
| } // end class SpringXMLComponentTypeLoader |