diff options
author | dims <dims@13f79535-47bb-0310-9956-ffa450edef68> | 2008-06-17 00:23:01 +0000 |
---|---|---|
committer | dims <dims@13f79535-47bb-0310-9956-ffa450edef68> | 2008-06-17 00:23:01 +0000 |
commit | bdd0a41aed7edf21ec2a65cfa17a86af2ef8c48a (patch) | |
tree | 38a92061c0793434c4be189f1d70c3458b6bc41d /java/sca/modules/implementation-java |
Move Tuscany from Incubator to top level.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@668359 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/sca/modules/implementation-java')
92 files changed, 10429 insertions, 0 deletions
diff --git a/java/sca/modules/implementation-java/LICENSE b/java/sca/modules/implementation-java/LICENSE new file mode 100644 index 0000000000..8aa906c321 --- /dev/null +++ b/java/sca/modules/implementation-java/LICENSE @@ -0,0 +1,205 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + diff --git a/java/sca/modules/implementation-java/NOTICE b/java/sca/modules/implementation-java/NOTICE new file mode 100644 index 0000000000..fdfa0e9faa --- /dev/null +++ b/java/sca/modules/implementation-java/NOTICE @@ -0,0 +1,6 @@ +${pom.name} +Copyright (c) 2005 - 2008 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + diff --git a/java/sca/modules/implementation-java/pom.xml b/java/sca/modules/implementation-java/pom.xml new file mode 100644 index 0000000000..2a9102366f --- /dev/null +++ b/java/sca/modules/implementation-java/pom.xml @@ -0,0 +1,69 @@ +<?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. +--> +<project> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-modules</artifactId> + <version>1.4-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>tuscany-implementation-java</artifactId> + <name>Apache Tuscany SCA Java Implementation Model</name> + + <dependencies> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-assembly</artifactId> + <version>1.4-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-interface-java</artifactId> + <version>1.4-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-sca-api</artifactId> + <version>1.4-SNAPSHOT</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + + <configuration> + <instructions> + <Bundle-Version>${tuscany.version}</Bundle-Version> + <Bundle-SymbolicName>org.apache.tuscany.sca.implementation.java</Bundle-SymbolicName> + <Bundle-Description>${pom.name}</Bundle-Description> + <Export-Package>org.apache.tuscany.sca.implementation.java*</Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/BaseJavaImplementation.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/BaseJavaImplementation.java new file mode 100644 index 0000000000..c8b7c072ac --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/BaseJavaImplementation.java @@ -0,0 +1,59 @@ +/* + * 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.java; + +import org.apache.tuscany.sca.assembly.Extensible; +import org.apache.tuscany.sca.assembly.Implementation; + +/** + * Represents a Java implementation. + * + * @version $Rev$ $Date$ + */ +public interface BaseJavaImplementation extends Implementation, Extensible { + + /** + * Returns the name of the Java implementation class. + * + * @return the name of the Java implementation class + */ + String getName(); + + /** + * Sets the name of the Java implementation class. + * + * @param className the name of the Java implementation class + */ + void setName(String className); + + /** + * Returns the Java implementation class. + * + * @return the Java implementation class + */ + Class<?> getJavaClass(); + + /** + * Sets the Java implementation class. + * + * @param javaClass the Java implementation class + */ + void setJavaClass(Class<?> javaClass); + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/DefaultJavaImplementationFactory.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/DefaultJavaImplementationFactory.java new file mode 100644 index 0000000000..e44ebd7c91 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/DefaultJavaImplementationFactory.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java; + +/** + * A factory for the Java model. + * + * @version $Rev$ $Date$ + */ +import org.apache.tuscany.sca.implementation.java.impl.JavaImplementationFactoryImpl; + +public class DefaultJavaImplementationFactory extends JavaImplementationFactoryImpl implements JavaImplementationFactory { + + public DefaultJavaImplementationFactory() { + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/IntrospectionException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/IntrospectionException.java new file mode 100644 index 0000000000..2198a632c0 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/IntrospectionException.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.java; + +import java.lang.reflect.Member; + +/** + * Denotes a problem processing annotations on a POJO implementation + * + * @version $Rev$ $Date$ + */ +public class IntrospectionException extends Exception { + private static final long serialVersionUID = -361025119035104470L; + private Member member; + + public IntrospectionException() { + } + + public IntrospectionException(String message) { + super(message); + } + + public IntrospectionException(String message, Member member) { + super(message); + this.member = member; + } + + public IntrospectionException(String message, Throwable cause) { + super(message, cause); + } + + public IntrospectionException(Throwable cause) { + super(cause); + } + + public Member getMember() { + return member; + } + + public void setMember(Member member) { + this.member = member; + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementation.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementation.java new file mode 100644 index 0000000000..c49ef21547 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementation.java @@ -0,0 +1,198 @@ +/* + * 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.java; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaScopeImpl; +import org.apache.tuscany.sca.policy.util.PolicyHandlerTuple; + +/** + * Represents a Java implementation. + * + * @version $Rev$ $Date$ + */ +public interface JavaImplementation extends BaseJavaImplementation { + + /** + * Returns the constructor used to instantiate implementation instances. + * + * @return the constructor used to instantiate implementation instances + */ + JavaConstructorImpl<?> getConstructor(); + + /** + * Sets the constructor used to instantiate implementation instances + * + * @param definition the constructor used to instantiate implementation instances + */ + void setConstructor(JavaConstructorImpl<?> definition); + + /** + * Returns the component initializer method. + * + * @return the component initializer method + */ + Method getInitMethod(); + + /** + * Sets the component initializer method. + * + * @param initMethod the component initializer method + */ + void setInitMethod(Method initMethod); + + /** + * Returns the component destructor method. + * + * @return the component destructor method + */ + Method getDestroyMethod(); + + /** + * Sets the component destructor method. + * + * @param destroyMethod the component destructor method + */ + void setDestroyMethod(Method destroyMethod); + + /** + * Returns the resources injected into this implementation. + * + * @return + */ + Map<String, JavaResourceImpl> getResources(); + + /** + * Returns the Java member used to inject a conversation ID. + * + * @return + */ + List<Member> getConversationIDMembers(); + + /** + * Sets the Java member used to inject a conversation ID. + * + * @param conversationIDMember + */ + void addConversationIDMember(Member conversationIDMember); + + /** + * Returns true if AllowsPassReference is set. + * + * @return true if AllowsPassByReference is set + */ + boolean isAllowsPassByReference(); + + /** + * @param allowsPassByReference the allowsPassByReference to set + */ + void setAllowsPassByReference(boolean allowsPassByReference); + + /** + * @return the allowsPassByReferenceMethods + */ + List<Method> getAllowsPassByReferenceMethods(); + + /** + * @param method + * @return + */ + boolean isAllowsPassByReference(Method method); + + /** + * @return the constructors + */ + Map<Constructor, JavaConstructorImpl> getConstructors(); + + /** + * @return the eagerInit + */ + boolean isEagerInit(); + + /** + * @param eagerInit the eagerInit to set + */ + void setEagerInit(boolean eagerInit); + + /** + * @return the callbacks + */ + Map<String, Collection<JavaElementImpl>> getCallbackMembers(); + + /** + * @return the properties + */ + Map<String, JavaElementImpl> getPropertyMembers(); + + /** + * @return the references + */ + Map<String, JavaElementImpl> getReferenceMembers(); + + /** + * @return the scope + */ + JavaScopeImpl getJavaScope(); + + /** + * @param scope the scope to set + */ + void setJavaScope(JavaScopeImpl scope); + + /** + * @return the maxAge + */ + long getMaxAge(); + + /** + * @param maxAge the maxAge to set + */ + void setMaxAge(long maxAge); + + /** + * @return the maxIdleTime + */ + long getMaxIdleTime(); + + /** + * @param maxIdleTime the maxIdleTime to set + */ + void setMaxIdleTime(long maxIdleTime); + + /** + * @return the map of a policy handler class names + */ + Map<ClassLoader, List<PolicyHandlerTuple>> getPolicyHandlerClassNames(); + + /** + * @param policyHandlerClassNames Map of policyhandler class names + */ + void setPolicyHandlerClassNames(Map<ClassLoader, List<PolicyHandlerTuple>> policyHandlerClassNames); + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementationFactory.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementationFactory.java new file mode 100644 index 0000000000..8228c80372 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementationFactory.java @@ -0,0 +1,75 @@ +/* + * 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.java; + +import java.util.List; + +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; + + +/** + * Factory for the Java model + * + * @version $Rev$ $Date$ + */ +public interface JavaImplementationFactory { + + /** + * Creates a new Java implementation model. + * + * @return + */ + JavaImplementation createJavaImplementation(); + + /** + * Creates a new Java implementation model from an implementation class. + * + * @param implementationClass The implementation class to introspect. + * @return + */ + JavaImplementation createJavaImplementation(Class<?> implementationClass) throws IntrospectionException; + + /** + * Creates the contents of a Java implementation model from an implementation class. + * + * @param implementationClass The implementation class to introspect. + * @return + */ + void createJavaImplementation(JavaImplementation javaImplementation, Class<?> implementationClass) throws IntrospectionException; + + /** + * Registers the given visitor. + * + * @param visitor + */ + void addClassVisitor(JavaClassVisitor visitor); + + /** + * Deregisters the given visitor. + */ + void removeClassVisitor(JavaClassVisitor visitor); + + /** + * Returns the list of visitors. + * + * @return + */ + List<JavaClassVisitor> getClassVisitors(); + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/BaseJavaImplementationImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/BaseJavaImplementationImpl.java new file mode 100644 index 0000000000..97773879fa --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/BaseJavaImplementationImpl.java @@ -0,0 +1,89 @@ +/* + * 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.java.impl; + +import org.apache.tuscany.sca.assembly.impl.ImplementationImpl; +import org.apache.tuscany.sca.implementation.java.BaseJavaImplementation; + +/** + * Represents a Java implementation. + * + * @version $Rev$ $Date$ + */ +abstract class BaseJavaImplementationImpl extends ImplementationImpl implements BaseJavaImplementation { + + private String className; + private Class<?> javaClass; + + protected BaseJavaImplementationImpl() { + } + + public String getName() { + if (isUnresolved()) { + return className; + } else if (javaClass != null) { + return javaClass.getName(); + } else { + return null; + } + } + + public void setName(String className) { + if (!isUnresolved()) { + throw new IllegalStateException(); + } + this.className = className; + } + + public Class<?> getJavaClass() { + return javaClass; + } + + public void setJavaClass(Class<?> javaClass) { + this.javaClass = javaClass; + if (this.className == null) { + this.className = javaClass.getName(); + } + } + + @Override + public String toString() { + return getName(); + } + + @Override + public int hashCode() { + return String.valueOf(getName()).hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof BaseJavaImplementation) { + if (getName() != null) { + return getName().equals(((BaseJavaImplementation)obj).getName()); + } else { + return ((BaseJavaImplementation)obj).getName() == null; + } + } else { + return false; + } + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaClassIntrospectorImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaClassIntrospectorImpl.java new file mode 100644 index 0000000000..0bcec3c78f --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaClassIntrospectorImpl.java @@ -0,0 +1,141 @@ +/* + * 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.java.impl; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper; + +/** + * An extensible Java class introspector implementation. + * + * @version $Rev$ $Date$ + */ +public class JavaClassIntrospectorImpl { + + private List<JavaClassVisitor> visitors; + + public JavaClassIntrospectorImpl(List<JavaClassVisitor> visitors) { + this.visitors = visitors; + } + + /** + * JSR-250 PFD recommends the following guidelines for how annotations + * interact with inheritance in order to keep the resulting complexity in + * control: + * <ol> + * <li>Class-level annotations only affect the class they annotate and + * their members, that is, its methods and fields. They never affect a + * member declared by a superclass, even if it is not hidden or overridden + * by the class in question. + * <li>In addition to affecting the annotated class, class-level + * annotations may act as a shorthand for member-level annotations. If a + * member carries a specific member-level annotation, any annotations of the + * same type implied by a class-level annotation are ignored. In other + * words, explicit member-level annotations have priority over member-level + * annotations implied by a class-level annotation. + * <li>The interfaces implemented by a class never contribute annotations + * to the class itself or any of its members. + * <li>Members inherited from a superclass and which are not hidden or + * overridden maintain the annotations they had in the class that declared + * them, including member-level annotations implied by class-level ones. + * <li>Member-level annotations on a hidden or overridden member are always + * ignored. + * </ol> + */ + public void introspectClass(JavaImplementation type, Class<?> clazz) + throws IntrospectionException { + for (JavaClassVisitor extension : visitors) { + extension.visitClass(clazz, type); + } + + for (Constructor<?> constructor : clazz.getConstructors()) { + for (JavaClassVisitor extension : visitors) { + extension.visitConstructor(constructor, type); + // Assuming the visitClass or visitConstructor will populate the + // type.getConstructors + JavaConstructorImpl<?> definition = type.getConstructors().get(constructor); + if (definition != null) { + for (JavaParameterImpl p : definition.getParameters()) { + extension.visitConstructorParameter(p, type); + } + } + } + } + + Set<Field> fields = JavaIntrospectionHelper.getAllPublicAndProtectedFields(clazz, true); + for (Field field : fields) { + for (JavaClassVisitor extension : visitors) { + extension.visitField(field, type); + } + } + + // Check if any private fields have illegal annotations that should be raised as errors + Set<Field> privateFields = JavaIntrospectionHelper.getPrivateFields(clazz); + for (Field field : privateFields) { + for (JavaClassVisitor processor : visitors) { + processor.visitField(field, type); + } + } + + Set<Method> methods = JavaIntrospectionHelper.getAllUniquePublicProtectedMethods(clazz, true); + for (Method method : methods) { + for (JavaClassVisitor processor : visitors) { + processor.visitMethod(method, type); + } + } + + // Check if any private methods have illegal annotations that should be raised as errors + Set<Method> privateMethods = JavaIntrospectionHelper.getPrivateMethods(clazz); + for (Method method : privateMethods) { + for (JavaClassVisitor processor : visitors) { + processor.visitMethod(method, type); + } + } + + Class superClass = clazz.getSuperclass(); + if (superClass != null) { + visitSuperClass(superClass, type); + } + + for (JavaClassVisitor extension : visitors) { + extension.visitEnd(clazz, type); + } + } + + private void visitSuperClass(Class<?> clazz, JavaImplementation type) throws IntrospectionException { + if (!Object.class.equals(clazz)) { + for (JavaClassVisitor extension : visitors) { + extension.visitSuperClass(clazz, type); + } + clazz = clazz.getSuperclass(); + if (clazz != null) { + visitSuperClass(clazz, type); + } + } + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaConstructorImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaConstructorImpl.java new file mode 100644 index 0000000000..c0b04b4b4e --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaConstructorImpl.java @@ -0,0 +1,53 @@ +/* + * 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.java.impl; + +import java.lang.reflect.Constructor; + +/** + * Hold injection information for the constructor used to instantiate a + * component implementation instance + * + * @version $Rev$ $Date$ + */ +public class JavaConstructorImpl<T> { + + private Constructor<T> constructor; + private JavaParameterImpl[] parameters; + + public JavaConstructorImpl(Constructor<T> constructor) { + this.constructor = constructor; + int size = constructor.getParameterTypes().length; + parameters = new JavaParameterImpl[size]; + for (int i = 0; i < size; i++) { + parameters[i] = new JavaParameterImpl(constructor, i); + } + } + + public Constructor<T> getConstructor() { + return constructor; + } + + /** + * @return the parameters + */ + public JavaParameterImpl[] getParameters() { + return parameters; + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaElementImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaElementImpl.java new file mode 100644 index 0000000000..2365298f71 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaElementImpl.java @@ -0,0 +1,224 @@ +/* + * 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.java.impl; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +/** + * This class represents a java element such as a Package, Class, Constructor, + * Field, Method or Parameter. + * + * @version $Rev$ $Date$ + */ +public class JavaElementImpl { + private AnnotatedElement anchor; + private ElementType elementType; + private Class<?> type; + private Type genericType; + private int index = -1; + private String name; + private Class<? extends Annotation> classifer; + + public JavaElementImpl(Package pkg) { + this.anchor = pkg; + this.elementType = ElementType.PACKAGE; + this.name = pkg.getName(); + } + + public JavaElementImpl(Class<?> cls) { + this.anchor = cls; + this.elementType = ElementType.TYPE; + this.type = cls; + this.genericType = cls; + this.name = cls.getName(); + } + + public JavaElementImpl(Field field) { + this.anchor = field; + this.elementType = ElementType.FIELD; + this.type = field.getType(); + this.genericType = field.getGenericType(); + this.name = field.getName(); + } + + public JavaElementImpl(Constructor<?> constructor, int index) { + this.anchor = constructor; + this.elementType = ElementType.PARAMETER; + this.type = constructor.getParameterTypes()[index]; + this.genericType = constructor.getGenericParameterTypes()[index]; + this.index = index; + this.name = ""; + } + + public JavaElementImpl(Method method, int index) { + this.anchor = method; + this.elementType = ElementType.PARAMETER; + this.type = method.getParameterTypes()[index]; + this.genericType = method.getGenericParameterTypes()[index]; + this.index = index; + this.name = ""; + } + + /** + * For testing purpose + * + * @param name + * @param type + * @param classifer TODO + * @param elementType + */ + public JavaElementImpl(String name, Class<?> type, Class<? extends Annotation> classifer) { + super(); + this.type = type; + this.name = name; + this.classifer = classifer; + } + + /** + * @return the anchor + */ + public AnnotatedElement getAnchor() { + return anchor; + } + + /** + * @return the elementType + */ + public ElementType getElementType() { + return elementType; + } + + /** + * @return the genericType + */ + public Type getGenericType() { + return genericType; + } + + /** + * @return the index + */ + public int getIndex() { + return index; + } + + /** + * @return the type + */ + public Class<?> getType() { + return type; + } + + public Annotation[] getAnnotations() { + if (elementType == ElementType.PARAMETER) { + if (anchor instanceof Method) { + // We only care about the method-level annotations + return ((Method)anchor).getAnnotations(); + } + if (anchor instanceof Constructor) { + return ((Constructor)anchor).getParameterAnnotations()[index]; + } + } + return anchor.getAnnotations(); + } + + public <T extends Annotation> T getAnnotation(Class<T> annotationType) { + for (Annotation a : getAnnotations()) { + if (a.annotationType() == annotationType) { + return annotationType.cast(a); + } + } + return null; + } + + @Override + public String toString() { + return anchor.toString() + (elementType == ElementType.PARAMETER ? "[" + index + "]" : ""); + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((anchor == null) ? 0 : anchor.hashCode()); + result = PRIME * result + index; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final JavaElementImpl other = (JavaElementImpl)obj; + if (anchor == null) { + if (other.anchor != null) { + return false; + } + } else if (!anchor.equals(other.anchor)) { + return false; + } + if (index != other.index) { + return false; + } + return true; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the classifier + */ + public Class<? extends Annotation> getClassifer() { + return classifer; + } + + /** + * @param classifer the classifier to set + */ + public void setClassifer(Class<? extends Annotation> classifer) { + this.classifer = classifer; + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationActivator.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationActivator.java new file mode 100644 index 0000000000..46594e0f50 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationActivator.java @@ -0,0 +1,86 @@ +/* + * 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.java.impl; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.ModuleActivator; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.AllowsPassByReferenceProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ComponentNameProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ConstructorProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ContextProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ConversationIDProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ConversationProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.DestroyProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.EagerInitProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.HeuristicPojoProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.InitProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.PolicyProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.PropertyProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ReferenceProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ResourceProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ScopeProcessor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.ServiceProcessor; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.policy.PolicyFactory; + +/** + * A module activator for the Java implementation model. + * + * @version $Rev$ $Date$ + */ +public class JavaImplementationActivator implements ModuleActivator { + + public void start(ExtensionPointRegistry registry) { + ModelFactoryExtensionPoint modelFactories = registry.getExtensionPoint(ModelFactoryExtensionPoint.class); + AssemblyFactory assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + JavaInterfaceFactory javaFactory = modelFactories.getFactory(JavaInterfaceFactory.class); + PolicyFactory policyFactory = modelFactories.getFactory(PolicyFactory.class); + + BaseJavaClassVisitor[] extensions = + new BaseJavaClassVisitor[] {new ConstructorProcessor(assemblyFactory), + new AllowsPassByReferenceProcessor(assemblyFactory), + new ComponentNameProcessor(assemblyFactory), + new ContextProcessor(assemblyFactory), + new ConversationIDProcessor(assemblyFactory), + new ConversationProcessor(assemblyFactory), + new DestroyProcessor(assemblyFactory), new EagerInitProcessor(assemblyFactory), + new InitProcessor(assemblyFactory), new PropertyProcessor(assemblyFactory), + new ReferenceProcessor(assemblyFactory, javaFactory), + new ResourceProcessor(assemblyFactory), new ScopeProcessor(assemblyFactory), + new ServiceProcessor(assemblyFactory, javaFactory), + new HeuristicPojoProcessor(assemblyFactory, javaFactory), + new PolicyProcessor(assemblyFactory, policyFactory)}; + + JavaImplementationFactory javaImplementationFactory = modelFactories.getFactory(JavaImplementationFactory.class); + for (JavaClassVisitor extension : extensions) { + javaImplementationFactory.addClassVisitor(extension); + } + + } + + public void stop(ExtensionPointRegistry registry) { + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationFactoryImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationFactoryImpl.java new file mode 100644 index 0000000000..0cc78498e6 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationFactoryImpl.java @@ -0,0 +1,70 @@ +/* + * 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.java.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; + +/** + * A factory for the Java model. + * + * @version $Rev$ $Date$ + */ +public abstract class JavaImplementationFactoryImpl implements JavaImplementationFactory { + + private List<JavaClassVisitor> visitors = new ArrayList<JavaClassVisitor>(); + private JavaClassIntrospectorImpl introspector; + + public JavaImplementationFactoryImpl() { + introspector = new JavaClassIntrospectorImpl(visitors); + } + + public JavaImplementation createJavaImplementation() { + JavaImplementation javaImplementation = new JavaImplementationImpl(); + return javaImplementation; + } + + public JavaImplementation createJavaImplementation(Class<?> implementationClass) throws IntrospectionException { + JavaImplementation javaImplementation = createJavaImplementation(); + introspector.introspectClass(javaImplementation, implementationClass); + return javaImplementation; + } + + public void createJavaImplementation(JavaImplementation javaImplementation, Class<?> implementationClass) throws IntrospectionException { + introspector.introspectClass(javaImplementation, implementationClass); + } + + public void addClassVisitor(JavaClassVisitor visitor) { + visitors.add(visitor); + } + + public void removeClassVisitor(JavaClassVisitor visitor) { + visitors.remove(visitor); + } + + public List<JavaClassVisitor> getClassVisitors() { + return visitors; + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationImpl.java new file mode 100644 index 0000000000..8aa62ae62c --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationImpl.java @@ -0,0 +1,168 @@ +/* + * 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.java.impl; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.policy.util.PolicyHandlerTuple; + +/** + * A component type specialization for POJO implementations + * + * @version $Rev$ $Date$ + */ +public class JavaImplementationImpl extends BaseJavaImplementationImpl implements JavaImplementation { + private JavaConstructorImpl<?> constructorDefinition; + private Map<Constructor, JavaConstructorImpl> constructors = new HashMap<Constructor, JavaConstructorImpl>(); + private Method initMethod; + private Method destroyMethod; + private final Map<String, JavaResourceImpl> resources = new HashMap<String, JavaResourceImpl>(); + private final Map<String, JavaElementImpl> propertyMembers = new HashMap<String, JavaElementImpl>(); + private final Map<String, JavaElementImpl> referenceMembers = new HashMap<String, JavaElementImpl>(); + private final Map<String, Collection<JavaElementImpl>> callbackMembers = new HashMap<String, Collection<JavaElementImpl>>(); + private List<Member> conversationIDMember = new ArrayList<Member>(); + private boolean eagerInit; + private boolean allowsPassByReference; + private List<Method> allowsPassByReferenceMethods = new ArrayList<Method>(); + private long maxAge = -1; + private long maxIdleTime = -1; + private JavaScopeImpl scope = JavaScopeImpl.STATELESS; + private Map<ClassLoader, List<PolicyHandlerTuple>> policyHandlerClassNames = null; + + protected JavaImplementationImpl() { + super(); + } + + public JavaConstructorImpl<?> getConstructor() { + return constructorDefinition; + } + + public void setConstructor(JavaConstructorImpl<?> definition) { + this.constructorDefinition = definition; + } + + public Method getInitMethod() { + return initMethod; + } + + public void setInitMethod(Method initMethod) { + this.initMethod = initMethod; + } + + public Method getDestroyMethod() { + return destroyMethod; + } + + public void setDestroyMethod(Method destroyMethod) { + this.destroyMethod = destroyMethod; + } + + public Map<String, JavaResourceImpl> getResources() { + return resources; + } + + public List<Member> getConversationIDMembers() { + return this.conversationIDMember; + } + + public void addConversationIDMember(Member conversationIDMember) { + this.conversationIDMember.add(conversationIDMember); + } + + public boolean isAllowsPassByReference() { + return allowsPassByReference; + } + + public void setAllowsPassByReference(boolean allowsPassByReference) { + this.allowsPassByReference = allowsPassByReference; + } + + public List<Method> getAllowsPassByReferenceMethods() { + return allowsPassByReferenceMethods; + } + + public boolean isAllowsPassByReference(Method method) { + return allowsPassByReference || allowsPassByReferenceMethods.contains(method); + } + + public Map<Constructor, JavaConstructorImpl> getConstructors() { + return constructors; + } + + public boolean isEagerInit() { + return eagerInit; + } + + public void setEagerInit(boolean eagerInit) { + this.eagerInit = eagerInit; + } + + public Map<String, Collection<JavaElementImpl>> getCallbackMembers() { + return callbackMembers; + } + + public Map<String, JavaElementImpl> getPropertyMembers() { + return propertyMembers; + } + + public Map<String, JavaElementImpl> getReferenceMembers() { + return referenceMembers; + } + + public JavaScopeImpl getJavaScope() { + return scope; + } + + public void setJavaScope(JavaScopeImpl scope) { + this.scope = scope; + } + + public long getMaxAge() { + return maxAge; + } + + public void setMaxAge(long maxAge) { + this.maxAge = maxAge; + } + + public long getMaxIdleTime() { + return maxIdleTime; + } + + public void setMaxIdleTime(long maxIdleTime) { + this.maxIdleTime = maxIdleTime; + } + + public Map<ClassLoader, List<PolicyHandlerTuple>> getPolicyHandlerClassNames() { + return policyHandlerClassNames; + } + + public void setPolicyHandlerClassNames(Map<ClassLoader, List<PolicyHandlerTuple>> policyHandlerClassNames) { + this.policyHandlerClassNames = policyHandlerClassNames; + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaParameterImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaParameterImpl.java new file mode 100644 index 0000000000..c4c528f4f2 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaParameterImpl.java @@ -0,0 +1,35 @@ +/* + * 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.java.impl; + +import java.lang.reflect.Constructor; + +/** + * @version $Rev$ $Date$ + */ +public class JavaParameterImpl extends JavaElementImpl { + /** + * @param constructor + * @param index + */ + public JavaParameterImpl(Constructor<?> constructor, int index) { + super(constructor, index); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaResourceImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaResourceImpl.java new file mode 100644 index 0000000000..1aca15ebb8 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaResourceImpl.java @@ -0,0 +1,85 @@ +/* + * 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.java.impl; + + +/** + * A resource dependency declared by a Java component implementation + * + * @version $Rev$ $Date$ + */ +public class JavaResourceImpl { + private JavaElementImpl element; + private String mappedName; + private boolean optional; + + public JavaResourceImpl(JavaElementImpl element) { + this.element = element; + } + + /** + * The name of the resource + * + * @return the name of the resource + */ + public String getName() { + return element.getName(); + } + + /** + * Returns the URI of the resource + * + * @return the URI of the resource + */ + public String getMappedName() { + return mappedName; + } + + /** + * Sets the resource URI + */ + public void setMappedName(String mappedName) { + this.mappedName = mappedName; + } + + /** + * If true, the resource is optional + * + * @return true if the resource is optional + */ + public boolean isOptional() { + return optional; + } + + /** + * Sets whether the resource is optional + */ + public void setOptional(boolean optional) { + this.optional = optional; + } + + /** + * @return the element + */ + public JavaElementImpl getElement() { + return element; + } + + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaScopeImpl.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaScopeImpl.java new file mode 100644 index 0000000000..85c2f73f75 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaScopeImpl.java @@ -0,0 +1,66 @@ +/* + * 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.java.impl; + +/** + * The default implementation scopes supported by assemblies. + * + * @version $Rev$ $Date$ + */ +public class JavaScopeImpl { + public static final JavaScopeImpl STATELESS = new JavaScopeImpl("STATELESS"); + public static final JavaScopeImpl REQUEST = new JavaScopeImpl("REQUEST"); + public static final JavaScopeImpl SESSION = new JavaScopeImpl("SESSION"); + public static final JavaScopeImpl CONVERSATION = new JavaScopeImpl("CONVERSATION"); + public static final JavaScopeImpl COMPOSITE = new JavaScopeImpl("COMPOSITE"); + public static final JavaScopeImpl SYSTEM = new JavaScopeImpl("SYSTEM"); + public static final JavaScopeImpl UNDEFINED = new JavaScopeImpl("UNDEFINED"); + + private String scope; + + public JavaScopeImpl(String scope) { + this.scope = scope.toUpperCase().intern(); + } + + public String getScope() { + return scope; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final JavaScopeImpl scope1 = (JavaScopeImpl) o; + return !(scope != null ? scope != scope1.scope.intern() : scope1.scope != null); + } + + @Override + public int hashCode() { + return scope != null ? scope.hashCode() : 0; + } + + @Override + public String toString() { + return scope; + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaClassVisitor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaClassVisitor.java new file mode 100644 index 0000000000..4fa40dee4b --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaClassVisitor.java @@ -0,0 +1,126 @@ +/* + * 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.java.introspect; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; + +/** + * Implementations process class-level metadata, typically parsing annotations + * and updating the corresponding <code>ComponentType</code>. A processor + * may, for example, create a Property which is responsible for injecting a + * complex type on a component implementation instance when it is instantiated. + * <p/> Processors will receive callbacks as the implementation class is walked + * while evaluating an assembly. It is the responsibility of the parser to + * determine whether to perform an action during the callback. + * + * @version $Rev$ $Date$ + */ +public interface JavaClassVisitor { + + /** + * A callback received when the component implementation class is first + * loaded + * + * @param clazz the component implementation class + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException; + + /** + * A callback received as the component implementation class hierarchy is + * evaluated + * + * @param clazz the superclass in the component implmentation's class + * hierarchy + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + <T> void visitSuperClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException; + + /** + * A callback received as the component implementation's public and + * protected methods are evaluated + * + * @param method the current public or protected method being evaluated + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + void visitMethod(Method method, JavaImplementation type) throws IntrospectionException; + + /** + * A callback received as the component implementation's constructor used + * for instantiation by the runtime is evaluated. If an implementation + * contains more than one constructor, the constructor passed to the + * callback will be chosen according to the algorithm described in the SCA + * Java Client and Implementation Model Specification. + * + * @param constructor the constructor used for instantiating component + * implementation instances + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + <T> void visitConstructor(Constructor<T> constructor, JavaImplementation type) throws IntrospectionException; + + /** + * @param parameter + * @param type + * @throws IntrospectionException + */ + void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) throws IntrospectionException; + + /** + * A callback received as the component implementation's public and + * protected fields are evaluated + * + * @param field the current public or protected field being evaluated + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + void visitField(Field field, JavaImplementation type) throws IntrospectionException; + + /** + * The final callback received when all other callbacks during evaluation of + * the component implementation have been issued + * + * @param clazz the component implementation class + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException; + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessor.java new file mode 100644 index 0000000000..9596fe0808 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessor.java @@ -0,0 +1,192 @@ +/* + * 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.java.introspect.impl; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper; + +/** + * Base class for ImplementationProcessors that handle annotations that add + * Properties. + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractPropertyProcessor<A extends Annotation> extends BaseJavaClassVisitor { + private final Class<A> annotationClass; + + protected AbstractPropertyProcessor(AssemblyFactory assemblyFactory, Class<A> annotationClass) { + super(assemblyFactory); + this.annotationClass = annotationClass; + } + + private boolean removeProperty(JavaElementImpl prop, JavaImplementation type) { + if(prop==null) { + return false; + } + List<Property> props = type.getProperties(); + for(int i=0;i<props.size();i++) { + if(props.get(i).getName().equals(prop.getName())) { + props.remove(i); + return true; + } + } + return false; + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + A annotation = method.getAnnotation(annotationClass); + if (annotation == null) { + return; + } + + if (!JavaIntrospectionHelper.isSetter(method)) { + throw new IllegalPropertyException("Annotated method is not a setter: " + method, method); + } + + String name = getName(annotation); + if (name == null || "".equals(name)) { + name = method.getName(); + if (name.startsWith("set")) { + name = JavaIntrospectionHelper.toPropertyName(method.getName()); + } + } + + Map<String, JavaElementImpl> properties = type.getPropertyMembers(); + JavaElementImpl prop = properties.get(name); + // Setter override field + if (prop != null && prop.getElementType() != ElementType.FIELD) { + throw new DuplicatePropertyException(name); + } + + removeProperty(prop, type); + + JavaElementImpl element = new JavaElementImpl(method, 0); + Property property = createProperty(name, element); + + // add databinding available as annotations, as extensions + + initProperty(property, annotation); + type.getProperties().add(property); + properties.put(name, element); + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + + A annotation = field.getAnnotation(annotationClass); + if (annotation == null) { + return; + } + + String name = getName(annotation); + if (name == null) { + name = ""; + } + if ("".equals(name) || name.equals(field.getType().getName())) { + name = field.getName(); + } + + Map<String, JavaElementImpl> properties = type.getPropertyMembers(); + JavaElementImpl prop = properties.get(name); + // Setter override field + if (prop != null && prop.getElementType() == ElementType.FIELD) { + throw new DuplicatePropertyException(name); + } + + if (prop == null) { + JavaElementImpl element = new JavaElementImpl(field); + Property property = createProperty(name, element); + initProperty(property, annotation); + type.getProperties().add(property); + properties.put(name, element); + } + } + + @Override + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) + throws IntrospectionException { + + Map<String, JavaElementImpl> properties = type.getPropertyMembers(); + A annotation = parameter.getAnnotation(annotationClass); + if (annotation != null) { + String name = getName(annotation); + if (name == null) { + name = parameter.getType().getName(); + } + if (!"".equals(name) && !"".equals(parameter.getName()) && !name.equals(parameter.getName())) { + throw new InvalidConstructorException("Mismatched property name: " + parameter); + } + if ("".equals(name) && "".equals(parameter.getName())) { + throw new InvalidPropertyException("Missing property name: " + parameter); + } + if ("".equals(name)) { + name = parameter.getName(); + } + + JavaElementImpl prop = properties.get(name); + // Setter override field + if (prop != null && prop.getElementType() != ElementType.FIELD) { + throw new DuplicatePropertyException(name); + } + removeProperty(prop, type); + + parameter.setName(name); + parameter.setClassifer(annotationClass); + Property property = createProperty(name, parameter); + initProperty(property, annotation); + type.getProperties().add(property); + properties.put(name, parameter); + } + } + + protected abstract String getName(A annotation); + + protected abstract void initProperty(Property property, A annotation) throws IntrospectionException; + + @SuppressWarnings("unchecked") + protected Property createProperty(String name, JavaElementImpl element) throws IntrospectionException { + + Property property = assemblyFactory.createProperty(); + property.setName(name); + Class<?> baseType = JavaIntrospectionHelper.getBaseType(element.getType(), element.getGenericType()); + property.setXSDType(JavaXMLMapper.getXMLType(baseType)); + + Class<?> javaType = element.getType(); + if (javaType.isArray() || Collection.class.isAssignableFrom(javaType)) { + property.setMany(true); + } + return property; + + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessor.java new file mode 100644 index 0000000000..4a3ce0c343 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessor.java @@ -0,0 +1,51 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.osoa.sca.annotations.AllowsPassByReference; + +/** + * Processes {@link AllowsPassByReference} on an implementation + * + * @version $Rev$ $Date$ + */ +public class AllowsPassByReferenceProcessor extends BaseJavaClassVisitor { + + public AllowsPassByReferenceProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + type.setAllowsPassByReference(clazz.isAnnotationPresent(AllowsPassByReference.class)); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + boolean pbr = method.isAnnotationPresent(AllowsPassByReference.class); + if (pbr) { + type.getAllowsPassByReferenceMethods().add(method); + } + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AmbiguousConstructorException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AmbiguousConstructorException.java new file mode 100644 index 0000000000..c6e6b6e4d6 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AmbiguousConstructorException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when constructor parameters cannot be unambiguously resolved to a property or reference + * + * @version $Rev$ $Date$ + */ +public class AmbiguousConstructorException extends IntrospectionException { + private static final long serialVersionUID = 3662860753837091880L; + + public AmbiguousConstructorException(String message) { + super(message); + } + + public AmbiguousConstructorException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/BaseJavaClassVisitor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/BaseJavaClassVisitor.java new file mode 100644 index 0000000000..bc6551d45d --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/BaseJavaClassVisitor.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.java.introspect.impl; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; + +/** + * A convenience class for annotation processors which alleviates the need to + * implement unused callbacks + * + * @version $Rev$ $Date$ + */ +public abstract class BaseJavaClassVisitor implements JavaClassVisitor { + protected AssemblyFactory assemblyFactory; + + protected BaseJavaClassVisitor(AssemblyFactory factory) { + this.assemblyFactory = factory; + } + + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + } + + public <T> void visitSuperClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + } + + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + } + + public <T> void visitConstructor(Constructor<T> constructor, JavaImplementation type) throws IntrospectionException { + } + + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + } + + public <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + } + + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) throws IntrospectionException { + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ComponentNameProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ComponentNameProcessor.java new file mode 100644 index 0000000000..556f0b77e9 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ComponentNameProcessor.java @@ -0,0 +1,80 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl; +import org.osoa.sca.annotations.ComponentName; + +/** + * Processes {@link @ComponentName} annotations on a component implementation and adds + * a {@link JavaMappedProperty} to the component type which will be used to + * inject the appropriate component name. + * + * @version $Rev$ $Date$ + */ +public class ComponentNameProcessor extends BaseJavaClassVisitor { + + public ComponentNameProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + if (method.getAnnotation(ComponentName.class) == null) { + return; + } + if (method.getParameterTypes().length != 1) { + throw new IllegalContextException("ComponentName setter must have one parameter", method); + } + Class<?> paramType = method.getParameterTypes()[0]; + String name = JavaIntrospectionHelper.toPropertyName(method.getName()); + if (String.class.equals(paramType)) { + JavaElementImpl element = new JavaElementImpl(method, 0); + element.setName(name); + element.setClassifer(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } else { + throw new IllegalContextException(paramType.getName()); + } + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + if (field.getAnnotation(ComponentName.class) == null) { + return; + } + Class<?> paramType = field.getType(); + if (String.class.equals(paramType)) { + JavaElementImpl element = new JavaElementImpl(field); + element.setClassifer(Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } else { + throw new IllegalContextException(paramType.getName()); + } + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessor.java new file mode 100644 index 0000000000..17e28479d3 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessor.java @@ -0,0 +1,83 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Constructor; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; + +/** + * Handles processing of a constructor decorated with + * {@link org.osoa.sca.annotations.Constructor} + * + * @version $Rev$ $Date$ + */ +@SuppressWarnings("unchecked") +public class ConstructorProcessor extends BaseJavaClassVisitor { + + public ConstructorProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + Constructor[] ctors = clazz.getConstructors(); + boolean found = false; + for (Constructor constructor : ctors) { + JavaConstructorImpl<?> definition = new JavaConstructorImpl(constructor); + type.getConstructors().put(constructor, definition); + if (constructor.getAnnotation(org.osoa.sca.annotations.Constructor.class) != null) { + if (found) { + throw new DuplicateConstructorException("Multiple constructors marked with @Constructor", constructor); + } + found = true; + type.setConstructor(definition); + } + } + } + + @Override + public <T> void visitConstructor(Constructor<T> constructor, JavaImplementation type) + throws IntrospectionException { + org.osoa.sca.annotations.Constructor annotation = constructor + .getAnnotation(org.osoa.sca.annotations.Constructor.class); + if (annotation == null) { + return; + } + JavaConstructorImpl<?> definition = type.getConstructor(); + if (definition == null) { + definition = new JavaConstructorImpl(constructor); + type.setConstructor(definition); + } + JavaParameterImpl[] parameters = definition.getParameters(); + String[] value = annotation.value(); + boolean isDefault = value.length == 0 || (value.length == 1 && "".equals(value[0])); + if (!isDefault && value.length != parameters.length) { + throw new InvalidConstructorException("Invalid Number of names in @Constructor"); + } + for (int i = 0; i < parameters.length; i++) { + parameters[i].setName(i < value.length ? value[i] : ""); + } + type.setConstructor(definition); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessor.java new file mode 100644 index 0000000000..177ceaa57c --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessor.java @@ -0,0 +1,82 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl; +import org.osoa.sca.ComponentContext; +import org.osoa.sca.RequestContext; +import org.osoa.sca.annotations.Context; + +/** + * Processes {@link @Context} annotations on a component implementation and adds + * a {@link JavaMappedProperty} to the component type which will be used to + * inject the appropriate context + * + * @version $Rev$ $Date$ + */ +public class ContextProcessor extends BaseJavaClassVisitor { + + public ContextProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + if (method.getAnnotation(Context.class) == null) { + return; + } + if (method.getParameterTypes().length != 1) { + throw new IllegalContextException("Context setter must have one parameter", method); + } + Class<?> paramType = method.getParameterTypes()[0]; + String name = JavaIntrospectionHelper.toPropertyName(method.getName()); + if (ComponentContext.class.equals(paramType) || RequestContext.class.equals(paramType)) { + JavaElementImpl element = new JavaElementImpl(method, 0); + element.setName(name); + element.setClassifer(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } else { + throw new UnknownContextTypeException(paramType.getName()); + } + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + if (field.getAnnotation(Context.class) == null) { + return; + } + Class<?> paramType = field.getType(); + if (ComponentContext.class.equals(paramType) || RequestContext.class.equals(paramType)) { + JavaElementImpl element = new JavaElementImpl(field); + element.setClassifer(Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } else { + throw new UnknownContextTypeException(paramType.getName()); + } + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationIDProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationIDProcessor.java new file mode 100644 index 0000000000..985f8baa82 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationIDProcessor.java @@ -0,0 +1,70 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl; +import org.osoa.sca.annotations.ConversationID; + +/** + * Processes {@link @ConversationID} annotations on a component implementation and adds + * a {@link JavaMappedProperty} to the component type which will be used to + * inject the appropriate conversationId + * + * @version $Rev$ $Date$ + */ +public class ConversationIDProcessor extends BaseJavaClassVisitor { + + public ConversationIDProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + if (method.getAnnotation(ConversationID.class) == null) { + return; + } + if (method.getParameterTypes().length != 1) { + throw new IllegalContextException("ConversationID setter must have one parameter", method); + } + String name = JavaIntrospectionHelper.toPropertyName(method.getName()); + JavaElementImpl element = new JavaElementImpl(method, 0); + element.setName(name); + element.setClassifer(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + if (field.getAnnotation(ConversationID.class) == null) { + return; + } + JavaElementImpl element = new JavaElementImpl(field); + element.setClassifer(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationProcessor.java new file mode 100644 index 0000000000..efd04262dd --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationProcessor.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.osoa.sca.annotations.ConversationAttributes; +import org.osoa.sca.annotations.ConversationID; +import org.osoa.sca.annotations.Scope; + +/** + * @version $Rev$ $Date$ + */ +public class ConversationProcessor extends BaseJavaClassVisitor { + private static final String SECONDS = " SECONDS"; + private static final String MINUTES = " MINUTES"; + private static final String HOURS = " HOURS"; + private static final String DAYS = " DAYS"; + private static final String YEARS = " YEARS"; + + public ConversationProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + + ConversationAttributes conversation = clazz.getAnnotation(ConversationAttributes.class); + if (conversation == null) { + return; + } + Scope scope = clazz.getAnnotation(Scope.class); + if (scope == null) { + // implicitly assume conversation + type.setJavaScope(org.apache.tuscany.sca.implementation.java.impl.JavaScopeImpl.CONVERSATION); + } else if (conversation != null) { + long maxAge; + long maxIdleTime; + String maxAgeVal = conversation.maxAge(); + String maxIdleTimeVal = conversation.maxIdleTime(); + try { + if (maxAgeVal.length() > 0) { + maxAge = convertTimeMillis(maxAgeVal); + type.setMaxAge(maxAge); + } + } catch (NumberFormatException e) { + throw new InvalidConversationalImplementation("Invalid maximum age", e); + } + try { + if (maxIdleTimeVal.length() > 0) { + maxIdleTime = convertTimeMillis(maxIdleTimeVal); + type.setMaxIdleTime(maxIdleTime); + } + } catch (NumberFormatException e) { + throw new InvalidConversationalImplementation("Invalid maximum idle time", e); + } + } + + } + + @Override + public void visitMethod(Method method, + JavaImplementation type) throws IntrospectionException { + ConversationID conversationID = method.getAnnotation(ConversationID.class); + if (conversationID == null) { + return; + } + type.addConversationIDMember(method); + } + + @Override + public void visitField(Field field, + JavaImplementation type) throws IntrospectionException { + ConversationID conversationID = field.getAnnotation(ConversationID.class); + if (conversationID == null) { + return; + } + type.addConversationIDMember(field); + } + + protected long convertTimeMillis(String expr) throws NumberFormatException { + expr = expr.trim().toUpperCase(); + int i = expr.lastIndexOf(SECONDS); + if (i >= 0) { + String units = expr.substring(0, i); + return Long.parseLong(units) * 1000; + } + i = expr.lastIndexOf(MINUTES); + if (i >= 0) { + String units = expr.substring(0, i); + return Long.parseLong(units) * 60000; + } + + i = expr.lastIndexOf(HOURS); + if (i >= 0) { + String units = expr.substring(0, i); + return Long.parseLong(units) * 3600000; + } + i = expr.lastIndexOf(DAYS); + if (i >= 0) { + String units = expr.substring(0, i); + return Long.parseLong(units) * 86400000; + } + i = expr.lastIndexOf(YEARS); + if (i >= 0) { + String units = expr.substring(0, i); + return Long.parseLong(units) * 31556926000L; + } + return Long.parseLong(expr) * 1000; // assume seconds if no suffix + // specified + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessor.java new file mode 100644 index 0000000000..50e4d46e97 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessor.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.java.introspect.impl; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.osoa.sca.annotations.Destroy; + +/** + * Processes the {@link @Destroy} annotation on a component implementation and + * updates the component type with the decorated destructor method + * + * @version $Rev$ $Date$ + */ +public class DestroyProcessor extends BaseJavaClassVisitor { + + public DestroyProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + Destroy annotation = method.getAnnotation(Destroy.class); + if (annotation == null) { + return; + } + if (method.getParameterTypes().length != 0) { + throw new IllegalDestructorException("Destructor must not have argments", method); + } + if(!method.getReturnType().equals(void.class)) { + throw new IllegalDestructorException("Destructor must return void.", method); + } + if (type.getDestroyMethod() != null) { + throw new DuplicateDestructorException("More than one destructor found on implementation"); + } + if (!Modifier.isPublic(method.getModifiers())) { + throw new IllegalDestructorException("Destructor must be a public method. Invalid annotation @Destroy found on "+method); + } + type.setDestroyMethod(method); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateConstructorException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateConstructorException.java new file mode 100644 index 0000000000..88a245cbf3 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateConstructorException.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when more than one component implementation constructor is annotated with {@link + * org.osoa.sca.annotations.Constructor} + * + * @version $Rev$ $Date$ + */ +public class DuplicateConstructorException extends IntrospectionException { + private static final long serialVersionUID = -5926763756570552986L; + + public DuplicateConstructorException(String message) { + super(message); + } + + public DuplicateConstructorException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateDestructorException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateDestructorException.java new file mode 100644 index 0000000000..9b834e7e87 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateDestructorException.java @@ -0,0 +1,35 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation is annotated multiple times with {@link org.osoa.sca.annotations.Destroy} + * + * @version $Rev$ $Date$ + */ +public class DuplicateDestructorException extends IntrospectionException { + private static final long serialVersionUID = -7474912510114895203L; + + public DuplicateDestructorException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateInitException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateInitException.java new file mode 100644 index 0000000000..4325faef26 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateInitException.java @@ -0,0 +1,35 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation is annotated multiple times with {@link @org.osoa.sca.annotations.Init} + * + * @version $Rev$ $Date$ + */ +public class DuplicateInitException extends IntrospectionException { + private static final long serialVersionUID = -6282935288115512057L; + + public DuplicateInitException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicatePropertyException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicatePropertyException.java new file mode 100644 index 0000000000..b9e1923e73 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicatePropertyException.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation has more than one property injection site with the same name + * + * @version $Rev$ $Date$ + */ +public class DuplicatePropertyException extends IntrospectionException { + private static final long serialVersionUID = 5536415875694904037L; + + public DuplicatePropertyException(String message) { + super(message); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateReferenceException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateReferenceException.java new file mode 100644 index 0000000000..300ad6817e --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateReferenceException.java @@ -0,0 +1,35 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation has more than one reference injection site with the same name + * + * @version $Rev$ $Date$ + */ +public class DuplicateReferenceException extends IntrospectionException { + private static final long serialVersionUID = 907910648213477158L; + + public DuplicateReferenceException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateResourceException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateResourceException.java new file mode 100644 index 0000000000..2d177b3f76 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateResourceException.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation has more than one resource injection site with the same name + * + * @version $Rev$ $Date$ + */ +public class DuplicateResourceException extends IntrospectionException { + + private static final long serialVersionUID = 1619276459330463299L; + + public DuplicateResourceException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessor.java new file mode 100644 index 0000000000..5619275b82 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessor.java @@ -0,0 +1,57 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.osoa.sca.annotations.EagerInit; + +/** + * Handles processing of {@link org.osoa.sca.annotations.EagerInit} + * + * @version $Rev$ $Date$ + */ +public class EagerInitProcessor extends BaseJavaClassVisitor { + + public EagerInitProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public <T> void visitClass(Class<T> clazz, + JavaImplementation type) throws IntrospectionException { + super.visitClass(clazz, type); + EagerInit annotation = clazz.getAnnotation(EagerInit.class); + if (annotation == null) { + Class<?> superClass = clazz.getSuperclass(); + while (!Object.class.equals(superClass)) { + annotation = superClass.getAnnotation(EagerInit.class); + if (annotation != null) { + break; + } + superClass = superClass.getSuperclass(); + } + if (annotation == null) { + return; + } + } + type.setEagerInit(true); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessor.java new file mode 100644 index 0000000000..fc4d27e752 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessor.java @@ -0,0 +1,607 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getAllInterfaces; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getAllPublicAndProtectedFields; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getAllUniquePublicProtectedMethods; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.toPropertyName; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +import org.apache.tuscany.sca.interfacedef.Interface; +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.osoa.sca.annotations.Callback; +import org.osoa.sca.annotations.Context; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Reference; +import org.osoa.sca.annotations.Remotable; + +/** + * Heuristically evaluates an un-annotated Java implementation type to determine + * services, references, and properties according to the algorithm described in + * the SCA Java Client and Implementation Model Specification <p/> TODO + * Implement: <p/> When no service interface is annotated, need to calculate a + * single service comprising all public methods that are not reference or + * property injection sites. If that service can be exactly mapped to an + * interface implemented by the class then the service interface will be defined + * in terms of that interface. + * + * @version $Rev$ $Date$ + */ +public class HeuristicPojoProcessor extends BaseJavaClassVisitor { + private JavaInterfaceFactory javaFactory; + + public HeuristicPojoProcessor(AssemblyFactory assemblyFactory, JavaInterfaceFactory javaFactory) { + super(assemblyFactory); + this.javaFactory = javaFactory; + } + + @Override + public <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + List<org.apache.tuscany.sca.assembly.Service> services = type.getServices(); + if (services.isEmpty()) { + // heuristically determine the service + /** + * The following is quoted from Java Specification 1.2.1.3. Introspecting services offered by a Java implementation + * In the cases described below, the services offered by a Java implementation class may be determined + * through introspection, eliding the need to specify them using @Service. The following algorithm is used + * to determine how services are introspected from an implementation class: + * + * If the interfaces of the SCA services are not specified with the @Service annotation on the + * implementation class, it is assumed that all implemented interfaces that have been annotated + * as @Remotable are the service interfaces provided by the component. If none of the implemented + * interfaces is remotable, then by default the implementation offers a single service whose type + * is the implementation class. + */ + Set<Class> interfaces = getAllInterfaces(clazz); + for (Class<?> i : interfaces) { + if (i.isAnnotationPresent(Remotable.class)) { + addService(type, i); + } + } + if (services.isEmpty()) { + // class is the interface + addService(type, clazz); + } + } + Set<Method> methods = getAllUniquePublicProtectedMethods(clazz, false); + if (!type.getReferenceMembers().isEmpty() || !type.getPropertyMembers().isEmpty()) { + // references and properties have been explicitly defined + // if (type.getServices().isEmpty()) { + // calculateServiceInterface(clazz, type, methods); + // if (type.getServices().isEmpty()) { + // throw new ServiceTypeNotFoundException(clazz.getName()); + // } + // } + evaluateConstructor(type, clazz); + return; + } + calcPropRefs(methods, services, type, clazz); + evaluateConstructor(type, clazz); + } + + private void addService(JavaImplementation type, Class<?> clazz) throws IntrospectionException { + try { + org.apache.tuscany.sca.assembly.Service service = createService(clazz); + type.getServices().add(service); + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + } + + private boolean isPublicSetter(Method method) { + return method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers()) + && method.getName().startsWith("set") + && method.getReturnType() == void.class; + } + + private boolean isProtectedSetter(Method method) { + return method.getParameterTypes().length == 1 && Modifier.isProtected(method.getModifiers()) + && method.getName().startsWith("set") + && method.getReturnType() == void.class; + } + + private <T> void calcPropRefs(Set<Method> methods, + List<org.apache.tuscany.sca.assembly.Service> services, + JavaImplementation type, + Class<T> clazz) throws IntrospectionException { + // heuristically determine the properties references + // make a first pass through all public methods with one param + Set<String> setters = new HashSet<String>(); + Set<String> others = new HashSet<String>(); + for (Method method : methods) { + if (!isPublicSetter(method)) { + continue; + } + if (method.isAnnotationPresent(Callback.class) || method.isAnnotationPresent(Context.class)) { + // Add the property name as others + others.add(toPropertyName(method.getName())); + continue; + } + if (!isInServiceInterface(method, services)) { + // Not part of the service interface + String name = toPropertyName(method.getName()); + setters.add(name); + // avoid duplicate property or ref names + if (!type.getPropertyMembers().containsKey(name) && !type.getReferenceMembers().containsKey(name)) { + Class<?> param = method.getParameterTypes()[0]; + Type genericType = method.getGenericParameterTypes()[0]; + if (isReferenceType(param, genericType)) { + type.getReferences().add(createReference(name, param)); + type.getReferenceMembers().put(name, new JavaElementImpl(method, 0)); + } else { + type.getProperties().add(createProperty(name, param)); + type.getPropertyMembers().put(name, new JavaElementImpl(method, 0)); + } + } + } + } + // second pass for protected methods with one param + for (Method method : methods) { + if (!isProtectedSetter(method)) { + continue; + } + if (method.isAnnotationPresent(Callback.class) || method.isAnnotationPresent(Context.class)) { + // Add the property name as others + others.add(toPropertyName(method.getName())); + continue; + } + Class<?> param = method.getParameterTypes()[0]; + String name = toPropertyName(method.getName()); + setters.add(name); + // avoid duplicate property or ref names + if (isReferenceType(param, method.getGenericParameterTypes()[0])) { + if (!type.getReferenceMembers().containsKey(name)) { + type.getReferences().add(createReference(name, param)); + type.getReferenceMembers().put(name, new JavaElementImpl(method, 0)); + } + } else { + if (!type.getPropertyMembers().containsKey(name)) { + type.getProperties().add(createProperty(name, param)); + type.getPropertyMembers().put(name, new JavaElementImpl(method, 0)); + } + } + } + + // Public or protected fields unless there is a public or protected + // setter method + // for the same name + Set<Field> fields = getAllPublicAndProtectedFields(clazz, false); + for (Field field : fields) { + if (field.isAnnotationPresent(Callback.class) || field.isAnnotationPresent(Context.class)) { + continue; + } + if (setters.contains(field.getName()) || others.contains(field.getName())) { + continue; + } + String name = field.getName(); + Class<?> paramType = field.getType(); + if (isReferenceType(paramType, field.getGenericType())) { + if (!type.getReferenceMembers().containsKey(name)) { + type.getReferences().add(createReference(name, paramType)); + type.getReferenceMembers().put(name, new JavaElementImpl(field)); + } + } else { + if (!type.getPropertyMembers().containsKey(name)) { + type.getProperties().add(createProperty(name, paramType)); + type.getPropertyMembers().put(name, new JavaElementImpl(field)); + } + } + } + } + + /** + * Determines the constructor to use based on the component type's + * references and properties + * + * @param type the component type + * @param clazz the implementation class corresponding to the component type + * @throws NoConstructorException if no suitable constructor is found + * @throws AmbiguousConstructorException if the parameters of a constructor + * cannot be unambiguously mapped to references and properties + */ + @SuppressWarnings("unchecked") + private <T> void evaluateConstructor(JavaImplementation type, Class<T> clazz) throws IntrospectionException { + // determine constructor if one is not annotated + JavaConstructorImpl<?> definition = type.getConstructor(); + Constructor constructor; + boolean explict = false; + if (definition != null && definition.getConstructor() + .isAnnotationPresent(org.osoa.sca.annotations.Constructor.class)) { + // the constructor was already defined explicitly + return; + } else if (definition != null) { + explict = true; + constructor = definition.getConstructor(); + } else { + // no definition, heuristically determine constructor + Constructor[] constructors = clazz.getConstructors(); + if (constructors.length == 0) { + throw new NoConstructorException("No public constructor for class"); + } else if (constructors.length == 1) { + // Only one constructor, take it + constructor = constructors[0]; + } else { + // FIXME multiple constructors, none yet done + Constructor<T> selected = null; + int sites = type.getPropertyMembers().size() + type.getReferenceMembers().size(); + for (Constructor<T> ctor : constructors) { + if (ctor.getParameterTypes().length == 0) { + selected = ctor; + } + if (ctor.getParameterTypes().length == sites) { + // TODO finish + // selected = constructor; + // select constructor + // break; + } + } + if (selected == null) { + throw new NoConstructorException(); + } + constructor = selected; + definition = type.getConstructors().get(selected); + type.setConstructor(definition); + // return; + } + definition = type.getConstructors().get(constructor); + type.setConstructor(definition); + } + JavaParameterImpl[] parameters = definition.getParameters(); + if (parameters.length == 0) { + return; + } + Map<String, JavaElementImpl> props = type.getPropertyMembers(); + Map<String, JavaElementImpl> refs = type.getReferenceMembers(); + Annotation[][] annotations = constructor.getParameterAnnotations(); + if (!explict) { + // the constructor wasn't defined by an annotation, so check to see + // if any of the params have an annotation + // which we can impute as explicitly defining the constructor, e.g. + // @Property, @Reference, or @Autowire + explict = injectionAnnotationsPresent(annotations); + } + if (explict) { + for (int i = 0; i < parameters.length; i++) { + if (isAnnotated(parameters[i])) { + continue; + } else if (!findReferenceOrProperty(parameters[i], props, refs)) { + throw new AmbiguousConstructorException(parameters[i].toString()); + } + } + } else { + if (!areUnique(parameters)) { + throw new AmbiguousConstructorException("Cannot resolve non-unique parameter types, use @Constructor"); + } + if (!calcPropRefUniqueness(props.values(), refs.values())) { + throw new AmbiguousConstructorException("Cannot resolve non-unique parameter types, use @Constructor"); + } + if (!(props.isEmpty() && refs.isEmpty())) { + calcParamNames(parameters, props, refs); + } else { + heuristicParamNames(type, parameters); + + } + } + } + + private void calcParamNames(JavaParameterImpl[] parameters, + Map<String, JavaElementImpl> props, + Map<String, JavaElementImpl> refs) throws AmbiguousConstructorException { + // the constructor param types must unambiguously match defined + // reference or property types + for (JavaParameterImpl param : parameters) { + if (!findReferenceOrProperty(param, props, refs)) { + throw new AmbiguousConstructorException(param.getName()); + } + } + } + + private void heuristicParamNames(JavaImplementation type, JavaParameterImpl[] parameters) + throws IntrospectionException { + // heuristically determine refs and props from the parameter types + for (JavaParameterImpl p : parameters) { + String name = p.getType().getSimpleName().toLowerCase(); + if (isReferenceType(p.getType(), p.getGenericType())) { + type.getReferences().add(createReference(name, p.getType())); + p.setClassifer(Reference.class); + type.getReferenceMembers().put(name, p); + } else { + type.getProperties().add(createProperty(name, p.getType())); + p.setClassifer(Property.class); + type.getPropertyMembers().put(name, p); + } + p.setName(name); + } + } + + private static boolean areUnique(Class[] collection) { + Set<Class> set = new HashSet<Class>(Arrays.asList(collection)); + return set.size() == collection.length; + } + + /** + * Returns true if the union of the given collections of properties and + * references have unique Java types + */ + private boolean calcPropRefUniqueness(Collection<JavaElementImpl> props, Collection<JavaElementImpl> refs) { + + Class[] classes = new Class[props.size() + refs.size()]; + int i = 0; + for (JavaElementImpl property : props) { + classes[i] = property.getType(); + i++; + } + for (JavaElementImpl reference : refs) { + classes[i] = reference.getType(); + i++; + } + return areUnique(classes); + } + + /** + * Unambiguously finds the reference or property associated with the given + * type + * + * @return the name of the reference or property if found, null if not + * @throws AmbiguousConstructorException if the constructor parameter cannot + * be resolved to a property or reference + */ + private boolean findReferenceOrProperty(JavaParameterImpl parameter, + Map<String, JavaElementImpl> props, + Map<String, JavaElementImpl> refs) throws AmbiguousConstructorException { + + boolean found = false; + if (!"".equals(parameter.getName())) { + // Match by name + JavaElementImpl prop = props.get(parameter.getName()); + if (prop != null && prop.getType() == parameter.getType()) { + parameter.setClassifer(Property.class); + return true; + } + JavaElementImpl ref = refs.get(parameter.getName()); + if (ref != null && ref.getType() == parameter.getType()) { + parameter.setClassifer(Reference.class); + return true; + } + } + for (JavaElementImpl property : props.values()) { + if (property.getType() == parameter.getType()) { + if (found) { + throw new AmbiguousConstructorException("Ambiguous property or reference for constructor type", + (Member)parameter.getAnchor()); + } + parameter.setClassifer(Property.class); + parameter.setName(property.getName()); + found = true; + // do not break since ambiguities must be checked, i.e. more + // than one prop or ref of the same type + } + } + for (JavaElementImpl reference : refs.values()) { + if (reference.getType() == parameter.getType()) { + if (found) { + throw new AmbiguousConstructorException("Ambiguous property or reference for constructor type", + (Member)parameter.getAnchor()); + } + parameter.setClassifer(Reference.class); + parameter.setName(reference.getName()); + found = true; + // do not break since ambiguities must be checked, i.e. more + // than one prop or ref of the same type + } + } + return found; + } + + /** + * Returns true if a given type is reference according to the SCA + * specification rules for determining reference types The following rules + * are used to determine whether an unannotated field or setter method is a + * property or reference: + * <ol> + * <li>If its type is simple, then it is a property. + * <li>If its type is complex, then if the type is an interface marked by + * + * @Remotable, then it is a reference; otherwise, it is a property. + * <li>Otherwise, if the type associated with the member is an + * array or a java.util.Collection, the basetype is the element + * type of the array or the parameterized type of the + * Collection; otherwise the basetype is the member type. If the + * basetype is an interface with an + * @Remotable or + * @Service annotation then the member is defined as a reference. Otherwise, + * it is defined as a property. + * </ol> + * <p> + * The name of the reference or of the property is derived from the + * name found on the setter method or on the field. + */ + private boolean isReferenceType(Class<?> cls, Type genericType) { + Class<?> baseType = JavaIntrospectionHelper.getBaseType(cls, genericType); + return baseType.isInterface() && baseType.isAnnotationPresent(Remotable.class); + } + + /** + * Returns true if the given operation is defined in the collection of + * service interfaces + */ + private boolean isInServiceInterface(Method operation, List<org.apache.tuscany.sca.assembly.Service> services) { + for (org.apache.tuscany.sca.assembly.Service service : services) { + Interface interface1 = service.getInterfaceContract().getInterface(); + if (interface1 instanceof JavaInterface) { + Class<?> clazz = ((JavaInterface)interface1).getJavaClass(); + if (isMethodMatched(clazz, operation)) { + return true; + } + } + } + return false; + } + + /** + * Test if the class declares a method which matches the signature of the + * given method + * + * @param clazz + * @param method + * @return + */ + private boolean isMethodMatched(Class<?> clazz, Method method) { + if (method.getDeclaringClass() == clazz) { + return true; + } + Method[] methods = clazz.getMethods(); + for (Method m : methods) { + if (JavaIntrospectionHelper.exactMethodMatch(method, m)) { + return true; + } + } + return false; + } + + /** + * Creates a mapped property. + * + * @param name the property name + * @param paramType the property type + */ + private org.apache.tuscany.sca.assembly.Property createProperty(String name, Class<?> paramType) { + org.apache.tuscany.sca.assembly.Property property = assemblyFactory.createProperty(); + property.setName(name); + property.setXSDType(JavaXMLMapper.getXMLType(paramType)); + return property; + } + + private boolean isAnnotated(JavaParameterImpl parameter) { + for (Annotation annotation : parameter.getAnnotations()) { + Class<? extends Annotation> annotType = annotation.annotationType(); + if (annotType.equals(Property.class) || annotType.equals(Reference.class) + || annotType.equals(Resource.class)) { + return true; + } + } + return false; + } + + public boolean areUnique(JavaParameterImpl[] parameters) { + Set<Class> set = new HashSet<Class>(parameters.length); + for (JavaParameterImpl p : parameters) { + if (!set.add(p.getType())) { + return false; + } + } + return true; + } + + public org.apache.tuscany.sca.assembly.Reference createReference(String name, Class<?> paramType) + throws IntrospectionException { + org.apache.tuscany.sca.assembly.Reference reference = assemblyFactory.createReference(); + reference.setName(name); + JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); + reference.setInterfaceContract(interfaceContract); + try { + JavaInterface callInterface = javaFactory.createJavaInterface(paramType); + reference.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); + reference.getInterfaceContract().setCallbackInterface(callbackInterface); + } + reference.setMultiplicity(Multiplicity.ZERO_ONE); + } catch (InvalidInterfaceException e1) { + throw new IntrospectionException(e1); + } + try { + processCallback(paramType, reference); + } catch (InvalidServiceType e) { + throw new IntrospectionException(e); + } + return reference; + } + + public org.apache.tuscany.sca.assembly.Service createService(Class<?> interfaze) throws InvalidInterfaceException { + org.apache.tuscany.sca.assembly.Service service = assemblyFactory.createService(); + service.setName(interfaze.getSimpleName()); + + JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); + service.setInterfaceContract(interfaceContract); + + JavaInterface callInterface = javaFactory.createJavaInterface(interfaze); + service.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); + service.getInterfaceContract().setCallbackInterface(callbackInterface); + } + + Interface javaInterface = service.getInterfaceContract().getInterface(); + javaInterface.setRemotable(interfaze.getAnnotation(Remotable.class) != null); + service.getInterfaceContract().setInterface(javaInterface); + return service; + } + + public void processCallback(Class<?> interfaze, Contract contract) throws InvalidServiceType { + Callback callback = interfaze.getAnnotation(Callback.class); + if (callback != null && !Void.class.equals(callback.value())) { + Class<?> callbackClass = callback.value(); + JavaInterface javaInterface = javaFactory.createJavaInterface(); + javaInterface.setJavaClass(callbackClass); + contract.getInterfaceContract().setCallbackInterface(javaInterface); + } else if (callback != null && Void.class.equals(callback.value())) { + throw new InvalidServiceType("No callback interface specified on annotation", interfaze); + } + } + + public boolean injectionAnnotationsPresent(Annotation[][] annots) { + for (Annotation[] annotations : annots) { + for (Annotation annotation : annotations) { + Class<? extends Annotation> annotType = annotation.annotationType(); + if (annotType.equals(Property.class) || annotType.equals(Reference.class) + || annotType.equals(Resource.class)) { + return true; + } + } + } + return false; + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalCallbackReferenceException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalCallbackReferenceException.java new file mode 100644 index 0000000000..9fe2fcd468 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalCallbackReferenceException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal use of {@link org.osoa.sca.annotations.Callback} on a reference + * + * @version $Rev$ $Date$ + */ +public class IllegalCallbackReferenceException extends IntrospectionException { + private static final long serialVersionUID = -8932525723147700591L; + + public IllegalCallbackReferenceException(String message) { + super(message); + } + + public IllegalCallbackReferenceException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalContextException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalContextException.java new file mode 100644 index 0000000000..f5696122df --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalContextException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal signature for a method decorated with {@link org.osoa.sca.annotations.Context} + * + * @version $Rev$ $Date$ + */ +public class IllegalContextException extends IntrospectionException { + private static final long serialVersionUID = -6946383136750117008L; + + public IllegalContextException(String message) { + super(message); + } + + public IllegalContextException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalDestructorException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalDestructorException.java new file mode 100644 index 0000000000..6a0d60c92f --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalDestructorException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal signature for a method decorated with {@link org.osoa.sca.annotations.Destroy} + * + * @version $Rev$ $Date$ + */ +public class IllegalDestructorException extends IntrospectionException { + private static final long serialVersionUID = 365719353107446326L; + + public IllegalDestructorException(String message) { + super(message); + } + + public IllegalDestructorException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalInitException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalInitException.java new file mode 100644 index 0000000000..8f50852c2d --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalInitException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal signature for a method decorated with {@link @org.osoa.sca.annotations.Init} + * + * @version $Rev$ $Date$ + */ +public class IllegalInitException extends IntrospectionException { + private static final long serialVersionUID = -3690763271986854701L; + + public IllegalInitException(String message) { + super(message); + } + + public IllegalInitException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalPropertyException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalPropertyException.java new file mode 100644 index 0000000000..54f7dfad1e --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalPropertyException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal property definition in a component type + * + * @version $Rev$ $Date$ + */ +public class IllegalPropertyException extends IntrospectionException { + private static final long serialVersionUID = -2836849110706758494L; + + public IllegalPropertyException(String message) { + super(message); + } + + public IllegalPropertyException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalReferenceException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalReferenceException.java new file mode 100644 index 0000000000..25196c56e5 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalReferenceException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal reference definition in a component type + * + * @version $Rev$ $Date$ + */ +public class IllegalReferenceException extends IntrospectionException { + private static final long serialVersionUID = 4612984122225271395L; + + public IllegalReferenceException(String message) { + super(message); + } + + public IllegalReferenceException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalResourceException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalResourceException.java new file mode 100644 index 0000000000..ccfbaf0043 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalResourceException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal resource definition in a component type + * + * @version $Rev$ $Date$ + */ +public class IllegalResourceException extends IntrospectionException { + private static final long serialVersionUID = -1100936539412435579L; + + public IllegalResourceException(String message) { + super(message); + } + + public IllegalResourceException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalServiceDefinitionException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalServiceDefinitionException.java new file mode 100644 index 0000000000..e130f4221d --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalServiceDefinitionException.java @@ -0,0 +1,35 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal use of the {@link @org.osoa.sca.annotations.Service} annotation + * + * @version $Rev$ $Date$ + */ +public class IllegalServiceDefinitionException extends IntrospectionException { + private static final long serialVersionUID = -7151534258405092548L; + + public IllegalServiceDefinitionException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessor.java new file mode 100644 index 0000000000..583ccc86cd --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessor.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.java.introspect.impl; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.osoa.sca.annotations.Init; + +/** + * Processes the {@link @Init} annotation on a component implementation and + * updates the component type with the decorated initializer method + * + * @version $Rev$ $Date$ + */ +public class InitProcessor extends BaseJavaClassVisitor { + + public InitProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + Init annotation = method.getAnnotation(Init.class); + if (annotation == null) { + return; + } + if (method.getParameterTypes().length != 0) { + throw new IllegalInitException("Initializer must not have argments", method); + } + if(!method.getReturnType().equals(void.class)) { + throw new IllegalInitException("Initializer must return void.", method); + } + if (type.getInitMethod() != null) { + throw new DuplicateInitException("More than one initializer found on implementaton"); + } + if (!Modifier.isPublic(method.getModifiers())) { + throw new IllegalInitException("Initializer must be a public method. Invalid annotation @Init found on "+method); + } + type.setInitMethod(method); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConstructorException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConstructorException.java new file mode 100644 index 0000000000..91b97b2caf --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConstructorException.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an invalid constructor definition, e.g. when the number of injection names specified in {@link + * org.osoa.sca.annotations.Constructor} do not match the number of actual constructor parameters + * + * @version $Rev$ $Date$ + */ +public class InvalidConstructorException extends IntrospectionException { + private static final long serialVersionUID = 1411492435210741512L; + + public InvalidConstructorException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConversationalImplementation.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConversationalImplementation.java new file mode 100644 index 0000000000..a1e1d01ab3 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConversationalImplementation.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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Raised when an implementation specifies improper conversational metadata + * + * @version $Rev$ $Date$ + */ +public class InvalidConversationalImplementation extends IntrospectionException { + private static final long serialVersionUID = -5487291552769408149L; + + public InvalidConversationalImplementation(String message) { + super(message); + } + + public InvalidConversationalImplementation(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidPropertyException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidPropertyException.java new file mode 100644 index 0000000000..976b4da120 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidPropertyException.java @@ -0,0 +1,35 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an invalid usage of {@link org.osoa.sca.annotations.Property} + * + * @version $Rev$ $Date$ + */ +public class InvalidPropertyException extends IntrospectionException { + private static final long serialVersionUID = -2682862652069727948L; + + public InvalidPropertyException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidReferenceException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidReferenceException.java new file mode 100644 index 0000000000..e77a6beb0d --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidReferenceException.java @@ -0,0 +1,42 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an invalid usage of {@link org.osoa.sca.annotations.Reference} + * + * @version $Rev$ $Date$ + */ +public class InvalidReferenceException extends IntrospectionException { + private static final long serialVersionUID = -3285246635989254165L; + + public InvalidReferenceException(String message) { + super(message); + } + + public InvalidReferenceException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidReferenceException(Throwable cause) { + super(cause); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidResourceException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidResourceException.java new file mode 100644 index 0000000000..debb5cbacc --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidResourceException.java @@ -0,0 +1,40 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an invalid usage of {@link @org.apache.tuscany.api.annotation.Resource} + * + * @version $Rev$ $Date$ + */ +public class InvalidResourceException extends IntrospectionException { + private static final long serialVersionUID = 511728001735534934L; + + public InvalidResourceException(String message) { + super(message); + } + + public InvalidResourceException(String message, Member member) { + super(message, member); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidServiceType.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidServiceType.java new file mode 100644 index 0000000000..7147da55b4 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidServiceType.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when a service type specified by an {@link org.osoa.sca.annotations.Service} annotation is invalid, e.g. it is + * not an interface + * + * @version $Rev$ $Date$ + */ +public class InvalidServiceType extends IntrospectionException { + private static final long serialVersionUID = -1076466639416644386L; + private Class<?> serviceType; + + public InvalidServiceType(String message) { + super(message); + } + + public InvalidServiceType(String message, Class<?> clazz) { + super(message); + this.serviceType = clazz; + } + + /** + * @return the serviceType + */ + public Class<?> getServiceType() { + return serviceType; + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JavaIntrospectionHelper.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JavaIntrospectionHelper.java new file mode 100644 index 0000000000..6a1876fc5d --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JavaIntrospectionHelper.java @@ -0,0 +1,577 @@ +/* + * 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.java.introspect.impl; + +import java.beans.Introspector; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import org.osoa.sca.CallableReference; + +/** + * Implements various reflection-related operations + * + * @version $Rev$ $Date$ + */ +public final class JavaIntrospectionHelper { + private static final Logger logger = Logger.getLogger(JavaIntrospectionHelper.class.getName()); + private static final Class[] EMPTY_CLASS_ARRY = new Class[0]; + + /** + * Hide the constructor + */ + private JavaIntrospectionHelper() { + } + + /** + * Returns a collection of public, and protected fields declared by a class + * or one of its supertypes + */ + public static Set<Field> getAllPublicAndProtectedFields(Class clazz, boolean validating) { + return getAllPublicAndProtectedFields(clazz, new HashSet<Field>(), validating); + } + + private static void checkInvalidAnnotations(AnnotatedElement element) { + for (Annotation a : element.getAnnotations()) { + if ("org.osoa.sca.annotations".equals(a.annotationType().getPackage().getName())) { + logger.warning("Invalid annotation " + a + " is found on " + element); + } + } + } + + /** + * Recursively evaluates the type hierarchy to return all fields that are + * public or protected + */ + private static Set<Field> getAllPublicAndProtectedFields(Class clazz, Set<Field> fields, boolean validating) { + if (clazz == null || clazz.isArray() || Object.class.equals(clazz)) { + return fields; + } + fields = getAllPublicAndProtectedFields(clazz.getSuperclass(), fields, validating); + Field[] declaredFields = clazz.getDeclaredFields(); + for (final Field field : declaredFields) { + int modifiers = field.getModifiers(); + if ((Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) && !Modifier.isStatic(modifiers)) { + // Allow privileged access to set accessibility. Requires ReflectPermission + // in security policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + field.setAccessible(true); // ignore Java accessibility + return null; + } + }); + fields.add(field); + } else { + if (validating) { + checkInvalidAnnotations(field); + } + } + } + return fields; + } + + /** + * Returns a collection of public and protected methods declared by a class + * or one of its supertypes. Note that overridden methods will not be + * returned in the collection (i.e. only the method override will be). <p/> + * This method can potentially be expensive as reflection information is not + * cached. It is assumed that this method will be used during a + * configuration phase. + */ + public static Set<Method> getAllUniquePublicProtectedMethods(Class clazz, boolean validating) { + return getAllUniqueMethods(clazz, new HashSet<Method>(), validating); + } + + /** + * Recursively evaluates the type hierarchy to return all unique methods + */ + private static Set<Method> getAllUniqueMethods(Class pClass, Set<Method> methods, boolean validating) { + if (pClass == null || pClass.isArray() || Object.class.equals(pClass)) { + return methods; + } + // we first evaluate methods of the subclass and then move to the parent + Method[] declaredMethods = pClass.getDeclaredMethods(); + for (final Method declaredMethod : declaredMethods) { + int modifiers = declaredMethod.getModifiers(); + if ((!Modifier.isPublic(modifiers) && !Modifier.isProtected(modifiers)) || Modifier.isStatic(modifiers)) { + if (validating) { + checkInvalidAnnotations(declaredMethod); + } + continue; + } + if (methods.size() == 0) { + methods.add(declaredMethod); + } else { + List<Method> temp = new ArrayList<Method>(); + boolean matched = false; + for (Method method : methods) { + // only add if not already in the set from a superclass (i.e. + // the method is not overridden) + if (exactMethodMatch(declaredMethod, method)) { + matched = true; + break; + } + } + if (!matched) { + // Allow privileged access to set accessibility. Requires ReflectPermission + // in security policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + declaredMethod.setAccessible(true); + return null; + } + }); + temp.add(declaredMethod); + } + methods.addAll(temp); + temp.clear(); + } + } + // evaluate class hierarchy - this is done last to track inherited + // methods + methods = getAllUniqueMethods(pClass.getSuperclass(), methods, validating); + return methods; + } + + /** + * Finds the closest matching field with the given name, that is, a field of + * the exact specified type or, alternately, of a supertype. + * + * @param name the name of the field + * @param type the field type + * @param fields the collection of fields to search + * @return the matching field or null if not found + */ + public static Field findClosestMatchingField(String name, Class type, Set<Field> fields) { + Field candidate = null; + for (Field field : fields) { + if (field.getName().equals(name)) { + if (field.getType().equals(type)) { + return field; // exact match + } else if (field.getType().isAssignableFrom(type) || (field.getType().isPrimitive() && primitiveAssignable(field + .getType(), + type))) { + // We could have the situation where a field parameter is a + // primitive and the demarshalled value is + // an object counterpart (e.g. Integer and int) + // @spec issue + // either an interface or super class, so keep a reference + // until + // we know there are no closer types + candidate = field; + } + } + } + if (candidate != null) { + return candidate; + } else { + return null; + } + } + + /** + * Finds the closest matching method with the given name, that is, a method + * taking the exact parameter types or, alternately, parameter supertypes. + * + * @param name the name of the method + * @param types the method parameter types + * @param methods the collection of methods to search + * @return the matching method or null if not found + */ + public static Method findClosestMatchingMethod(String name, Class[] types, Set<Method> methods) { + if (types == null) { + types = EMPTY_CLASS_ARRY; + } + Method candidate = null; + for (Method method : methods) { + if (method.getName().equals(name) && method.getParameterTypes().length == types.length) { + Class<?>[] params = method.getParameterTypes(); + boolean disqualify = false; + boolean exactMatch = true; + for (int i = 0; i < params.length; i++) { + if (!params[i].equals(types[i]) && !params[i].isAssignableFrom(types[i])) { + // no match + disqualify = true; + exactMatch = false; + break; + } else if (!params[i].equals(types[i]) && params[i].isAssignableFrom(types[i])) { + // not exact match + exactMatch = false; + } + } + if (disqualify) { + continue; + } else if (exactMatch) { + return method; + } else { + candidate = method; + } + } + } + if (candidate != null) { + return candidate; + } else { + return null; + } + } + + /** + * Determines if two methods "match" - that is, they have the same method + * names and exact parameter types (one is not a supertype of the other) + */ + public static boolean exactMethodMatch(Method method1, Method method2) { + if (!method1.getName().equals(method2.getName())) { + return false; + } + Class<?>[] types1 = method1.getParameterTypes(); + Class<?>[] types2 = method2.getParameterTypes(); + if (types1.length != types2.length) { + return false; + } + boolean matched = true; + for (int i = 0; i < types1.length; i++) { + if (types1[i] != types2[i]) { + matched = false; + break; + } + } + return matched; + } + + public static <T> Constructor<T> getDefaultConstructor(Class<T> clazz) throws NoSuchMethodException { + return clazz.getConstructor((Class[])null); + } + + /** + * Returns the simple name of a class - i.e. the class name devoid of its + * package qualifier + * + * @param implClass the implementation class + */ + public static String getBaseName(Class<?> implClass) { + return implClass.getSimpleName(); + } + + public static boolean isImmutable(Class clazz) { + return String.class == clazz || clazz.isPrimitive() + || Number.class.isAssignableFrom(clazz) + || Boolean.class.isAssignableFrom(clazz) + || Character.class.isAssignableFrom(clazz) + || Byte.class.isAssignableFrom(clazz); + } + + /** + * Takes a property name and converts it to a getter method name according + * to JavaBean conventions. For example, property + * <code>foo<code> is returned as <code>getFoo</code> + */ + public static String toGetter(String name) { + return "get" + name.toUpperCase().substring(0, 1) + name.substring(1); + } + + /** + * Takes a setter or getter method name and converts it to a property name + * according to JavaBean conventions. For example, <code>setFoo(var)</code> + * is returned as property <code>foo<code> + */ + public static String toPropertyName(String name) { + if (!name.startsWith("set")) { + return name; + } + return Introspector.decapitalize(name.substring(3)); + } + + public static Class<?> getErasure(Type type) { + if (type instanceof Class) { + return (Class)type; + } else if (type instanceof GenericArrayType) { + // FIXME: How to deal with the []? + GenericArrayType arrayType = (GenericArrayType)type; + return getErasure(arrayType.getGenericComponentType()); + } else if (type instanceof ParameterizedType) { + ParameterizedType pType = (ParameterizedType)type; + return getErasure(pType.getRawType()); + } else if (type instanceof WildcardType) { + WildcardType wType = (WildcardType)type; + Type[] types = wType.getUpperBounds(); + return getErasure(types[0]); + } else if (type instanceof TypeVariable) { + TypeVariable var = (TypeVariable)type; + Type[] types = var.getBounds(); + return getErasure(types[0]); + } + return null; + } + + public static Class<?> getBaseType(Class<?> cls, Type genericType) { + if (cls.isArray()) { + return cls.getComponentType(); + } else if (Collection.class.isAssignableFrom(cls)) { + if (genericType instanceof ParameterizedType) { + // Collection<BaseType> + ParameterizedType parameterizedType = (ParameterizedType)genericType; + Type baseType = parameterizedType.getActualTypeArguments()[0]; + if (baseType instanceof GenericArrayType) { + // Base is array + return cls; + } else { + return getErasure(baseType); + } + } else { + return cls; + } + } else { + return cls; + } + } + + public static Type getParameterType(Type type) { + if (type instanceof ParameterizedType) { + // Collection<BaseType> + ParameterizedType parameterizedType = (ParameterizedType)type; + Type baseType = parameterizedType.getActualTypeArguments()[0]; + return baseType; + } else { + return Object.class; + } + } + + public static Class<?> getBusinessInterface(Class<?> cls, Type callableReferenceType) { + if (CallableReference.class.isAssignableFrom(cls) && callableReferenceType instanceof ParameterizedType) { + // Collection<BaseType> + ParameterizedType parameterizedType = (ParameterizedType)callableReferenceType; + Type baseType = parameterizedType.getActualTypeArguments()[0]; + if (baseType instanceof GenericArrayType) { + // Base is array + return cls; + } else { + return getErasure(baseType); + } + } + return Object.class; + } + + /** + * Takes a property name and converts it to a setter method name according + * to JavaBean conventions. For example, the property + * <code>foo<code> is returned as <code>setFoo(var)</code> + */ + public static String toSetter(String name) { + return "set" + name.toUpperCase().substring(0, 1) + name.substring(1); + } + + /** + * Compares a two types, assuming one is a primitive, to determine if the + * other is its object counterpart + */ + private static boolean primitiveAssignable(Class memberType, Class param) { + if (memberType == Integer.class) { + return param == Integer.TYPE; + } else if (memberType == Double.class) { + return param == Double.TYPE; + } else if (memberType == Float.class) { + return param == Float.TYPE; + } else if (memberType == Short.class) { + return param == Short.TYPE; + } else if (memberType == Character.class) { + return param == Character.TYPE; + } else if (memberType == Boolean.class) { + return param == Boolean.TYPE; + } else if (memberType == Byte.class) { + return param == Byte.TYPE; + } else if (param == Integer.class) { + return memberType == Integer.TYPE; + } else if (param == Double.class) { + return memberType == Double.TYPE; + } else if (param == Float.class) { + return memberType == Float.TYPE; + } else if (param == Short.class) { + return memberType == Short.TYPE; + } else if (param == Character.class) { + return memberType == Character.TYPE; + } else if (param == Boolean.class) { + return memberType == Boolean.TYPE; + } else if (param == Byte.class) { + return memberType == Byte.TYPE; + } else { + return false; + } + } + + /** + * Returns the generic types represented in the given type. Usage as + * follows: <code> + * JavaIntrospectionHelper.getGenerics(field.getGenericType()); + * <p/> + * JavaIntrospectionHelper.getGenerics(m.getGenericParameterTypes()[0];); </code> + * + * @return the generic types in order of declaration or an empty array if + * the type is not genericized + */ + public static List<? extends Type> getGenerics(Type genericType) { + List<Type> classes = new ArrayList<Type>(); + if (genericType instanceof ParameterizedType) { + ParameterizedType ptype = (ParameterizedType)genericType; + // get the type arguments + Type[] targs = ptype.getActualTypeArguments(); + for (Type targ : targs) { + classes.add(targ); + } + } + return classes; + } + + /** + * Returns the generic type specified by the class at the given position as + * in: <p/> <code> public class Foo<Bar,Baz>{ //.. } + * <p/> + * JavaIntrospectionHelper.introspectGeneric(Foo.class,1); <code> + * <p/> + * will return Baz. + */ + public static Class introspectGeneric(Class<?> clazz, int pos) { + assert clazz != null : "No class specified"; + Type type = clazz.getGenericSuperclass(); + if (type instanceof ParameterizedType) { + Type[] args = ((ParameterizedType)type).getActualTypeArguments(); + if (args.length <= pos) { + throw new IllegalArgumentException("Invalid index value for generic class " + clazz.getName()); + } + return (Class)((ParameterizedType)type).getActualTypeArguments()[pos]; + } else { + Type[] interfaces = clazz.getGenericInterfaces(); + for (Type itype : interfaces) { + if (!(itype instanceof ParameterizedType)) { + continue; + } + ParameterizedType interfaceType = (ParameterizedType)itype; + return (Class)interfaceType.getActualTypeArguments()[0]; + } + } + return null; + } + + /** + * Returns the set of interfaces implemented by the given class and its + * ancestors or a blank set if none + */ + public static Set<Class> getAllInterfaces(Class clazz) { + Set<Class> implemented = new HashSet<Class>(); + getAllInterfaces(clazz, implemented); + return implemented; + } + + private static void getAllInterfaces(Class clazz, Set<Class> implemented) { + Class[] interfaces = clazz.getInterfaces(); + for (Class interfaze : interfaces) { + implemented.add(interfaze); + } + Class<?> superClass = clazz.getSuperclass(); + // Object has no superclass so check for null + if (superClass != null && !superClass.equals(Object.class)) { + getAllInterfaces(superClass, implemented); + } + } + + public static boolean isSetter(Method method) { + return (void.class == method.getReturnType() && method.getParameterTypes().length == 1 && method.getName() + .startsWith("set")); + } + + public static boolean isGetter(Method method) { + return (void.class != method.getReturnType() && method.getParameterTypes().length == 0 && method.getName() + .startsWith("get")); + } + + private final static Map<Class, String> signatures = new HashMap<Class, String>(); + static { + signatures.put(boolean.class, "Z"); + signatures.put(byte.class, "B"); + signatures.put(char.class, "C"); + signatures.put(short.class, "S"); + signatures.put(int.class, "I"); + signatures.put(long.class, "J"); + signatures.put(float.class, "F"); + signatures.put(double.class, "D"); + }; + + public static String getSignature(Class<?> cls) { + if (cls.isPrimitive()) { + return signatures.get(cls); + } + if (cls.isArray()) { + return "[" + getSignature(cls.getComponentType()); + } + return "L" + cls.getName().replace('.', '/') + ";"; + } + + public static Class<?> getArrayType(Class<?> componentType, int dims) throws ClassNotFoundException { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < dims; i++) { + buf.append('['); + } + buf.append(getSignature(componentType)); + return Class.forName(buf.toString(), false, componentType.getClassLoader()); + } + + public static Set<Method> getPrivateMethods(Class clazz) { + Set<Method> methods = new HashSet<Method>(); + Method[] declaredMethods = clazz.getDeclaredMethods(); + for (final Method declaredMethod : declaredMethods) { + int modifiers = declaredMethod.getModifiers(); + if(Modifier.isPrivate(modifiers)) { + methods.add(declaredMethod); + } + } + + return methods; + } + + public static Set<Field> getPrivateFields(Class clazz) { + Set<Field> fields = new HashSet<Field>(); + Field[] declaredFields = clazz.getDeclaredFields(); + for (final Field declaredField : declaredFields) { + int modifiers = declaredField.getModifiers(); + if(Modifier.isPrivate(modifiers)) { + fields.add(declaredField); + } + } + + return fields; + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/NoConstructorException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/NoConstructorException.java new file mode 100644 index 0000000000..453cfa35fe --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/NoConstructorException.java @@ -0,0 +1,37 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when a suitable constructor for a component implementation cannot be found + * + * @version $Rev$ $Date$ + */ +public class NoConstructorException extends IntrospectionException { + private static final long serialVersionUID = 3086706387280694424L; + + public NoConstructorException() { + } + + public NoConstructorException(String message) { + super(message); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessor.java new file mode 100644 index 0000000000..954a3abbc8 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessor.java @@ -0,0 +1,292 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Callback; +import org.apache.tuscany.sca.assembly.ConfiguredOperation; +import org.apache.tuscany.sca.assembly.OperationsConfigurator; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicyFactory; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySetAttachPoint; +import org.osoa.sca.annotations.PolicySets; +import org.osoa.sca.annotations.Requires; + +/** + * Processes an {@link org.osoa.sca.annotations.Requires} annotation + * + * @version $Rev$ $Date$ + */ +public class PolicyProcessor extends BaseJavaClassVisitor { + + private PolicyFactory policyFactory; + + public PolicyProcessor(AssemblyFactory assemblyFactory, PolicyFactory policyFactory) { + super(assemblyFactory); + this.policyFactory = policyFactory; + } + + private QName getQName(String intentName) { + QName qname; + if (intentName.startsWith("{")) { + int i = intentName.indexOf('}'); + if (i != -1) { + qname = new QName(intentName.substring(1, i), intentName.substring(i + 1)); + } else { + qname = new QName("", intentName); + } + } else { + qname = new QName("", intentName); + } + return qname; + } + + /** + * Read policy intents on the given interface or class + * @param clazz + * @param requiredIntents + */ + private void readIntentsAndPolicySets(Class<?> clazz, + List<Intent> requiredIntents, + List<PolicySet> policySets) { + Requires intentAnnotation = clazz.getAnnotation(Requires.class); + if (intentAnnotation != null) { + String[] intentNames = intentAnnotation.value(); + if (intentNames.length != 0) { + for (String intentName : intentNames) { + + // Add each intent to the list + Intent intent = policyFactory.createIntent(); + intent.setName(getQName(intentName)); + requiredIntents.add(intent); + } + } + } + + PolicySets policySetAnnotation = clazz.getAnnotation(PolicySets.class); + if (policySetAnnotation != null) { + String[] policySetNames = policySetAnnotation.value(); + if (policySetNames.length != 0) { + for (String policySetName : policySetNames) { + + // Add each intent to the list + PolicySet policySet = policyFactory.createPolicySet(); + policySet.setName(getQName(policySetName)); + policySets.add(policySet); + } + } + } + } + + private void readIntents(Requires intentAnnotation, List<Intent> requiredIntents) { + //Requires intentAnnotation = method.getAnnotation(Requires.class); + if (intentAnnotation != null) { + String[] intentNames = intentAnnotation.value(); + if (intentNames.length != 0) { + //Operation operation = assemblyFactory.createOperation(); + //operation.setName(method.getName()); + //operation.setUnresolved(true); + for (String intentName : intentNames) { + + // Add each intent to the list, associated with the + // operation corresponding to the annotated method + Intent intent = policyFactory.createIntent(); + intent.setName(getQName(intentName)); + //intent.getOperations().add(operation); + requiredIntents.add(intent); + } + } + } + } + + private void readPolicySets(PolicySets policySetAnnotation, List<PolicySet> policySets) { + if (policySetAnnotation != null) { + String[] policySetNames = policySetAnnotation.value(); + if (policySetNames.length != 0) { + //Operation operation = assemblyFactory.createOperation(); + //operation.setName(method.getName()); + //operation.setUnresolved(true); + for (String policySetName : policySetNames) { + // Add each intent to the list, associated with the + // operation corresponding to the annotated method + PolicySet policySet = policyFactory.createPolicySet(); + policySet.setName(getQName(policySetName)); + //intent.getOperations().add(operation); + policySets.add(policySet); + } + } + } + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + + // Read intents on the Java implementation class + if ( type instanceof PolicySetAttachPoint ) { + readIntentsAndPolicySets(clazz, + ((PolicySetAttachPoint)type).getRequiredIntents(), + ((PolicySetAttachPoint)type).getPolicySets()); + } + + // Process annotations on the service interfaces + //TODO This will have to move to a JavaInterface introspector later + for (Service service: type.getServices()) { + InterfaceContract interfaceContract = service.getInterfaceContract(); + if (interfaceContract instanceof JavaInterfaceContract) { + JavaInterfaceContract javaInterfaceContract = (JavaInterfaceContract)interfaceContract; + + // Read intents on the service interface + if (javaInterfaceContract.getInterface() != null) { + JavaInterface javaInterface = (JavaInterface)javaInterfaceContract.getInterface(); + if (javaInterface.getJavaClass() != null) { + readIntentsAndPolicySets(javaInterface.getJavaClass(), + service.getRequiredIntents(), + service.getPolicySets()); + + // Read intents on the service interface methods + Method[] methods = javaInterface.getJavaClass().getMethods(); + ConfiguredOperation confOp = null; + for (Method method: methods) { + if ( method.getAnnotation(Requires.class) != null || + method.getAnnotation(PolicySets.class) != null ) { + confOp = assemblyFactory.createConfiguredOperation(); + confOp.setName(method.getName()); + confOp.setContractName(service.getName()); + + service.getConfiguredOperations().add(confOp); + readIntents(method.getAnnotation(Requires.class), confOp.getRequiredIntents()); + readPolicySets(method.getAnnotation(PolicySets.class), confOp.getPolicySets()); + } + } + } + + } + + // Read intents on the callback interface + if (javaInterfaceContract.getCallbackInterface() != null) { + JavaInterface javaCallbackInterface = (JavaInterface)javaInterfaceContract.getCallbackInterface(); + if (javaCallbackInterface.getJavaClass() != null) { + Callback callback = service.getCallback(); + if (callback == null) { + callback = assemblyFactory.createCallback(); + service.setCallback(callback); + } + readIntentsAndPolicySets(javaCallbackInterface.getJavaClass(), + callback.getRequiredIntents(), + callback.getPolicySets()); + + // Read intents on the callback interface methods + Method[] methods = javaCallbackInterface.getJavaClass().getMethods(); + ConfiguredOperation confOp = null; + for (Method method: methods) { + confOp = assemblyFactory.createConfiguredOperation(); + confOp.setName(method.getName()); + callback.getConfiguredOperations().add(confOp); + readIntents(method.getAnnotation(Requires.class), confOp.getRequiredIntents()); + readPolicySets(method.getAnnotation(PolicySets.class), confOp.getPolicySets()); + } + } + } + } + } + } + + private Reference getReference(Method method, JavaImplementation type) { + //since the ReferenceProcessor is called ahead of the PolicyProcessor the type should have + //picked up the reference setter method + org.osoa.sca.annotations.Reference annotation = + method.getAnnotation(org.osoa.sca.annotations.Reference.class); + if (annotation != null) { + if (JavaIntrospectionHelper.isSetter(method)) { + String name = annotation.name(); + if ("".equals(name)) { + name = JavaIntrospectionHelper.toPropertyName(method.getName()); + } + return getReferenceByName(name, type); + } + } + return null; + } + + private Reference getReferenceByName(String name, JavaImplementation type) { + for ( Reference reference : type.getReferences() ) { + if ( reference.getName().equals(name) ) { + return reference; + } + } + return null; + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + org.osoa.sca.annotations.Reference annotation = + field.getAnnotation( org.osoa.sca.annotations.Reference.class); + if (annotation == null) { + return; + } + String name = annotation.name(); + if ("".equals(name)) { + name = field.getName(); + } + + Reference reference = null; + if ( (reference = getReferenceByName(name, type)) != null ) { + readIntents(field.getAnnotation(Requires.class), reference.getRequiredIntents()); + readPolicySets(field.getAnnotation(PolicySets.class), reference.getPolicySets()); + } + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + Reference reference = null; + if ( (reference = getReference(method, type)) != null ) { + readIntents(method.getAnnotation(Requires.class), reference.getRequiredIntents()); + readPolicySets(method.getAnnotation(PolicySets.class), reference.getPolicySets()); + } else { + if ( type instanceof OperationsConfigurator ) { + //Read the intents specified on the given implementation method + if ( (method.getAnnotation(Requires.class) != null || + method.getAnnotation(PolicySets.class) != null ) && + (type instanceof PolicySetAttachPoint )) { + ConfiguredOperation confOp = assemblyFactory.createConfiguredOperation(); + confOp.setName(method.getName()); + ((OperationsConfigurator)type).getConfiguredOperations().add(confOp); + + + readIntents(method.getAnnotation(Requires.class), confOp.getRequiredIntents()); + readPolicySets(method.getAnnotation(PolicySets.class), confOp.getPolicySets()); + } + } + } + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessor.java new file mode 100644 index 0000000000..cf1b4a9830 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessor.java @@ -0,0 +1,46 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.osoa.sca.annotations.Property; + +/** + * Processes an {@link @Property} annotation, updating the component type with + * corresponding {@link JavaMappedProperty} + * + * @version $Rev$ $Date$ + */ +public class PropertyProcessor extends AbstractPropertyProcessor<Property> { + + public PropertyProcessor(AssemblyFactory assemblyFactory) { + super(assemblyFactory, Property.class); + } + + @Override + protected String getName(Property annotation) { + return annotation.name(); + } + + @Override + protected void initProperty(org.apache.tuscany.sca.assembly.Property property, Property annotation) { + property.setMustSupply(annotation.required()); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessor.java new file mode 100644 index 0000000000..a1f8a766ae --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessor.java @@ -0,0 +1,208 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getBaseType; + +import java.lang.annotation.ElementType; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +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.osoa.sca.CallableReference; +import org.osoa.sca.annotations.Reference; + +/** + * Processes an {@link @Reference} annotation, updating the component type with + * corresponding {@link + * org.apache.tuscany.spi.implementation.java.JavaMappedReference} + * + * @version $Rev$ $Date$ + */ +public class ReferenceProcessor extends BaseJavaClassVisitor { + private JavaInterfaceFactory javaFactory; + + public ReferenceProcessor(AssemblyFactory assemblyFactory, JavaInterfaceFactory javaFactory) { + super(assemblyFactory); + this.javaFactory = javaFactory; + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + Reference annotation = method.getAnnotation(Reference.class); + if (annotation == null) { + return; // Not a reference annotation. + } + if (!JavaIntrospectionHelper.isSetter(method)) { + throw new IllegalReferenceException("Annotated method is not a setter: " + method, method); + } + String name = annotation.name(); + if ("".equals(name)) { + name = JavaIntrospectionHelper.toPropertyName(method.getName()); + } + JavaElementImpl ref = type.getReferenceMembers().get(name); + // Setter override field + if (ref != null && ref.getElementType() != ElementType.FIELD) { + throw new DuplicateReferenceException(name); + } + removeReference(ref, type); + + JavaElementImpl element = new JavaElementImpl(method, 0); + org.apache.tuscany.sca.assembly.Reference reference = createReference(element, name); + type.getReferences().add(reference); + type.getReferenceMembers().put(name, element); + } + + private boolean removeReference(JavaElementImpl ref, JavaImplementation type) { + if (ref == null) { + return false; + } + List<org.apache.tuscany.sca.assembly.Reference> refs = type.getReferences(); + for (int i = 0; i < refs.size(); i++) { + if (refs.get(i).getName().equals(ref.getName())) { + refs.remove(i); + return true; + } + } + return false; + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + Reference annotation = field.getAnnotation(Reference.class); + if (annotation == null) { + return; + } + String name = annotation.name(); + if ("".equals(name)) { + name = field.getName(); + } + JavaElementImpl ref = type.getReferenceMembers().get(name); + if (ref != null && ref.getElementType() == ElementType.FIELD) { + throw new DuplicateReferenceException(name); + } + + // Setter method override field + if (ref == null) { + JavaElementImpl element = new JavaElementImpl(field); + org.apache.tuscany.sca.assembly.Reference reference = createReference(element, name); + type.getReferences().add(reference); + type.getReferenceMembers().put(name, element); + } + } + + @Override + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) + throws IntrospectionException { + Reference refAnnotation = parameter.getAnnotation(Reference.class); + if (refAnnotation == null) { + return; + } + String paramName = parameter.getName(); + String name = getReferenceName(paramName, parameter.getIndex(), refAnnotation.name()); + JavaElementImpl ref = type.getReferenceMembers().get(name); + + // Setter override field + if (ref != null && ref.getElementType() != ElementType.FIELD) { + throw new DuplicateReferenceException(name); + } + + removeReference(ref, type); + org.apache.tuscany.sca.assembly.Reference reference = createReference(parameter, name); + type.getReferences().add(reference); + type.getReferenceMembers().put(name, parameter); + parameter.setClassifer(Reference.class); + parameter.setName(name); + } + + private String getReferenceName(String paramName, int pos, String name) throws InvalidConstructorException { + if ("".equals(name)) { + name = paramName; + } + if ("".equals(name)) { + return "_ref" + pos; + } + if (!"".equals(paramName) && !name.equals(paramName)) { + throw new InvalidConstructorException("Mismatching names specified for reference parameter " + pos); + } else { + return name; + } + } + + private org.apache.tuscany.sca.assembly.Reference createReference(JavaElementImpl element, String name) + throws IntrospectionException { + org.apache.tuscany.sca.assembly.Reference reference = assemblyFactory.createReference(); + JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); + reference.setInterfaceContract(interfaceContract); + + // reference.setMember((Member)element.getAnchor()); + boolean required = true; + Reference ref = element.getAnnotation(Reference.class); + if (ref != null) { + required = ref.required(); + } + // reference.setRequired(required); + reference.setName(name); + Class<?> rawType = element.getType(); + if (rawType.isArray() || Collection.class.isAssignableFrom(rawType)) { + if (required) { + reference.setMultiplicity(Multiplicity.ONE_N); + } else { + reference.setMultiplicity(Multiplicity.ZERO_N); + } + } else { + if (required) { + reference.setMultiplicity(Multiplicity.ONE_ONE); + } else { + reference.setMultiplicity(Multiplicity.ZERO_ONE); + } + } + Type genericType = element.getGenericType(); + Class<?> baseType = getBaseType(rawType, genericType); + if (CallableReference.class.isAssignableFrom(baseType)) { + if (Collection.class.isAssignableFrom(rawType)) { + genericType = JavaIntrospectionHelper.getParameterType(genericType); + } + baseType = JavaIntrospectionHelper.getBusinessInterface(baseType, genericType); + } + try { + JavaInterface callInterface = javaFactory.createJavaInterface(baseType); + reference.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); + reference.getInterfaceContract().setCallbackInterface(callbackInterface); + } + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + return reference; + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/Resource.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/Resource.java new file mode 100644 index 0000000000..3d43e39ce8 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/Resource.java @@ -0,0 +1,49 @@ +/* + * 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.java.introspect.impl; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation used to indicate a resource should be provided to an implementation by the runtime. + * + * @version $Rev$ $Date$ + */ +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Resource { + + /** + * Denotes the name of the resource declared by the implementation. + */ + String name() default ""; + + /** + * Denotes if the resource is optional + */ + boolean optional() default false; + + /** + * Denotes the default name of the resource provided by the runtime environment. + */ + String mappedName() default ""; +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessor.java new file mode 100644 index 0000000000..e15f9a0d6a --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessor.java @@ -0,0 +1,137 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl; + +/** + * Processes an {@link @Resource} annotation, updating the component type with + * corresponding {@link org.apache.tuscany.spi.implementation.java.JavaResourceImpl} + * + * @version $Rev$ $Date$ + */ +public class ResourceProcessor extends BaseJavaClassVisitor { + + public ResourceProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + org.apache.tuscany.sca.implementation.java.introspect.impl.Resource annotation = method + .getAnnotation(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + if (annotation == null) { + return; + } + if (method.getParameterTypes().length != 1) { + throw new IllegalResourceException("Resource setter must have one parameter", method); + } + String name = annotation.name(); + if (name.length() < 1) { + name = JavaIntrospectionHelper.toPropertyName(method.getName()); + } + if (type.getResources().get(name) != null) { + throw new DuplicateResourceException(name); + } + + String mappedName = annotation.mappedName(); + JavaResourceImpl resource = createResource(name, new JavaElementImpl(method, 0)); + resource.setOptional(annotation.optional()); + if (mappedName.length() > 0) { + resource.setMappedName(mappedName); + } + type.getResources().put(resource.getName(), resource); + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + + org.apache.tuscany.sca.implementation.java.introspect.impl.Resource annotation = field + .getAnnotation(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + if (annotation == null) { + return; + } + String name = annotation.name(); + if (name.length() < 1) { + name = field.getName(); + } + if (type.getResources().get(name) != null) { + throw new DuplicateResourceException(name); + } + + String mappedName = annotation.mappedName(); + + JavaResourceImpl resource = createResource(name, new JavaElementImpl(field)); + resource.setOptional(annotation.optional()); + if (mappedName.length() > 0) { + resource.setMappedName(mappedName); + } + type.getResources().put(resource.getName(), resource); + } + + @SuppressWarnings("unchecked") + public JavaResourceImpl createResource(String name, JavaElementImpl element) { + element.setClassifer(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + element.setName(name); + return new JavaResourceImpl(element); + } + + @Override + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) + throws IntrospectionException { + org.apache.tuscany.sca.implementation.java.introspect.impl.Resource resourceAnnotation = parameter + .getAnnotation(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + if (resourceAnnotation != null) { + String name = resourceAnnotation.name(); + if ("".equals(name)) { + name = parameter.getName(); + } + if ("".equals(name)) { + throw new InvalidResourceException("Missing resource name", (Member)parameter.getAnchor()); + } + + if (!"".equals(parameter.getName()) && !name.equals(parameter.getName())) { + throw new InvalidConstructorException("Mismatched resource name: " + parameter); + } + + if (type.getResources().get(name) != null) { + throw new DuplicateResourceException(name); + } + + String mappedName = resourceAnnotation.mappedName(); + + JavaResourceImpl resource = createResource(name, parameter); + resource.setOptional(resourceAnnotation.optional()); + if (mappedName.length() > 0) { + resource.setMappedName(mappedName); + } + type.getResources().put(resource.getName(), resource); + } + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessor.java new file mode 100644 index 0000000000..a3d3889d30 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessor.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.java.introspect.impl; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaScopeImpl; + +/** + * Processes the {@link JavaScopeImpl} annotation and updates the component type with the corresponding implmentation scope + * + * @version $Rev$ $Date$ + */ +public class ScopeProcessor extends BaseJavaClassVisitor { + + public ScopeProcessor(AssemblyFactory factory) { + super(factory); + } + + @Override + public <T> void visitClass(Class<T> clazz, + JavaImplementation type) + throws IntrospectionException { + org.osoa.sca.annotations.Scope annotation = clazz.getAnnotation(org.osoa.sca.annotations.Scope.class); + if (annotation == null) { + type.setJavaScope(JavaScopeImpl.STATELESS); + return; + } + String name = annotation.value(); + JavaScopeImpl scope; + if ("COMPOSITE".equals(name)) { + scope = JavaScopeImpl.COMPOSITE; + } else if ("SESSION".equals(name)) { + scope = JavaScopeImpl.SESSION; + } else if ("CONVERSATION".equals(name)) { + scope = JavaScopeImpl.CONVERSATION; + } else if ("REQUEST".equals(name)) { + scope = JavaScopeImpl.REQUEST; + } else { + scope = new JavaScopeImpl(name); + } + type.setJavaScope(scope); + } +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessor.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessor.java new file mode 100644 index 0000000000..78963f5b03 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessor.java @@ -0,0 +1,179 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getAllInterfaces; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Set; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +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.osoa.sca.CallableReference; +import org.osoa.sca.annotations.Callback; +import org.osoa.sca.annotations.Remotable; + +/** + * Processes an {@link org.osoa.sca.annotations.Service} annotation and updates + * the component type with corresponding {@link Service}s. Also processes + * related {@link org.osoa.sca.annotations.Callback} annotations. + * + * @version $Rev$ $Date$ + */ +public class ServiceProcessor extends BaseJavaClassVisitor { + private static final Logger logger = Logger.getLogger(ServiceProcessor.class.getName()); + private JavaInterfaceFactory javaFactory; + + public ServiceProcessor(AssemblyFactory assemblyFactory, JavaInterfaceFactory javaFactory) { + super(assemblyFactory); + this.javaFactory = javaFactory; + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + org.osoa.sca.annotations.Service annotation = clazz.getAnnotation(org.osoa.sca.annotations.Service.class); + if (annotation == null) { + // scan interfaces for remotable + Set<Class> interfaces = getAllInterfaces(clazz); + for (Class<?> interfaze : interfaces) { + if (interfaze.isAnnotationPresent(Remotable.class) || interfaze.isAnnotationPresent(Callback.class)) { + Service service; + try { + service = createService(interfaze); + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + type.getServices().add(service); + } + } + return; + } + Class<?>[] interfaces = annotation.interfaces(); + if (interfaces.length == 0) { + Class<?> interfaze = annotation.value(); + if (Void.class.equals(interfaze)) { + //throw new IllegalServiceDefinitionException("No interfaces specified"); + logger.warning("Ignoring @Service annotation. No interfaces specified. class = "+clazz.getName()); + } else { + interfaces = new Class<?>[1]; + interfaces[0] = interfaze; + } + } + for (Class<?> interfaze : interfaces) { + try { + Service service = createService(interfaze); + type.getServices().add(service); + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + } + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + + Callback annotation = method.getAnnotation(Callback.class); + if (annotation == null) { + return; + } + if(Modifier.isPrivate(method.getModifiers())) { + throw new IllegalCallbackReferenceException("Illegal annotation @Callback found on "+method, method); + } + if (method.getParameterTypes().length != 1) { + throw new IllegalCallbackReferenceException("Setter must have one parameter", method); + } + JavaElementImpl element = new JavaElementImpl(method, 0); + createCallback(type, element); + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + + Callback annotation = field.getAnnotation(Callback.class); + if (annotation == null) { + return; + } + if(Modifier.isPrivate(field.getModifiers())) { + throw new IllegalCallbackReferenceException("Illegal annotation @Callback found on "+field, field); + } + JavaElementImpl element = new JavaElementImpl(field); + createCallback(type, element); + } + + /** + * @param type + * @param element + * @throws IllegalCallbackReferenceException + */ + private void createCallback(JavaImplementation type, JavaElementImpl element) + throws IllegalCallbackReferenceException { + Service callbackService = null; + Class<?> callbackClass = element.getType(); + Type genericType = element.getGenericType(); + Class<?> baseType = callbackClass; + if(CallableReference.class.isAssignableFrom(baseType)) { + // @Callback protected CallableReference<MyCallback> callback; + // The base type will be MyCallback + baseType = JavaIntrospectionHelper.getBusinessInterface(baseType, genericType); + } + for (Service service : type.getServices()) { + JavaInterface javaInterface = (JavaInterface)service.getInterfaceContract().getCallbackInterface(); + if (javaInterface != null && baseType == javaInterface.getJavaClass()) { + callbackService = service; + } + } + if (callbackService == null) { + throw new IllegalCallbackReferenceException("Callback type does not match a service callback interface: " + type.getName() ); + } + if(type.getCallbackMembers().get(baseType.getName()) == null) { + type.getCallbackMembers().put(baseType.getName(), new ArrayList<JavaElementImpl>()); + } + type.getCallbackMembers().get(baseType.getName()).add(element); + } + + public Service createService(Class<?> interfaze) throws InvalidInterfaceException { + Service service = assemblyFactory.createService(); + JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); + service.setInterfaceContract(interfaceContract); + + // create a relative URI + service.setName(interfaze.getSimpleName()); + + 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; + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceTypeNotFoundException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceTypeNotFoundException.java new file mode 100644 index 0000000000..e1ca3ea565 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceTypeNotFoundException.java @@ -0,0 +1,35 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when a service interface cannot be determined based on a heuristic evaluation of an implementation + * + * @version $Rev$ $Date$ + */ +public class ServiceTypeNotFoundException extends IntrospectionException { + private static final long serialVersionUID = -5124437274726947007L; + + public ServiceTypeNotFoundException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/UnknownContextTypeException.java b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/UnknownContextTypeException.java new file mode 100644 index 0000000000..57d224b2bf --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/UnknownContextTypeException.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +/** + * Thrown when a method or field marked with {@link org.osoa.sca.annotations.Context} takes an unknown type + * + * @version $Rev$ $Date$ + */ +public class UnknownContextTypeException extends IllegalContextException { + private static final long serialVersionUID = 8125863714365422419L; + + public UnknownContextTypeException(String message) { + super(message); + } + +} diff --git a/java/sca/modules/implementation-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivator b/java/sca/modules/implementation-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivator new file mode 100644 index 0000000000..df60d57cf9 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivator @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+org.apache.tuscany.sca.implementation.java.impl.JavaImplementationActivator
diff --git a/java/sca/modules/implementation-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.implementation.java.JavaImplementationFactory b/java/sca/modules/implementation-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.implementation.java.JavaImplementationFactory new file mode 100644 index 0000000000..dc9de12632 --- /dev/null +++ b/java/sca/modules/implementation-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.implementation.java.JavaImplementationFactory @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory
diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractProcessorTest.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractProcessorTest.java new file mode 100644 index 0000000000..fe93424d28 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractProcessorTest.java @@ -0,0 +1,76 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Constructor; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; + + +/** + * Base class to simulate the processor sequences + * + * @version $Rev$ $Date$ + */ +public class AbstractProcessorTest extends TestCase { + protected AssemblyFactory factory; + protected JavaInterfaceFactory javaFactory; + protected ConstructorProcessor constructorProcessor; + private ReferenceProcessor referenceProcessor; + private PropertyProcessor propertyProcessor; + private ResourceProcessor resourceProcessor; + + + protected AbstractProcessorTest() { + factory = new DefaultAssemblyFactory(); + javaFactory = new DefaultJavaInterfaceFactory(); + referenceProcessor = new ReferenceProcessor(factory, javaFactory); + propertyProcessor = new PropertyProcessor(factory); + resourceProcessor = new ResourceProcessor(factory); + constructorProcessor = new ConstructorProcessor(factory); + referenceProcessor = new ReferenceProcessor(factory, javaFactory); + propertyProcessor = new PropertyProcessor(factory); + } + + protected <T> void visitConstructor(Constructor<T> constructor, + JavaImplementation type) throws IntrospectionException { + constructorProcessor.visitConstructor(constructor, type); + JavaConstructorImpl<?> definition = type.getConstructor(); + if (definition == null) { + definition = new JavaConstructorImpl<T>(constructor); + type.getConstructors().put(constructor, definition); + } + JavaParameterImpl[] parameters = definition.getParameters(); + for (int i = 0; i < parameters.length; i++) { + referenceProcessor.visitConstructorParameter(parameters[i], type); + propertyProcessor.visitConstructorParameter(parameters[i], type); + resourceProcessor.visitConstructorParameter(parameters[i], type); + // monitorProcessor.visitConstructorParameter(parameters[i], type); + } + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessorTestCase.java new file mode 100644 index 0000000000..5beb31f0f9 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessorTestCase.java @@ -0,0 +1,169 @@ +/* + * 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.java.introspect.impl; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getProperty; + +import java.lang.annotation.Retention; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; + + +/** + * @version $Rev$ $Date$ + */ +public class AbstractPropertyProcessorTestCase extends TestCase { + + private JavaClassVisitor extension; + private JavaImplementationFactory javaImplementationFactory; + + public void testVisitMethod() throws Exception { + Method method = Foo.class.getMethod("setBar", String.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + extension.visitMethod(method, type); + Property prop = getProperty(type, "test"); + assertNotNull(prop); + } + + public void testVisitNoParamsMethod() throws Exception { + Method method = Foo.class.getMethod("setNoParamsBar"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + extension.visitMethod(method, type); + fail(); + } catch (IllegalPropertyException e) { + // expected + } + } + + public void testVisitNonVoidMethod() throws Exception { + Method method = Foo.class.getMethod("setBadBar", String.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + extension.visitMethod(method, type); + fail(); + } catch (IllegalPropertyException e) { + // expected + } + } + + public void testDuplicateMethod() throws Exception { + Method method = Foo.class.getMethod("setBar", String.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + extension.visitMethod(method, type); + try { + extension.visitMethod(method, type); + fail(); + } catch (DuplicatePropertyException e) { + // expected + } + } + + public void testVisitField() throws Exception { + Field field = Foo.class.getDeclaredField("d"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + extension.visitField(field, type); + Property prop = getProperty(type, "test"); + assertNotNull(prop); + } + + public void testVisitConstructor() throws Exception { + Constructor<Foo> ctor = Foo.class.getConstructor(String.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + JavaConstructorImpl<Foo> def = new JavaConstructorImpl<Foo>(ctor); + JavaParameterImpl parameter = def.getParameters()[0]; + extension.visitConstructorParameter(parameter, type); + assertEquals("test", def.getParameters()[0].getName()); + assertNotNull(getProperty(type, "test")); + } + + @Override + @SuppressWarnings("unchecked") + protected void setUp() throws Exception { + super.setUp(); + extension = new TestProcessor(); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + } + + @Retention(RUNTIME) + private @interface Bar { + + } + + private class TestProcessor extends AbstractPropertyProcessor<Bar> { + + public TestProcessor() { + super(new DefaultAssemblyFactory(), Bar.class); + } + + @Override + @SuppressWarnings("unchecked") + protected void initProperty(Property property, Bar annotation) { + // property.setDefaultValueFactory(EasyMock.createMock(ObjectFactory.class)); + property.setName("test"); + } + + @Override + protected String getName(Bar annotation) { + return "test"; + } + } + + private static class Foo { + + @Bar + protected String d; + + public Foo(String a, @Bar + String b) { + } + + public Foo(@Bar + String d) { + this.d = d; + } + + @Bar + public void setBar(String d) { + this.d = d; + } + + @Bar + public void setNoParamsBar() { + } + + @Bar + public String setBadBar(String d) { + return null; + } + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessorTestCase.java new file mode 100644 index 0000000000..e5abb07760 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessorTestCase.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.annotations.AllowsPassByReference; + +/** + * @version $Rev$ $Date$ + */ +public class AllowsPassByReferenceProcessorTestCase extends TestCase { + + JavaImplementation type; + AllowsPassByReferenceProcessor processor; + private JavaImplementationFactory javaImplementationFactory; + + public void testClassAnnotation() throws Exception { + processor.visitClass(Foo.class, type); + assertEquals(true, type.isAllowsPassByReference()); + + processor.visitClass(Bar.class, type); + assertEquals(false, type.isAllowsPassByReference()); + + Method m1 = Bar.class.getMethod("m1", new Class[] {}); + processor.visitMethod(m1, type); + assertTrue(type.isAllowsPassByReference(m1)); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + type = javaImplementationFactory.createJavaImplementation(); + processor = new AllowsPassByReferenceProcessor(new DefaultAssemblyFactory()); + } + + @AllowsPassByReference + private class Foo { + } + + // no annotation + private class Bar { + @AllowsPassByReference + public void m1() { + + } + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessorTestCase.java new file mode 100644 index 0000000000..fa1527fbe5 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessorTestCase.java @@ -0,0 +1,192 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getProperty; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getReference; + +import java.lang.reflect.Constructor; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Reference; + +/** + * @version $Rev$ $Date$ + */ +public class ConstructorProcessorTestCase extends TestCase { + private ConstructorProcessor processor = new ConstructorProcessor(new DefaultAssemblyFactory()); + + private JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + + public void testDuplicateConstructor() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + processor.visitClass(BadFoo.class, type); + fail(); + } catch (DuplicateConstructorException e) { + // expected + } + } + + public void testConstructorAnnotation() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor1 = Foo.class.getConstructor(String.class); + processor.visitConstructor(ctor1, type); + assertEquals("foo", type.getConstructor().getParameters()[0].getName()); + } + + public void testNoAnnotation() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<NoAnnotation> ctor1 = NoAnnotation.class.getConstructor(); + processor.visitConstructor(ctor1, type); + assertNull(type.getConstructor()); + } + + public void testBadAnnotation() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadAnnotation> ctor1 = BadAnnotation.class.getConstructor(String.class, Foo.class); + try { + processor.visitConstructor(ctor1, type); + fail(); + } catch (InvalidConstructorException e) { + // expected + } + } + + public void testMixedParameters() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Mixed> ctor1 = Mixed.class.getConstructor(String.class, String.class, String.class); + processor.visitConstructor(ctor1, type); + + AssemblyFactory assemblyFactory = new DefaultAssemblyFactory(); + JavaInterfaceFactory javaFactory = new DefaultJavaInterfaceFactory(); + ReferenceProcessor referenceProcessor = new ReferenceProcessor(assemblyFactory, javaFactory); + PropertyProcessor propertyProcessor = new PropertyProcessor(assemblyFactory); + JavaParameterImpl[] parameters = type.getConstructor().getParameters(); + for (int i = 0; i < parameters.length; i++) { + referenceProcessor.visitConstructorParameter(parameters[i], type); + propertyProcessor.visitConstructorParameter(parameters[i], type); + } + + assertEquals("_ref0", parameters[0].getName()); + assertEquals("foo", parameters[1].getName()); + assertEquals("bar", parameters[2].getName()); + } + + private static class BadFoo { + + @org.osoa.sca.annotations.Constructor("foo") + public BadFoo(String foo) { + + } + + @org.osoa.sca.annotations.Constructor( {"foo", "bar"}) + public BadFoo(String foo, String bar) { + + } + } + + private static class Foo { + @org.osoa.sca.annotations.Constructor("foo") + public Foo(String foo) { + + } + } + + private static class NoAnnotation { + public NoAnnotation() { + } + } + + private static class BadAnnotation { + @org.osoa.sca.annotations.Constructor("foo") + public BadAnnotation(String foo, Foo ref) { + } + } + + public static final class Mixed { + @org.osoa.sca.annotations.Constructor + public Mixed(@Reference + String param1, @Property(name = "foo") + String param2, @Reference(name = "bar") + String param3) { + } + } + + public static final class Multiple { + @org.osoa.sca.annotations.Constructor + public Multiple(@Reference + Collection<String> param1, @Property(name = "foo") + String[] param2, @Reference(name = "bar", required = true) + List<String> param3, @Property(name = "abc") + Set<String> param4, @Reference(name = "xyz") + String[] param5) { + } + } + + public void testMultiplicity() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Multiple> ctor1 = Multiple.class.getConstructor(Collection.class, + String[].class, + List.class, + Set.class, + String[].class); + processor.visitConstructor(ctor1, type); + AssemblyFactory assemblyFactory = new DefaultAssemblyFactory(); + JavaInterfaceFactory javaFactory = new DefaultJavaInterfaceFactory(); + ReferenceProcessor referenceProcessor = new ReferenceProcessor(assemblyFactory, javaFactory); + PropertyProcessor propertyProcessor = new PropertyProcessor(assemblyFactory); + JavaParameterImpl[] parameters = type.getConstructor().getParameters(); + for (int i = 0; i < parameters.length; i++) { + referenceProcessor.visitConstructorParameter(parameters[i], type); + propertyProcessor.visitConstructorParameter(parameters[i], type); + } + + org.apache.tuscany.sca.assembly.Reference ref0 = getReference(type, "_ref0"); + assertNotNull(ref0); + assertEquals(Multiplicity.ONE_N, ref0.getMultiplicity()); + org.apache.tuscany.sca.assembly.Reference ref1 = getReference(type, "bar"); + assertNotNull(ref1); + assertEquals(Multiplicity.ONE_N, ref1.getMultiplicity()); + org.apache.tuscany.sca.assembly.Reference ref2 = getReference(type, "xyz"); + assertNotNull(ref2); + assertEquals(Multiplicity.ONE_N, ref2.getMultiplicity()); + org.apache.tuscany.sca.assembly.Property prop1 = getProperty(type, "foo"); + assertNotNull(prop1); + assertTrue(prop1.isMany()); + org.apache.tuscany.sca.assembly.Property prop2 = getProperty(type, "abc"); + assertNotNull(prop2); + assertTrue(prop2.isMany()); + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorPropertyTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorPropertyTestCase.java new file mode 100644 index 0000000000..690869ccb8 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorPropertyTestCase.java @@ -0,0 +1,157 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getProperty; + +import java.lang.reflect.Constructor; +import java.util.List; + +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.annotations.Property; + +/** + * @version $Rev$ $Date$ + */ +public class ConstructorPropertyTestCase extends AbstractProcessorTest { + + private JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + + public void testProperty() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(String.class); + visitConstructor(ctor, type); + org.apache.tuscany.sca.assembly.Property property = getProperty(type, "myProp"); + assertTrue(property.isMustSupply()); + assertEquals("myProp", property.getName()); + } + + public void testTwoPropertiesSameType() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(String.class, String.class); + visitConstructor(ctor, type); + assertNotNull(getProperty(type, "myProp1")); + assertNotNull(getProperty(type, "myProp2")); + } + + public void testDuplicateProperty() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadFoo> ctor = BadFoo.class.getConstructor(String.class, String.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (DuplicatePropertyException e) { + // expected + } + } + + public void testNoName() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadFoo> ctor = BadFoo.class.getConstructor(String.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (InvalidPropertyException e) { + // expected + } + } + + public void testNamesOnConstructor() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(Integer.class); + visitConstructor(ctor, type); + assertNotNull(getProperty(type, "myProp")); + } + + public void testInvalidNumberOfNames() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadFoo> ctor = BadFoo.class.getConstructor(Integer.class, Integer.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (InvalidConstructorException e) { + // expected + } + } + + public void testNoMatchingNames() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadFoo> ctor = BadFoo.class.getConstructor(List.class, List.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (InvalidConstructorException e) { + // expected + } + } + +// public void testMultiplicityRequired() throws Exception { + // TODO multiplicity +// } + + private static class Foo { + + @org.osoa.sca.annotations.Constructor() + public Foo(@Property(name = "myProp", required = true)String prop) { + + } + + @org.osoa.sca.annotations.Constructor("myProp") + public Foo(@Property Integer prop) { + + } + + @org.osoa.sca.annotations.Constructor() + public Foo(@Property(name = "myProp1")String prop1, @Property(name = "myProp2")String prop2) { + + } + + @org.osoa.sca.annotations.Constructor() + public Foo(@Property List prop) { + + } + } + + private static class BadFoo { + + @org.osoa.sca.annotations.Constructor() + public BadFoo(@Property(name = "myProp")String prop1, @Property(name = "myProp")String prop2) { + + } + + @org.osoa.sca.annotations.Constructor() + public BadFoo(@Property String prop) { + + } + + @org.osoa.sca.annotations.Constructor("myProp") + public BadFoo(@Property Integer prop, @Property Integer prop2) { + + } + + @org.osoa.sca.annotations.Constructor({"myRef", "myRef2"}) + public BadFoo(@Property List ref, @Property(name = "myOtherRef")List ref2) { + + } + + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorReferenceTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorReferenceTestCase.java new file mode 100644 index 0000000000..8c10df2146 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorReferenceTestCase.java @@ -0,0 +1,167 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getReference; + +import java.lang.reflect.Constructor; +import java.util.List; + +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.annotations.Reference; + +/** + * @version $Rev$ $Date$ + */ +public class ConstructorReferenceTestCase extends AbstractProcessorTest { + + private JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + + public void testReference() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(String.class); + visitConstructor(ctor, type); + org.apache.tuscany.sca.assembly.Reference reference = getReference(type, "myRef"); + assertEquals(Multiplicity.ONE_ONE, reference.getMultiplicity()); + assertEquals("myRef", reference.getName()); + } + + public void testTwoReferencesSameType() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(String.class, String.class); + visitConstructor(ctor, type); + assertNotNull(getReference(type, "myRef1")); + assertNotNull(getReference(type, "myRef2")); + } + + public void testDuplicateProperty() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadFoo> ctor = BadFoo.class.getConstructor(String.class, String.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (DuplicateReferenceException e) { + // expected + } + } + + public void testNoName() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<NoNameFoo> ctor = NoNameFoo.class.getConstructor(String.class); + visitConstructor(ctor, type); + assertNotNull(getReference(type, "_ref0")); + } + + public void testNamesOnConstructor() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(Integer.class); + visitConstructor(ctor, type); + assertNotNull(getReference(type, "myRef")); + } + + public void testInvalidNumberOfNames() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadFoo> ctor = BadFoo.class.getConstructor(Integer.class, Integer.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (InvalidConstructorException e) { + // expected + } + } + + public void testNoMatchingNames() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadFoo> ctor = BadFoo.class.getConstructor(List.class, List.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (InvalidConstructorException e) { + // expected + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + +// public void testMultiplicityRequired() throws Exception { + // TODO multiplicity +// } + + private static class Foo { + + @org.osoa.sca.annotations.Constructor() + public Foo(@Reference(name = "myRef", required = true)String prop) { + + } + + @org.osoa.sca.annotations.Constructor() + public Foo(@Reference(name = "myRef1")String prop1, @Reference(name = "myRef2")String prop2) { + + } + + @org.osoa.sca.annotations.Constructor("myRef") + public Foo(@Reference Integer prop) { + + } + + @org.osoa.sca.annotations.Constructor() + public Foo(@Reference List prop) { + + } + } + + private static class NoNameFoo { + + @org.osoa.sca.annotations.Constructor + public NoNameFoo(@Reference String prop) { + + } + } + + private static class BadFoo { + + @org.osoa.sca.annotations.Constructor + public BadFoo(@Reference(name = "myRef")String prop1, @Reference(name = "myRef")String prop2) { + + } + + @org.osoa.sca.annotations.Constructor + public BadFoo(@Reference String prop) { + + } + + @org.osoa.sca.annotations.Constructor("myRef") + public BadFoo(@Reference Integer ref, @Reference Integer ref2) { + + } + + @org.osoa.sca.annotations.Constructor({"myRef", "myRef2"}) + public BadFoo(@Reference List ref, @Reference(name = "myOtherRef")List ref2) { + + } + + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorResourceTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorResourceTestCase.java new file mode 100644 index 0000000000..365fb12afe --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorResourceTestCase.java @@ -0,0 +1,152 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Constructor; +import java.util.List; + +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; + +/** + * @version $Rev$ $Date$ + */ +public class ConstructorResourceTestCase extends AbstractProcessorTest { + + private JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + + public void testResource() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(String.class); + visitConstructor(ctor, type); + org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl resource = type.getResources().get("myResource"); + assertFalse(resource.isOptional()); + } + + public void testTwoResourcesSameType() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(String.class, String.class); + visitConstructor(ctor, type); + assertNotNull(type.getResources().get("myResource1")); + assertNotNull(type.getResources().get("myResource2")); + } + + public void testDuplicateResource() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<BadFoo> ctor = BadFoo.class.getConstructor(String.class, String.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (DuplicateResourceException e) { + // expected + } + } + + public void testNoName() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<ConstructorResourceTestCase.BadFoo> ctor = + ConstructorResourceTestCase.BadFoo.class.getConstructor(String.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (InvalidResourceException e) { + // expected + } + } + + public void testNamesOnConstructor() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(Integer.class); + visitConstructor(ctor, type); + assertNotNull(type.getResources().get("myResource")); + } + + public void testInvalidNumberOfNames() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<ConstructorResourceTestCase.BadFoo> ctor = + ConstructorResourceTestCase.BadFoo.class.getConstructor(Integer.class, Integer.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (InvalidConstructorException e) { + // expected + } + } + + public void testNoMatchingNames() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<ConstructorResourceTestCase.BadFoo> ctor = + ConstructorResourceTestCase.BadFoo.class.getConstructor(List.class, List.class); + try { + visitConstructor(ctor, type); + fail(); + } catch (InvalidConstructorException e) { + // expected + } + } + + private static class Foo { + + @org.osoa.sca.annotations.Constructor + public Foo(@Resource(name = "myResource") String resource) { + + } + + @org.osoa.sca.annotations.Constructor("myResource") + public Foo(@Resource Integer resource) { + + } + + @org.osoa.sca.annotations.Constructor + public Foo(@Resource(name = "myResource1") String res1, @Resource(name = "myResource2") String res2) { + + } + + @org.osoa.sca.annotations.Constructor + public Foo(@Resource List res) { + + } + } + + private static class BadFoo { + + @org.osoa.sca.annotations.Constructor + public BadFoo(@Resource(name = "myResource") String res1, @Resource(name = "myResource") String res2) { + + } + + @org.osoa.sca.annotations.Constructor + public BadFoo(@Resource String res) { + + } + + @org.osoa.sca.annotations.Constructor("myProp") + public BadFoo(@Resource Integer res, @Resource Integer res2) { + + } + + @org.osoa.sca.annotations.Constructor({"myRes", "myRes2"}) + public BadFoo(@Resource List res, @Resource(name = "myOtherRes") List res2) { + + } + + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessorTestCase.java new file mode 100644 index 0000000000..f77c9abad9 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessorTestCase.java @@ -0,0 +1,201 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.ComponentContext; +import org.osoa.sca.RequestContext; +import org.osoa.sca.annotations.ComponentName; +import org.osoa.sca.annotations.Context; + +/** + * @version $Rev$ $Date$ + */ +public class ContextProcessorTestCase extends TestCase { + private ContextProcessor processor; + private ComponentNameProcessor nameProcessor; + private JavaImplementationFactory javaImplementationFactory; + + public void testComponentContextMethod() throws Exception { + Method method = Foo.class.getMethod("setContext", ComponentContext.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitMethod(method, type); + assertNotNull(type.getResources().get("context")); + } + + public void testComponentContextField() throws Exception { + Field field = Foo.class.getDeclaredField("context"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitField(field, type); + assertNotNull(type.getResources().get("context")); + } + + public void testRequestContextMethod() throws Exception { + Method method = Foo.class.getMethod("setRequestContext", RequestContext.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitMethod(method, type); + assertNotNull(type.getResources().get("requestContext")); + } + + public void testRequestContextField() throws Exception { + Field field = Foo.class.getDeclaredField("requestContext"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitField(field, type); + assertNotNull(type.getResources().get("requestContext")); + } + + public void testComponentNameMethod() throws Exception { + Method method = Foo.class.getMethod("setName", String.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + nameProcessor.visitMethod(method, type); + assertNotNull(type.getResources().get("name")); + } + + public void testComponentNameField() throws Exception { + Field field = Foo.class.getDeclaredField("name"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + nameProcessor.visitField(field, type); + assertNotNull(type.getResources().get("name")); + } + + public void testInvalidParamType() throws Exception { + Method method = Foo.class.getMethod("setContext", String.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + processor.visitMethod(method, type); + fail(); + } catch (UnknownContextTypeException e) { + // expected + } + } + + public void testInvalidParamTypeField() throws Exception { + Field field = Foo.class.getDeclaredField("badContext"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + processor.visitField(field, type); + fail(); + } catch (UnknownContextTypeException e) { + // expected + } + } + + + public void testInvalidParamNum() throws Exception { + Method method = Foo.class.getMethod("setContext", ComponentContext.class, String.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalContextException e) { + // expected + } + } + + public void testInvalidNoParams() throws Exception { + Method method = Foo.class.getMethod("setContext"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalContextException e) { + // expected + } + } + + public void testNoContext() throws Exception { + Method method = Foo.class.getMethod("noContext", ComponentContext.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitMethod(method, type); + assertEquals(0, type.getResources().size()); + } + + public void testNoContextField() throws Exception { + Field field = Foo.class.getDeclaredField("noContext"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitField(field, type); + assertEquals(0, type.getResources().size()); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + processor = new ContextProcessor(new DefaultAssemblyFactory()); + nameProcessor = new ComponentNameProcessor(new DefaultAssemblyFactory()); + } + + private class Foo { + @Context + protected ComponentContext context; + + @ComponentName + protected String name; + + @Context + protected Object badContext; + + protected ComponentContext noContext; + + @Context + protected RequestContext requestContext; + + @Context + public void setContext(ComponentContext context) { + + } + + @ComponentName + public void setName(String name) { + + } + + @Context + public void setContext(String context) { + + } + + @Context + public void setContext(ComponentContext context, String string) { + + } + + @Context + public void setContext() { + + } + + public void noContext(ComponentContext context) { + + } + + @Context + public void setRequestContext(RequestContext requestContext) { + this.requestContext = requestContext; + } + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationIDProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationIDProcessorTestCase.java new file mode 100644 index 0000000000..c6b2626e9c --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationIDProcessorTestCase.java @@ -0,0 +1,94 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.annotations.ConversationID; + +/** + * Test the ConversationIDProcessor + * + * @version $Rev$ $Date$ + */ +public class ConversationIDProcessorTestCase extends TestCase { + private ConversationIDProcessor processor; + private JavaImplementationFactory javaImplementationFactory; + + public void testConversationIDMethod() throws Exception { + Method method = Foo.class.getMethod("setConversationID", String.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitMethod(method, type); + assertNotNull(type.getResources().get("conversationID")); + } + + public void testConversationIDField() throws Exception { + Field field = Foo.class.getDeclaredField("cid"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitField(field, type); + assertNotNull(type.getResources().get("cid")); + } + + public void testConversationIDMethodNotString() throws Exception { + Method method = Foo.class.getMethod("setConversationID", Long.class); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitMethod(method, type); + assertNotNull(type.getResources().get("conversationID")); + } + + public void testConversationIDFieldNotString() throws Exception { + Field field = Foo.class.getDeclaredField("longCID"); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitField(field, type); + assertNotNull(type.getResources().get("longCID")); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + processor = new ConversationIDProcessor(new DefaultAssemblyFactory()); + } + + private class Foo { + + @ConversationID + protected String cid; + + @ConversationID + public void setConversationID(String cid) { + + } + + @ConversationID + protected Long longCID; + + @ConversationID + public void setConversationID(Long cid) { + + } + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationProcessorTestCase.java new file mode 100644 index 0000000000..4555736813 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConversationProcessorTestCase.java @@ -0,0 +1,144 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.annotations.ConversationAttributes; +import org.osoa.sca.annotations.ConversationID; +import org.osoa.sca.annotations.Scope; + +/** + * @version $Rev$ $Date$ + */ +public class ConversationProcessorTestCase extends TestCase { + private ConversationProcessor processor = new ConversationProcessor(new DefaultAssemblyFactory()); + private JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + + public void testMaxIdleTime() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(FooMaxIdle.class, type); + assertEquals(10000L, type.getMaxIdleTime()); + assertEquals(-1, type.getMaxAge()); + } + + public void testMaxAge() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(FooMaxAge.class, type); + assertEquals(10000L, type.getMaxAge()); + assertEquals(-1, type.getMaxIdleTime()); + } + + public void testImplicitScope() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(ImplicitFooScope.class, type); + assertEquals(org.apache.tuscany.sca.implementation.java.impl.JavaScopeImpl.CONVERSATION, type.getJavaScope()); + } + + /* TUSCANY-1999 - apply conversation properties to all scopes + public void testBadFooScope() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + processor.visitClass(BadFooScope.class, type); + fail(); + } catch (InvalidConversationalImplementation e) { + // expected + } + } + */ + + public void testBadFooBoth() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(BadFooBoth.class, type); + assertEquals(10000L, type.getMaxAge()); + assertEquals(10000L, type.getMaxIdleTime()); + } + + public void testJustConversation() throws Exception { + // TODO do we want these semantics + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(FooJustConversation.class, type); + assertEquals(org.apache.tuscany.sca.implementation.java.impl.JavaScopeImpl.CONVERSATION, type.getJavaScope()); + assertEquals(-1, type.getMaxAge()); + assertEquals(-1, type.getMaxIdleTime()); + } + + public void testSetConversationIDField() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Field field = FooWithConversationIDField.class.getDeclaredField("conversationID"); + processor.visitField(field, type); + assertNotNull(type.getConversationIDMembers()); + assertEquals(field, type.getConversationIDMembers().get(0)); + } + + public void testSetConversationIDMethod() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = FooWithConversationIDMethod.class.getDeclaredMethods()[0]; + processor.visitMethod(method, type); + assertNotNull(type.getConversationIDMembers()); + assertEquals(method, type.getConversationIDMembers().get(0)); + } + + @Scope("CONVERSATION") + @ConversationAttributes(maxIdleTime = "10 seconds") + private class FooMaxIdle { + } + + @Scope("CONVERSATION") + @ConversationAttributes(maxAge = "10 seconds") + private class FooMaxAge { + } + + @Scope("CONVERSATION") + @ConversationAttributes(maxAge = "10 seconds", maxIdleTime = "10 seconds") + private class BadFooBoth { + } + + @ConversationAttributes(maxAge = "10 seconds") + private class ImplicitFooScope { + } + + @Scope("STATELESS") + @ConversationAttributes(maxAge = "10 seconds") + private class BadFooScope { + } + + @ConversationAttributes + private class FooJustConversation { + } + + private class FooWithConversationIDField { + + @ConversationID + String conversationID; + } + + private class FooWithConversationIDMethod { + @ConversationID + void setConversationID(String conversationID) { + } + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConvertTimeMillisTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConvertTimeMillisTestCase.java new file mode 100644 index 0000000000..aa2671071c --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConvertTimeMillisTestCase.java @@ -0,0 +1,117 @@ +/* + * 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.java.introspect.impl; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; + +/** + * @version $Rev$ $Date$ + */ +public class ConvertTimeMillisTestCase extends TestCase { + private MockProcessor registy; + + public void testConvertSeconds() throws Exception { + assertEquals(10000L, registy.convertTimeMillis("10 seconds")); + assertEquals(10000L, registy.convertTimeMillis("10 SECONDS")); + try { + registy.convertTimeMillis("10seconds"); + fail(); + } catch (NumberFormatException e) { + // expected + } + } + + public void testConvertMinutes() throws Exception { + assertEquals(600000L, registy.convertTimeMillis("10 minutes")); + assertEquals(600000L, registy.convertTimeMillis("10 MINUTES")); + try { + registy.convertTimeMillis("10minutes"); + fail(); + } catch (NumberFormatException e) { + // expected + } + } + + public void testConvertHours() throws Exception { + assertEquals(36000000L, registy.convertTimeMillis("10 hours")); + assertEquals(36000000L, registy.convertTimeMillis("10 HOURS")); + try { + registy.convertTimeMillis("10hours"); + fail(); + } catch (NumberFormatException e) { + // expected + } + } + + public void testConvertDays() throws Exception { + assertEquals(864000000L, registy.convertTimeMillis("10 days")); + assertEquals(864000000L, registy.convertTimeMillis("10 DAYS")); + try { + registy.convertTimeMillis("10days"); + fail(); + } catch (NumberFormatException e) { + // expected + } + } + + public void testConvertYears() throws Exception { + assertEquals(315569260000L, registy.convertTimeMillis("10 years")); + assertEquals(315569260000L, registy.convertTimeMillis("10 YEARS")); + try { + registy.convertTimeMillis("10years"); + fail(); + } catch (NumberFormatException e) { + // expected + } + } + + public void testConvertDefault() throws Exception { + assertEquals(10000L, registy.convertTimeMillis("10 ")); + assertEquals(10000L, registy.convertTimeMillis("10")); + } + + public void testInvalid() throws Exception { + try { + registy.convertTimeMillis("foo"); + fail(); + } catch (NumberFormatException e) { + // expected + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + registy = new MockProcessor(); + } + + private class MockProcessor extends ConversationProcessor { + + public MockProcessor() { + super(new DefaultAssemblyFactory()); + } + + @Override + protected long convertTimeMillis(String expr) throws NumberFormatException { + return super.convertTimeMillis(expr); + } + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessorTestCase.java new file mode 100644 index 0000000000..ffc67325fa --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessorTestCase.java @@ -0,0 +1,129 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.annotations.Destroy; + +/** + * @version $Rev$ $Date$ + */ +public class DestroyProcessorTestCase extends TestCase { + + private AssemblyFactory assemblyFactory = new DefaultAssemblyFactory(); + private JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + + public void testDestroy() throws Exception { + DestroyProcessor processor = new DestroyProcessor(assemblyFactory); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = Foo.class.getMethod("destroy"); + processor.visitMethod(method, type); + assertNotNull(type.getDestroyMethod()); + } + + public void testBadDestroy() throws Exception { + DestroyProcessor processor = new DestroyProcessor(assemblyFactory); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = Bar.class.getMethod("badDestroy", String.class); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalDestructorException e) { + // expected + } + } + + public void testTwoDestroy() throws Exception { + DestroyProcessor processor = new DestroyProcessor(assemblyFactory); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = Bar.class.getMethod("destroy"); + Method method2 = Bar.class.getMethod("destroy2"); + processor.visitMethod(method, type); + try { + processor.visitMethod(method2, type); + fail(); + } catch (DuplicateDestructorException e) { + // expected + } + } + + public void testProtectedDestroy() throws Exception { + DestroyProcessor processor = new DestroyProcessor(assemblyFactory); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = Bar.class.getDeclaredMethod("protectedDestroy"); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalDestructorException e) { + // expected + } + } + + public void testPrivateDestroy() throws Exception { + DestroyProcessor processor = new DestroyProcessor(assemblyFactory); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = Bar.class.getDeclaredMethod("privateDestroy"); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalDestructorException e) { + // expected + } + } + + private class Foo { + + @Destroy + public void destroy() { + } + } + + + private class Bar { + + @Destroy + public void destroy() { + } + + @Destroy + public void destroy2() { + } + + @Destroy + public void badDestroy(String foo) { + } + + @Destroy + protected void protectedDestroy(){ + } + + @Destroy + private void privateDestroy(){ + } + + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessorTestCase.java new file mode 100644 index 0000000000..09bcc7ab6c --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessorTestCase.java @@ -0,0 +1,59 @@ +/* + * 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.java.introspect.impl; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.annotations.EagerInit; + +/** + * @version $Rev$ $Date$ + */ +public class EagerInitProcessorTestCase extends TestCase { + + private AssemblyFactory assemblyFactory = new DefaultAssemblyFactory(); + private JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + + public void testNoLevel() throws IntrospectionException { + EagerInitProcessor processor = new EagerInitProcessor(assemblyFactory); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(Level.class, type); + } + + public void testSubclass() throws IntrospectionException { + EagerInitProcessor processor = new EagerInitProcessor(assemblyFactory); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(SubClass.class, type); + } + + @EagerInit + private class Level { + } + + private class SubClass extends Level { + + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicAndPropertyTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicAndPropertyTestCase.java new file mode 100644 index 0000000000..c7f340bd46 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicAndPropertyTestCase.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import java.lang.reflect.Constructor; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.osoa.sca.annotations.Property; + +/** + * @version $Rev$ $Date$ + */ +public class HeuristicAndPropertyTestCase extends TestCase { + + private PropertyProcessor propertyProcessor; + private HeuristicPojoProcessor heuristicProcessor; + private AssemblyFactory assemblyFactory = new DefaultAssemblyFactory(); + private JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + + /** + * Verifies the property and heuristic processors don't collide + */ + @SuppressWarnings("unchecked") + public void testPropertyProcessorWithHeuristicProcessor() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor ctor = Foo.class.getConstructor(String.class); + type.setConstructor(new JavaConstructorImpl(ctor)); + propertyProcessor.visitConstructorParameter(type.getConstructor().getParameters()[0], type); + heuristicProcessor.visitEnd(Foo.class, type); + assertEquals(1, type.getProperties().size()); + assertEquals("foo", type.getProperties().get(0).getName()); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + propertyProcessor = new PropertyProcessor(assemblyFactory); + heuristicProcessor = new HeuristicPojoProcessor(assemblyFactory, new DefaultJavaInterfaceFactory()); + } + + public static class Foo { + public Foo(@Property(name = "foo") + String prop) { + } + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicConstructorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicConstructorTestCase.java new file mode 100644 index 0000000000..e98a8fec1f --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicConstructorTestCase.java @@ -0,0 +1,310 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getProperty; + +import java.lang.reflect.Constructor; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Reference; +import org.osoa.sca.annotations.Remotable; + +/** + * @version $Rev$ $Date$ + */ +public class HeuristicConstructorTestCase extends AbstractProcessorTest { + + private AssemblyFactory factory; + private JavaInterfaceFactory javaFactory; + private HeuristicPojoProcessor processor; + private JavaImplementationFactory javaImplementationFactory; + + public HeuristicConstructorTestCase() { + factory = new DefaultAssemblyFactory(); + javaFactory = new DefaultJavaInterfaceFactory(); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + processor = new HeuristicPojoProcessor(factory, javaFactory); + } + + private <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + for (Constructor<?> constructor : clazz.getConstructors()) { + visitConstructor(constructor, type); + } + processor.visitEnd(clazz, type); + } + + /** + * Verifies a single constructor is chosen with a parameter as the type + */ + public void testSingleConstructorWithParam() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + org.apache.tuscany.sca.assembly.Property prop = factory.createProperty(); + prop.setName("foo"); + type.getProperties().add(prop); + // Hack to add a property member + JavaElementImpl element = new JavaElementImpl("foo", String.class, null); + type.getPropertyMembers().put("foo", element); + visitEnd(Foo1.class, type); + assertNotNull(type.getConstructor().getConstructor()); + assertEquals("foo", type.getConstructor().getParameters()[0].getName()); + } + + /** + * Verifies a single constructor is chosen with a reference as the type + */ + public void testSingleConstructorWithRef() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + org.apache.tuscany.sca.assembly.Reference ref = factory.createReference(); + ref.setName("foo"); + type.getReferences().add(ref); + type.getReferenceMembers().put("foo", new JavaElementImpl("foo", String.class, null)); + visitEnd(Foo1.class, type); + assertNotNull(type.getConstructor().getConstructor()); + assertEquals("foo", type.getConstructor().getParameters()[0].getName()); + } + + /** + * Verifies a single constructor is chosen with a property and a reference + * as the type + */ + public void testSingleConstructorWithPropRef() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + + org.apache.tuscany.sca.assembly.Property prop = factory.createProperty(); + prop.setName("foo"); + type.getProperties().add(prop); + // Hack to add a property member + JavaElementImpl element = new JavaElementImpl("foo", String.class, null); + type.getPropertyMembers().put("foo", element); + + org.apache.tuscany.sca.assembly.Reference ref = ModelHelper.createReference(factory, javaFactory, "ref", Foo1.class); + type.getReferences().add(ref); + type.getReferenceMembers().put("ref", new JavaElementImpl("ref", Foo1.class, null)); + visitEnd(Foo2.class, type); + assertNotNull(type.getConstructor().getConstructor()); + assertEquals(2, type.getConstructor().getParameters().length); + } + + public void testSingleConstructorResolvableParam() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(Foo5.class, type); + assertEquals(String.class, type.getPropertyMembers().get("string").getType()); + } + + public void testSingleConstructorResolvableRef() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(Foo6.class, type); + assertTrue(ModelHelper.matches(ModelHelper.getReference(type, "ref"), Ref.class)); + } + + public void testSingleConstructorAmbiguousRef() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + org.apache.tuscany.sca.assembly.Reference ref = ModelHelper.createReference(factory, javaFactory, "ref", Foo1.class); + type.getReferences().add(ref); + type.getReferenceMembers().put("ref", new JavaElementImpl("ref", Foo1.class, null)); + org.apache.tuscany.sca.assembly.Reference ref2 = ModelHelper.createReference(factory, javaFactory, "ref2", Foo1.class); + type.getReferences().add(ref2); + type.getReferenceMembers().put("ref2", new JavaElementImpl("ref2", Foo1.class, null)); + try { + visitEnd(Foo4.class, type); + fail(); + } catch (AmbiguousConstructorException e) { + // expected + } + } + + public void testConstructorPropertyAnnotatedParamsOnly() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(Foo7.class, type); + assertNotNull(getProperty(type, "myProp")); + } + + public void testConstructorReferenceAnnotatedParamsOnly() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(Foo8.class, type); + assertNotNull(ModelHelper.getReference(type, "myRef")); + } + + @SuppressWarnings("unchecked") + public void testDefaultConstructor() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(Foo3.class, type); + assertNotNull(type.getConstructor().getConstructor()); + } + + public void testSameTypesButAnnotated() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(Foo12.class, type); + assertEquals(2, type.getProperties().size()); + assertNotNull(getProperty(type, "prop1")); + assertNotNull(getProperty(type, "prop2")); + } + + /** + * Verifies processing executes with additional extension annotations + */ + public void testRandomAnnotation() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(Foo11.class, type); + assertEquals(1, type.getProperties().size()); + assertNotNull(getProperty(type, "prop1")); + } + + public void testPrivateConstructor() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + visitEnd(Foo14.class, type); + fail(); + } catch (NoConstructorException e) { + // expected + } + } + + public void testMultipleConstructors() throws Exception { + // throw new UnsupportedOperationException("Finish heuristic multiple + // constructors - Foo10"); + } + + public static class Foo1 { + public Foo1(String val) { + } + } + + public static class Foo2 { + public Foo2(String val, Foo1 ref) { + } + } + + public static class Foo3 { + } + + public static class Foo4 { + public Foo4(Foo1 ref) { + } + } + + public static class Prop { + + } + + @Remotable + public static interface Ref { + + } + + public static class Foo5 { + public Foo5(String val) { + } + } + + public static class Foo6 { + public Foo6(Ref ref) { + } + } + + public static class Foo7 { + public Foo7(@Property(name = "myProp") + String prop) { + } + } + + public static class Foo8 { + public Foo8(@Reference(name = "myRef") + String ref) { + } + } + + public static class Foo9 { + public Foo9(@Reference(name = "myRef") + String ref) { + } + } + + public static class Foo10 { + + public Foo10() { + } + + public Foo10(String prop) { + } + + public Foo10(@Property(name = "prop1") + String prop1, @Property(name = "prop2") + String prop2) { + + } + } + + public static class Foo11 { + + public Foo11(@Property(name = "prop1") + String prop, @Baz + String baz) { + } + } + + public static class Foo12 { + + public Foo12(@Property(name = "prop1") + String prop, @Property(name = "prop2") + String baz) { + } + } + + public @interface Baz { + + } + + public static class Foo13 { + public Foo13(@Reference + String foo) { + } + } + + public static final class Foo14 { + private Foo14() { + } + } + + public static final class Foo15 { + public Foo15(@Reference + String param1, @Reference + String param2) { + } + } + + public static final class Foo16 { + public Foo16(@Reference + String param1, @Property(name = "foo") + String param2, @Reference(name = "bar") + String param3) { + } + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessorTestCase.java new file mode 100644 index 0000000000..50a221722f --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessorTestCase.java @@ -0,0 +1,535 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Constructor; +import java.util.Collection; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Reference; +import org.osoa.sca.annotations.Remotable; +import org.osoa.sca.annotations.Service; + +/** + * Verifies component type information is properly introspected from an unadorned + * POJO according to the SCA Java Client and Implementation Model Specification + * + * @version $Rev$ $Date$ + */ +public class HeuristicPojoProcessorTestCase extends AbstractProcessorTest { + + private org.apache.tuscany.sca.implementation.java.introspect.impl.HeuristicPojoProcessor processor; + private JavaImplementationFactory javaImplementationFactory; + + public HeuristicPojoProcessorTestCase() { + processor = new HeuristicPojoProcessor(new DefaultAssemblyFactory(), new DefaultJavaInterfaceFactory()); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + } + + private <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + for (Constructor<?> constructor : clazz.getConstructors()) { + visitConstructor(constructor, type); + } + processor.visitEnd(clazz, type); + } + + /** + * Verifies a single service interface is computed when only one interface + * is implemented + */ + public void testSingleInterface() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<SingleInterfaceImpl> ctor = SingleInterfaceImpl.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<SingleInterfaceImpl>(ctor)); + processor.visitEnd(SingleInterfaceImpl.class, type); + assertEquals(1, type.getServices().size()); + assertTrue(ModelHelper.matches(ModelHelper.getService(type, PropertyInterface.class.getSimpleName()), + PropertyInterface.class)); + assertTrue(type.getProperties().isEmpty()); + assertTrue(type.getReferences().isEmpty()); + } + + /** + * Verifies property and reference setters are computed + */ + public void testPropertyReference() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<SingleInterfaceWithPropertyReferenceImpl> ctor = SingleInterfaceWithPropertyReferenceImpl.class + .getConstructor(); + type.setConstructor(new JavaConstructorImpl<SingleInterfaceWithPropertyReferenceImpl>(ctor)); + processor.visitEnd(SingleInterfaceWithPropertyReferenceImpl.class, type); + assertEquals(1, type.getServices().size()); + assertTrue(ModelHelper + .matches(ModelHelper.getService(type, Interface1.class.getSimpleName()), Interface1.class)); + assertEquals(1, type.getProperties().size()); + org.apache.tuscany.sca.assembly.Property prop = ModelHelper.getProperty(type, "property"); + assertNotNull(prop); + assertEquals(ComplexProperty.class, type.getPropertyMembers().get("property").getType()); + assertEquals(1, type.getReferences().size()); + assertTrue(ModelHelper.matches(ModelHelper.getReference(type, "reference"), Ref.class)); + } + + /** + * Verifies that a property setter is not introspected if an analogous + * operation is in the service interface + */ + public void testPropertySetterInInterface() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<SingleInterfaceImpl> ctor = SingleInterfaceImpl.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<SingleInterfaceImpl>(ctor)); + processor.visitEnd(SingleInterfaceImpl.class, type); + assertEquals(0, type.getProperties().size()); + } + + /** + * Verifies that a reference setter is not introspected if an analogous + * operation is in the service interface + */ + public void testReferenceSetterInInterface() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<RefInterfaceImpl> ctor = RefInterfaceImpl.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<RefInterfaceImpl>(ctor)); + processor.visitEnd(RefInterfaceImpl.class, type); + assertEquals(0, type.getReferences().size()); + } + + /** + * Verifies collection generic types or array types are introspected as + * references according to specification rules + */ + public void testReferenceCollectionType() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<ReferenceCollectionImpl> ctor = ReferenceCollectionImpl.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<ReferenceCollectionImpl>(ctor)); + processor.visitEnd(ReferenceCollectionImpl.class, type); + assertEquals(1, type.getProperties().size()); + assertEquals(3, type.getReferences().size()); + } + + /** + * Verifies collection generic types or array types are introspected as + * properties according to specification rules + */ + public void testPropertyCollectionType() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<PropertyCollectionImpl> ctor = PropertyCollectionImpl.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<PropertyCollectionImpl>(ctor)); + processor.visitEnd(PropertyCollectionImpl.class, type); + assertEquals(0, type.getReferences().size()); + assertEquals(4, type.getProperties().size()); + } + + /** + * Verifies references are calculated when the type marked with is + * + * @Remotable + */ + public void testRemotableRef() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<RemotableRefImpl> ctor = RemotableRefImpl.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<RemotableRefImpl>(ctor)); + processor.visitEnd(RemotableRefImpl.class, type); + assertEquals(2, type.getReferences().size()); + assertEquals(0, type.getProperties().size()); + } + + public void testParentInterface() throws IntrospectionException, NoSuchMethodException { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Child> ctor = Child.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<Child>(ctor)); + processor.visitEnd(Child.class, type); + assertNotNull(ModelHelper.getService(type, Interface1.class.getSimpleName())); + } + + /** + * Verifies a service interface is calculated when only props and refs are + * given + */ + public void testExcludedPropertyAndReference() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + org.apache.tuscany.sca.assembly.Reference ref = factory.createReference(); + ref.setName("reference"); + type.getReferences().add(ref); + type.getReferenceMembers().put("reference", new JavaElementImpl("reference", Ref.class, null)); + org.apache.tuscany.sca.assembly.Reference ref2 = factory.createReference(); + ref2.setName("reference2"); + type.getReferences().add(ref2); + type.getReferenceMembers().put("reference2", new JavaElementImpl("reference2", Ref.class, null)); + org.apache.tuscany.sca.assembly.Property prop1 = factory.createProperty(); + prop1.setName("string1"); + type.getProperties().add(prop1); + type.getPropertyMembers().put("string1", new JavaElementImpl("string1", String.class, null)); + org.apache.tuscany.sca.assembly.Property prop2 = factory.createProperty(); + prop2.setName("string2"); + type.getProperties().add(prop2); + type.getPropertyMembers().put("string2", new JavaElementImpl("string2", String.class, null)); + visitEnd(MockService.class, type); + assertEquals(1, type.getServices().size()); + } + + public void testProtectedRemotableRefField() throws IntrospectionException, NoSuchMethodException { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<ProtectedRemotableRefFieldImpl> ctor = ProtectedRemotableRefFieldImpl.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<ProtectedRemotableRefFieldImpl>(ctor)); + processor.visitEnd(ProtectedRemotableRefFieldImpl.class, type); + assertNotNull(ModelHelper.getReference(type, "otherRef")); + } + + public void testProtectedRemotableRefMethod() throws IntrospectionException, NoSuchMethodException { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<ProtectedRemotableRefMethodImpl> ctor = ProtectedRemotableRefMethodImpl.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<ProtectedRemotableRefMethodImpl>(ctor)); + processor.visitEnd(ProtectedRemotableRefMethodImpl.class, type); + assertNotNull(ModelHelper.getReference(type, "otherRef")); + } + + public void testSetDataTypes() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<PropertyIntTypeOnConstructor> ctor = PropertyIntTypeOnConstructor.class.getConstructor(); + type.setConstructor(new JavaConstructorImpl<PropertyIntTypeOnConstructor>(ctor)); + processor.visitEnd(PropertyIntTypeOnConstructor.class, type); + org.apache.tuscany.sca.assembly.Property foo = ModelHelper.getProperty(type, "foo"); + assertEquals(int.class, type.getPropertyMembers().get("foo").getType()); + assertEquals(new QName(JavaXMLMapper.URI_2001_SCHEMA_XSD, "int"), foo.getXSDType()); + } + + /** + * Errata for Java Component Implementation Specification v1.0 corrects the algorithm for determining + * references of an unannotated POJO (section 1.2.7). This test makes sure that the earlier implementation + * is corrected as per the errata. A notable difference is that the interfaces annotated with @Service + * no longer result in references. + */ + public void testUpdatedRule() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(SomeServiceImpl.class, type); + assertEquals(12, type.getReferenceMembers().size()); + assertTrue(type.getReferenceMembers().containsKey("rri1")); + assertTrue(type.getReferenceMembers().containsKey("rri2")); + assertTrue(type.getReferenceMembers().containsKey("rri3")); + assertTrue(type.getReferenceMembers().containsKey("rri4")); + + assertTrue(type.getReferenceMembers().containsKey("rria1")); + assertTrue(type.getReferenceMembers().containsKey("rria2")); + assertTrue(type.getReferenceMembers().containsKey("rria3")); + assertTrue(type.getReferenceMembers().containsKey("rria4")); + + assertTrue(type.getReferenceMembers().containsKey("rric1")); + assertTrue(type.getReferenceMembers().containsKey("rric2")); + assertTrue(type.getReferenceMembers().containsKey("rric3")); + assertTrue(type.getReferenceMembers().containsKey("rric4")); + + assertEquals(16, type.getPropertyMembers().size()); + assertTrue(type.getPropertyMembers().containsKey("pnri1")); + assertTrue(type.getPropertyMembers().containsKey("pnri2")); + assertTrue(type.getPropertyMembers().containsKey("pnri3")); + assertTrue(type.getPropertyMembers().containsKey("pnri4")); + + assertTrue(type.getPropertyMembers().containsKey("pnria1")); + assertTrue(type.getPropertyMembers().containsKey("pnria2")); + assertTrue(type.getPropertyMembers().containsKey("pnria3")); + assertTrue(type.getPropertyMembers().containsKey("pnria4")); + + assertTrue(type.getPropertyMembers().containsKey("pnric1")); + assertTrue(type.getPropertyMembers().containsKey("pnric2")); + assertTrue(type.getPropertyMembers().containsKey("pnric3")); + assertTrue(type.getPropertyMembers().containsKey("pnric4")); + + assertTrue(type.getPropertyMembers().containsKey("gen1")); + assertTrue(type.getPropertyMembers().containsKey("gen2")); + assertTrue(type.getPropertyMembers().containsKey("gen3")); + assertTrue(type.getPropertyMembers().containsKey("gen4")); + } + + @Remotable + private interface ReferenceRemotableInterface { + void operation1(String param1); + } + + @Service + private interface PropertyNonRemotableInterface { + void operation1(String param1); + } + + @Remotable + private interface SomeService { + void serviceOperation1(); + } + + private static class SomeServiceImpl implements SomeService { + + public SomeServiceImpl() { + } + + // References - interface with @Remotable + public void setRri1(ReferenceRemotableInterface rri) { + } + protected void setRri2(ReferenceRemotableInterface rri) { + } + public ReferenceRemotableInterface rri3; + protected ReferenceRemotableInterface rri4; + + // References - array of interface with @Remotable + public void setRria1(ReferenceRemotableInterface[] rri) { + } + protected void setRria2(ReferenceRemotableInterface[] rri) { + } + public ReferenceRemotableInterface[] rria3; + protected ReferenceRemotableInterface[] rria4; + + // References - parametrized Collection of interface with @Remotable + public void setRric1(Collection<ReferenceRemotableInterface> rri) { + } + protected void setRric2(Collection<ReferenceRemotableInterface> rri) { + } + public Collection<ReferenceRemotableInterface> rric3; + protected Collection<ReferenceRemotableInterface> rric4; + + // Properties - interface with @Service and without @Remotable + public void setPnri1(PropertyNonRemotableInterface arg) { + } + protected void setPnri2(PropertyNonRemotableInterface arg) { + } + public PropertyNonRemotableInterface pnri3; + protected PropertyNonRemotableInterface pnri4; + + // Properties - array of interface with @Service and without @Remotable + public void setPnria1(PropertyNonRemotableInterface[] arg) { + } + protected void setPnria2(PropertyNonRemotableInterface[] arg) { + } + public PropertyNonRemotableInterface[] pnria3; + protected PropertyNonRemotableInterface[] pnria4; + + // Properties - parametrized Collection of interface with @Service and without @Remotable + public void setPnric1(Collection<PropertyNonRemotableInterface> arg) { + } + protected void setPnric2(Collection<PropertyNonRemotableInterface> arg) { + } + public Collection<PropertyNonRemotableInterface> pnric3; + protected Collection<PropertyNonRemotableInterface> pnric4; + + // Properties - Non-parametrized Collection + public void setGen1(Collection arg) { + } + protected void setGen2(Collection arg) { + } + public Collection gen3; + protected Collection gen4; + + public void serviceOperation1() { + } + } + + private static class PropertyIntTypeOnConstructor { + protected int foo; + + public PropertyIntTypeOnConstructor() { + } + + public int getFoo() { + return foo; + } + } + + @Remotable + private interface PropertyInterface { + void setString1(String val); + } + + @Remotable + private interface Interface1 { + } + + private static class Parent implements Interface1 { + + } + + private static class Child extends Parent { + public Child() { + } + + } + + private static class SingleInterfaceImpl implements PropertyInterface { + public SingleInterfaceImpl() { + } + + public void setString1(String val) { + } + + } + + private interface HeuristicServiceInterface { + void fooOperation(String ref); + + void setInvalid1(); // No parameter + + void setInvalid2(String str, int i); // More than one parameter + + String setInvalid3(String str); // return should be void + } + + public static class MockService implements PropertyInterface, RefInterface, HeuristicServiceInterface { + + @Property + public void setString1(String val) { + } + + @Property + public void setString2(String val) { + } + + @Reference + public void setReference(Ref ref) { + } + + @Reference + public void setReference2(Ref ref) { + } + + public void fooOperation(String ref) { + + } + + public void setInvalid1() { + } + + public void setInvalid2(String str, int i) { + } + + public String setInvalid3(String str) { + return null; + } + + } + + @Remotable + private interface Ref { + } + + private class ComplexProperty { + } + + private interface RefInterface { + void setReference(Ref ref); + } + + private static class RefInterfaceImpl implements RefInterface { + public RefInterfaceImpl() { + } + + public void setReference(Ref ref) { + } + } + + private static class SingleInterfaceWithPropertyReferenceImpl implements Interface1 { + public SingleInterfaceWithPropertyReferenceImpl() { + } + + public void setReference(Ref ref) { + } + + public void setProperty(ComplexProperty prop) { + } + } + + private static class ReferenceCollectionImpl implements Interface1 { + public ReferenceCollectionImpl() { + } + + public void setCollectionReference(Collection<Ref> ref) { + } + + public void setNonGenericCollectionReference(Collection ref) { + // [rfeng] By the SCA specification, this should be classified as property + } + + public void setListReference(List<Ref> ref) { + } + + public void setArrayReference(Ref[] ref) { + } + } + + private static class PropertyCollectionImpl implements Interface1 { + public PropertyCollectionImpl() { + } + + public void setCollectionProperty(Collection<ComplexProperty> prop) { + } + + public void setCollectionProperty2(Collection<String> prop) { + } + + public void setArrayProperty(ComplexProperty[] prop) { + } + + public void setArrayProperty2(String[] prop) { + } + } + + @Remotable + private interface RemotableRef { + } + + private static class RemotableRefImpl implements Interface1 { + protected RemotableRef otherRef; + + public RemotableRefImpl() { + } + + public void setRef(RemotableRef ref) { + + } + } + + private static class ProtectedRemotableRefFieldImpl implements Interface1 { + protected RemotableRef otherRef; + + public ProtectedRemotableRefFieldImpl() { + } + + public ProtectedRemotableRefFieldImpl(RemotableRef otherRef) { + this.otherRef = otherRef; + } + + } + + private static class ProtectedRemotableRefMethodImpl implements Interface1 { + public ProtectedRemotableRefMethodImpl() { + } + + protected void setOtherRef(RemotableRef otherRef) { + } + + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeutisticExtensibleConstructorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeutisticExtensibleConstructorTestCase.java new file mode 100644 index 0000000000..ed0527d3d7 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeutisticExtensibleConstructorTestCase.java @@ -0,0 +1,148 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Constructor; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; + +/** + * Verifies constructors that have extensible annotation types, i.e. that have + * parameters marked by annotations which are themselves processed by some other + * implementation processor + * + * @version $Rev$ $Date$ + */ +public class HeutisticExtensibleConstructorTestCase extends AbstractProcessorTest { + + private org.apache.tuscany.sca.implementation.java.introspect.impl.HeuristicPojoProcessor processor; + private JavaImplementationFactory javaImplementationFactory; + + public HeutisticExtensibleConstructorTestCase() { + processor = new HeuristicPojoProcessor(new DefaultAssemblyFactory(), new DefaultJavaInterfaceFactory()); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + } + + private <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + for (Constructor<?> constructor : clazz.getConstructors()) { + visitConstructor(constructor, type); + } + processor.visitEnd(clazz, type); + } + + /** + * Verifies heuristic processing can be called prior to an extension + * annotation processors being called. + */ + public void testBarAnnotationProcessedFirst() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo> ctor = Foo.class.getConstructor(String.class, String.class); + JavaConstructorImpl<Foo> definition = new JavaConstructorImpl<Foo>(ctor); + type.setConstructor(definition); + Property property = factory.createProperty(); + property.setName("myBar"); + definition.getParameters()[0].setName("myBar"); + type.getProperties().add(property); + visitEnd(Foo.class, type); + assertEquals(2, type.getProperties().size()); + } + + /** + * Verifies heuristic processing can be called before an extension + * annotation processors is called. <p/> For example, given: + * + * <pre> + * Foo(@Bar String prop, @org.osoa.sca.annotations.Property(name = "foo") String prop2) + * </pre> + * + * <p/> Heuristic evaluation of + * @Property can occur prior to another implementation processor evaluating + * @Bar + * @throws Exception + */ + public void testBarAnnotationProcessedLast() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + visitEnd(Foo.class, type); + + // now simulate process the bar impl + JavaConstructorImpl<?> definition = type.getConstructor(); + definition.getParameters()[0].setName("myBar"); + Property property = factory.createProperty(); + property.setName("myBar"); + type.getProperties().add(property); + + assertEquals(2, type.getProperties().size()); + assertEquals("foo", definition.getParameters()[1].getName()); + } + + /** + * Verifies heuristic processing can be called before an extension + * annotation processors is called with the extension parameter in a middle + * position. Specifically, verifies that the heuristic processor updates + * injection names and preserves their ordering. + */ + public void testBarAnnotationProcessedFirstInMiddle() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Constructor<Foo2> ctor = Foo2.class.getConstructor(String.class, String.class, String.class); + JavaConstructorImpl<Foo2> definition = new JavaConstructorImpl<Foo2>(ctor); + type.setConstructor(definition); + // insert placeholder for first param, which would be done by a + // processor + definition.getParameters()[0].setName(""); + Property property = factory.createProperty(); + // Hack to add a property member + JavaElementImpl element = new JavaElementImpl("myBar", String.class, null); + type.getPropertyMembers().put("myBar", element); + property.setName("myBar"); + definition.getParameters()[1].setName("myBar"); + type.getProperties().add(property); + visitEnd(Foo2.class, type); + assertEquals("baz", definition.getParameters()[0].getName()); + assertEquals(2, type.getProperties().size()); + assertEquals(1, type.getReferences().size()); + } + + public @interface Bar { + + } + + public static class Foo { + public Foo(@Bar + String prop, @org.osoa.sca.annotations.Property(name = "foo") + String prop2) { + } + } + + public static class Foo2 { + public Foo2(@org.osoa.sca.annotations.Reference(name = "baz") + String prop1, @Bar + String prop2, @org.osoa.sca.annotations.Property(name = "foo") + String prop3) { + } + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessorTestCase.java new file mode 100644 index 0000000000..70c615ca24 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessorTestCase.java @@ -0,0 +1,145 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.osoa.sca.annotations.Init; + +/** + * @version $Rev$ $Date$ + */ +public class InitProcessorTestCase extends TestCase { + + private JavaImplementationFactory javaImplementationFactory; + + public InitProcessorTestCase() { + javaImplementationFactory = new DefaultJavaImplementationFactory(); + } + + public void testInit() throws Exception { + InitProcessor processor = new InitProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = InitProcessorTestCase.Foo.class.getMethod("init"); + processor.visitMethod(method, type); + assertNotNull(type.getInitMethod()); + } + + public void testBadInit() throws Exception { + InitProcessor processor = new InitProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = InitProcessorTestCase.Bar.class.getMethod("badInit", String.class); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalInitException e) { + // expected + } + } + + public void testTwoInit() throws Exception { + InitProcessor processor = new InitProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = InitProcessorTestCase.Bar.class.getMethod("init"); + Method method2 = InitProcessorTestCase.Bar.class.getMethod("init2"); + processor.visitMethod(method, type); + try { + processor.visitMethod(method2, type); + fail(); + } catch (DuplicateInitException e) { + // expected + } + } + + public void testProtectedInit() throws Exception { + InitProcessor processor = new InitProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = InitProcessorTestCase.Bar.class.getDeclaredMethod("protectedInit"); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalInitException e) { + // expected + } + } + + public void testPrivateInit() throws Exception { + InitProcessor processor = new InitProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = InitProcessorTestCase.Bar.class.getDeclaredMethod("privateInit"); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalInitException e) { + // expected + } + } + + public void testBadInit2() throws Exception { + InitProcessor processor = new InitProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + Method method = InitProcessorTestCase.Bar.class.getDeclaredMethod("badInit2"); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalInitException e) { + // expected + } + } + + private class Foo { + @Init + public void init() { + } + } + + + private class Bar { + @Init + public void init() { + } + + @Init + public void init2() { + } + + @Init + public void badInit(String foo) { + } + + @Init + public String badInit2() { + return null; + } + + @Init + protected void protectedInit() { + } + + @Init + private void privateInit() { + } + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JavaClassIntrospectorImplTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JavaClassIntrospectorImplTestCase.java new file mode 100644 index 0000000000..388a1aae8b --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JavaClassIntrospectorImplTestCase.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.java.introspect.impl; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; +import org.easymock.EasyMock; + +/** + * @version $Rev$ $Date$ + */ +public class JavaClassIntrospectorImplTestCase extends TestCase { + + public void testRegister() throws Exception { + JavaImplementationFactory factory = new DefaultJavaImplementationFactory(); + JavaClassVisitor extension = EasyMock.createNiceMock(JavaClassVisitor.class); + factory.addClassVisitor(extension); + } + + public void testUnegister() throws Exception { + JavaImplementationFactory factory = new DefaultJavaImplementationFactory(); + JavaClassVisitor extension = EasyMock.createNiceMock(JavaClassVisitor.class); + factory.addClassVisitor(extension); + factory.removeClassVisitor(extension); + } + + @SuppressWarnings("unchecked") + public void testWalk() throws Exception { + JavaImplementationFactory factory = new DefaultJavaImplementationFactory(); + JavaClassVisitor extension = EasyMock.createMock(JavaClassVisitor.class); + extension.visitClass(EasyMock.eq(Bar.class), EasyMock.isA(JavaImplementation.class)); + extension.visitConstructor(EasyMock.isA(Constructor.class), EasyMock.isA(JavaImplementation.class)); + extension.visitMethod(EasyMock.isA(Method.class), EasyMock.isA(JavaImplementation.class)); + extension.visitField(EasyMock.isA(Field.class), EasyMock.isA(JavaImplementation.class)); + extension.visitSuperClass(EasyMock.isA(Class.class), EasyMock.isA(JavaImplementation.class)); + extension.visitEnd(EasyMock.isA(Class.class), EasyMock.isA(JavaImplementation.class)); + + // mock.expects(once()).method("visitClass"); + // mock.expects(once()).method("visitMethod"); + // mock.expects(once()).method("visitField"); + // mock.expects(once()).method("visitConstructor"); + // mock.expects(once()).method("visitSuperClass"); + // mock.expects(once()).method("visitEnd"); + EasyMock.replay(extension); + factory.addClassVisitor(extension); + factory.createJavaImplementation(Bar.class); + EasyMock.verify(extension); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + private class Baz { + + } + + private class Bar extends Baz { + + protected String bar; + + public Bar() { + } + + public void bar() { + } + + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ModelHelper.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ModelHelper.java new file mode 100644 index 0000000000..aad6b96cf9 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ModelHelper.java @@ -0,0 +1,99 @@ +/* + * 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.java.introspect.impl; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Contract; +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.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; + +/** + * @version $Rev$ $Date$ + */ +public class ModelHelper { + + public static Property getProperty(JavaImplementation type, String name) { + for (Property prop : type.getProperties()) { + if (prop.getName().equals(name)) { + return prop; + } + } + return null; + } + + public static Reference getReference(JavaImplementation type, String name) { + for (Reference ref : type.getReferences()) { + if (ref.getName().equals(name)) { + return ref; + } + } + return null; + } + + public static Service getService(JavaImplementation type, String name) { + for (Service svc : type.getServices()) { + if (svc.getName().equals(name)) { + return svc; + } + } + return null; + } + + public static boolean matches(Contract contract, Class<?> type) { + Interface interface1 = contract.getInterfaceContract().getInterface(); + if (interface1 instanceof JavaInterface) { + return type == ((JavaInterface)interface1).getJavaClass(); + } else { + return false; + } + } + + public static ComponentService createService(AssemblyFactory factory, + JavaInterfaceFactory javaFactory, Class<?> type) { + org.apache.tuscany.sca.assembly.ComponentService ref = factory.createComponentService(); + ref.setName(type.getSimpleName()); + JavaInterface i = javaFactory.createJavaInterface(); + i.setJavaClass(type); + JavaInterfaceContract ic = javaFactory.createJavaInterfaceContract(); + ic.setInterface(i); + ref.setInterfaceContract(ic); + return ref; + } + + public static Reference createReference(AssemblyFactory factory, + JavaInterfaceFactory javaFactory, String name, Class<?> type) { + org.apache.tuscany.sca.assembly.Reference ref = factory.createReference(); + ref.setName(name); + JavaInterface i = javaFactory.createJavaInterface(); + i.setJavaClass(type); + JavaInterfaceContract ic = javaFactory.createJavaInterfaceContract(); + ic.setInterface(i); + ref.setInterfaceContract(ic); + return ref; + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessorTestCase.java new file mode 100644 index 0000000000..4a625982b0 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessorTestCase.java @@ -0,0 +1,418 @@ +/* + * 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.java.introspect.impl; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.ConfiguredOperation; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.assembly.OperationsConfigurator; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.impl.PolicyJavaInterfaceVisitor; +import org.apache.tuscany.sca.policy.DefaultPolicyFactory; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySetAttachPoint; +import org.osoa.sca.annotations.Requires; +import org.osoa.sca.annotations.Service; + +/** + * @version $Rev$ $Date$ + */ +public class PolicyProcessorTestCase extends TestCase { + private ServiceProcessor serviceProcessor; + private PolicyProcessor policyProcessor; + private PolicyJavaInterfaceVisitor visitor; + private JavaImplementation type; + + // This actually is a test for PolicyJavaInterfaceProcessor. It will get + // invoked via the call to ImplementationProcessorServiceImpl.createService in + // ServiceProcessor. Of course ServiceProcessor class has to be working. + public void stestSingleInterfaceWithIntentsOnInterfaceAtInterfaceLevel() throws Exception { + serviceProcessor.visitClass(Service1.class, type); + visitor.visitInterface((JavaInterface)type.getServices().get(0).getInterfaceContract().getInterface()); + policyProcessor.visitClass(Service1.class, type); + verifyIntents(Service1.class, type); + } + + public void stestMultipleInterfacesWithIntentsOnInterfaceAtInterfaceLevel() throws Exception { + serviceProcessor.visitClass(Service2.class, type); + visitor.visitInterface((JavaInterface)type.getServices().get(0).getInterfaceContract().getInterface()); + policyProcessor.visitClass(Service2.class, type); + verifyIntents(Service2.class, type); + } + + public void stestSingleInterfaceWithIntentsOnImplAtClassLevel() throws Exception { + serviceProcessor.visitClass(Service3.class, type); + visitor.visitInterface((JavaInterface)type.getServices().get(0).getInterfaceContract().getInterface()); + policyProcessor.visitClass(Service3.class, type); + verifyIntents(Service3.class, type); + } + + public void stestMultipleInterfacesWithIntentsOnImplAtClassLevel() throws Exception { + serviceProcessor.visitClass(Service4.class, type); + visitor.visitInterface((JavaInterface)type.getServices().get(0).getInterfaceContract().getInterface()); + policyProcessor.visitClass(Service4.class, type); + verifyIntents(Service4.class, type); + } + + public void stestSingleInterfaceWithIntentsOnInterfaceAtMethodLevel() throws Exception { + serviceProcessor.visitClass(Service5.class, type); + visitor.visitInterface((JavaInterface)type.getServices().get(0).getInterfaceContract().getInterface()); + policyProcessor.visitClass(Service5.class, type); + verifyIntents(Service5.class, type); + } + + public void testSingleInterfaceWithIntentsOnServiceAndInterfaceAtImplAndInertfaceAndMethodLevel() throws Exception { + serviceProcessor.visitClass(Service6.class, type); + visitor.visitInterface((JavaInterface)type.getServices().get(0).getInterfaceContract().getInterface()); + policyProcessor.visitClass(Service6.class, type); + for (Method method : Service6.class.getDeclaredMethods()) { + policyProcessor.visitMethod(method, type); + } + verifyIntents(Service6.class, type); + } + + private void verifyIntents(Class serviceImplClass, JavaImplementation type) { + if ( !(type instanceof PolicySetAttachPoint) ) { + fail("No Intents on the service "); + } + Requires serviceImplIntentAnnotation = (Requires)serviceImplClass.getAnnotation(Requires.class); + if (serviceImplIntentAnnotation != null) { + String[] serviceImplIntents = serviceImplIntentAnnotation.value(); + List<Intent> requiredIntents = ((PolicySetAttachPoint)type).getRequiredIntents(); + if (serviceImplIntents.length > 0) { + if (requiredIntents == null || requiredIntents.size() == 0) { + fail("No Intents on the service "); + } + Map<String, Intent> intentMap = new HashMap<String, Intent>(); + for (Intent intent : requiredIntents) { + intentMap.put(intent.getName().getLocalPart(), intent); + } + for (String intent : serviceImplIntents) { + assertTrue("ComponentType for Service class " + serviceImplClass.getName() + + " did not contain Service Implementation intent " + + intent, intentMap.containsKey(intent)); + } + } + } + + // This should match what was specified on @Service for a Service Implementation + // If we use these to get the Service names and we get a null Service + // name then it would seem that wrong values were put on the @Service annotation + // or the wrong interfaces were specified on the implements list of the class + // statement? + Map<String, org.apache.tuscany.sca.assembly.Service> serviceMap = new HashMap<String, org.apache.tuscany.sca.assembly.Service>(); + for (org.apache.tuscany.sca.assembly.Service service: type.getServices()) { + serviceMap.put(service.getName(), service); + } + for (Class interfaceClass : serviceImplClass.getInterfaces()) { + Requires interfaceIntentAnnotation = (Requires)interfaceClass.getAnnotation(Requires.class); + org.apache.tuscany.sca.assembly.Service service = serviceMap.get(interfaceClass.getSimpleName()); + if (service == null) { + fail("No service defined for interface " + interfaceClass.getSimpleName() + + " on Service Implementation " + + serviceImplClass.getName()); + } + + if (interfaceIntentAnnotation != null) { + String[] interfaceIntents = interfaceIntentAnnotation.value(); + List<Intent> requiredIntents = service.getInterfaceContract().getInterface().getRequiredIntents(); + if (interfaceIntents.length > 0) { + if (requiredIntents == null || requiredIntents.size() == 0) { + fail("No Intents on the service " + service.getName()); + } + Map<String, Intent> intentMap = new HashMap<String, Intent>(); + for (Intent intent : requiredIntents) { + intentMap.put(intent.getName().getLocalPart(), intent); + } + for (String intent : interfaceIntents) { + assertTrue("Interface " + service.getName() + + " did not contain Service Interface intent " + + intent, intentMap.containsKey(intent)); + } + } + } + + for (Method method : interfaceClass.getDeclaredMethods()) { + Requires methodIntentAnnotation = method.getAnnotation(Requires.class); + + // Verify that each of the Intents on each of the Service + // Interface Methods exist on their associated operation. + if (methodIntentAnnotation != null) { + String[] methodIntents = methodIntentAnnotation.value(); + if (methodIntents.length > 0) { + List<Intent> requiredIntents = null; + for ( ConfiguredOperation confOp : service.getConfiguredOperations() ) { + if ( confOp.getName().equals(method.getName()) && + confOp.getContractName().equals(service.getName()) ) { + requiredIntents = confOp.getRequiredIntents(); + } + } + + if (requiredIntents == null || requiredIntents.size() == 0) { + fail("No Intents on operation " + method.getName()); + } + for (String intent : methodIntents) { + boolean found = false; + for (Intent requiredIntent: requiredIntents) { + if (requiredIntent.getName().getLocalPart().equals(intent)) { + found = true; + break; + } + } + assertTrue("Operation " + method.getName() + + " did not contain Service Interface method intent " + + intent, found); + } + } + } + } + + for (Method method : serviceImplClass.getDeclaredMethods()) { + Requires methodIntentAnnotation = method.getAnnotation(Requires.class); + + // Verify that each of the Intents on each of the Service + // Implementation Methods exist on their associated + // operation. + if (methodIntentAnnotation != null) { + String[] methodIntents = methodIntentAnnotation.value(); + if (methodIntents.length > 0) { + List<Intent> requiredIntents = null; + for ( ConfiguredOperation confOp : ((OperationsConfigurator)type).getConfiguredOperations() ) { + if ( confOp.getName().equals(method.getName()) ) { + requiredIntents = confOp.getRequiredIntents(); + } + } + + if (requiredIntents == null || requiredIntents.size() == 0) { + fail("No Intents on operation " + method.getName()); + } + + for (String intent : methodIntents) { + boolean found = false; + for (Intent requiredIntent: requiredIntents) { + if (requiredIntent.getName().getLocalPart().equals(intent)) { + found = true; + break; + } + } + assertTrue("Operation " + method.getName() + + " did not contain Implementation method intent " + + intent, found); + } + } + } + } + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + serviceProcessor = new ServiceProcessor(new DefaultAssemblyFactory(), new DefaultJavaInterfaceFactory()); + policyProcessor = new PolicyProcessor(new DefaultAssemblyFactory(), new DefaultPolicyFactory()); + visitor = new PolicyJavaInterfaceVisitor(new DefaultPolicyFactory()); + JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + type = javaImplementationFactory.createJavaImplementation(); + } + + // @Remotable + @Requires( {"transaction.global"}) + private interface Interface1 { + int method1(); + + int method2(); + + int method3(); + + int method4(); + } + + @Service(Interface1.class) + private class Service1 implements Interface1 { + public int method1() { + return 0; + } + + public int method2() { + return 0; + } + + public int method3() { + return 0; + } + + public int method4() { + return 0; + } + } + + // @Remotable + @Requires( {"transaction.local"}) + private interface Interface2 { + int method5(); + + int method6(); + } + + @Service(interfaces = {Interface1.class, Interface2.class}) + private class Service2 implements Interface1, Interface2 { + public int method1() { + return 0; + } + + public int method2() { + return 0; + } + + public int method3() { + return 0; + } + + public int method4() { + return 0; + } + + public int method5() { + return 0; + } + + public int method6() { + return 0; + } + } + + // @Remotable + private interface Interface3 { + int method1(); + + int method2(); + + int method3(); + + int method4(); + } + + @Service(Interface3.class) + @Requires( {"transaction.global"}) + private class Service3 implements Interface3 { + public int method1() { + return 0; + } + + public int method2() { + return 0; + } + + public int method3() { + return 0; + } + + public int method4() { + return 0; + } + } + + // @Remotable + private interface Interface4 { + int method5(); + + int method6(); + } + + @Service(interfaces = {Interface3.class, Interface4.class}) + @Requires( {"transaction.local"}) + private class Service4 implements Interface3, Interface4 { + public int method1() { + return 0; + } + + public int method2() { + return 0; + } + + public int method3() { + return 0; + } + + public int method4() { + return 0; + } + + public int method5() { + return 0; + } + + public int method6() { + return 0; + } + } + + private interface Interface5 { + @Requires( {"transaction.global"}) + int method1(); + + @Requires( {"transaction.local"}) + int method2(); + } + + @Service(Interface5.class) + private class Service5 implements Interface5 { + public int method1() { + return 0; + } + + public int method2() { + return 0; + } + } + + @Requires( {"transaction.global.Interface6"}) + private interface Interface6 { + @Requires( {"transaction.global.Interface6.method1"}) + int method1(); + + @Requires( {"transaction.local.Interface6.method2"}) + int method2(); + } + + @Service(Interface6.class) + @Requires( {"transaction.global.Service6"}) + private class Service6 implements Interface6 { + @Requires( {"transaction.global.Service6.method1"}) + public int method1() { + return 0; + } + + @Requires( {"transaction.global.Service6.method1"}) + public int method2() { + return 0; + } + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessorTestCase.java new file mode 100644 index 0000000000..8d5e816a08 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessorTestCase.java @@ -0,0 +1,212 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getProperty; + +import java.util.Collection; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.osoa.sca.annotations.Property; + +/** + * @version $Rev$ $Date$ + */ +public class PropertyProcessorTestCase extends TestCase { + + JavaImplementation type; + PropertyProcessor processor; + + public void testMethodAnnotation() throws Exception { + processor.visitMethod(Foo.class.getMethod("setFoo", String.class), type); + assertNotNull(getProperty(type, "foo")); + } + + public void testMethodRequired() throws Exception { + processor.visitMethod(Foo.class.getMethod("setFooRequired", String.class), type); + org.apache.tuscany.sca.assembly.Property prop = getProperty(type, "fooRequired"); + assertNotNull(prop); + assertTrue(prop.isMustSupply()); + } + + public void testMethodName() throws Exception { + processor.visitMethod(Foo.class.getMethod("setBarMethod", String.class), type); + assertNotNull(getProperty(type, "bar")); + } + + public void testFieldAnnotation() throws Exception { + processor.visitField(Foo.class.getDeclaredField("baz"), type); + assertNotNull(getProperty(type, "baz")); + } + + public void testFieldRequired() throws Exception { + processor.visitField(Foo.class.getDeclaredField("bazRequired"), type); + org.apache.tuscany.sca.assembly.Property prop = getProperty(type, "bazRequired"); + assertNotNull(prop); + assertTrue(prop.isMustSupply()); + } + + public void testFieldName() throws Exception { + processor.visitField(Foo.class.getDeclaredField("bazField"), type); + assertNotNull(getProperty(type, "theBaz")); + } + + public void testDuplicateFields() throws Exception { + processor.visitField(Bar.class.getDeclaredField("dup"), type); + try { + processor.visitField(Bar.class.getDeclaredField("baz"), type); + fail(); + } catch (DuplicatePropertyException e) { + // expected + } + } + + public void testDuplicateMethods() throws Exception { + processor.visitMethod(Bar.class.getMethod("setDupMethod", String.class), type); + try { + processor.visitMethod(Bar.class.getMethod("setDupSomeMethod", String.class), type); + fail(); + } catch (DuplicatePropertyException e) { + // expected + } + } + + public void testInvalidProperty() throws Exception { + try { + processor.visitMethod(Bar.class.getMethod("badMethod"), type); + fail(); + } catch (IllegalPropertyException e) { + // expected + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + type = javaImplementationFactory.createJavaImplementation(); + processor = new PropertyProcessor(new DefaultAssemblyFactory()); + } + + private class Foo { + + @Property + protected String baz; + @Property(required = true) + protected String bazRequired; + @Property(name = "theBaz") + protected String bazField; + + @Property + public void setFoo(String string) { + } + + @Property(required = true) + public void setFooRequired(String string) { + } + + @Property(name = "bar") + public void setBarMethod(String string) { + } + + } + + private class Bar { + + @Property + protected String dup; + + @Property(name = "dup") + protected String baz; + + @Property + public void setDupMethod(String s) { + } + + @Property(name = "dupMethod") + public void setDupSomeMethod(String s) { + } + + @Property + public void badMethod() { + } + + } + + private class Multiple { + @Property + protected List<String> refs1; + + @Property + protected String[] refs2; + + @Property + public void setRefs3(String[] refs) { + } + + @Property + public void setRefs4(Collection<String> refs) { + } + + } + + private Class<?> getBaseType(JavaElementImpl element) { + return JavaIntrospectionHelper.getBaseType(element.getType(), element.getGenericType()); + } + + public void testMultiplicityCollection() throws Exception { + processor.visitField(Multiple.class.getDeclaredField("refs1"), type); + org.apache.tuscany.sca.assembly.Property prop = getProperty(type, "refs1"); + assertNotNull(prop); + assertSame(String.class, getBaseType(type.getPropertyMembers().get(prop.getName()))); + assertTrue(prop.isMany()); + } + + public void testMultiplicityArray() throws Exception { + processor.visitField(Multiple.class.getDeclaredField("refs2"), type); + org.apache.tuscany.sca.assembly.Property prop = getProperty(type, "refs2"); + assertNotNull(prop); + assertSame(String.class, getBaseType(type.getPropertyMembers().get(prop.getName()))); + assertTrue(prop.isMany()); + } + + public void testMultiplicityArrayMethod() throws Exception { + processor.visitMethod(Multiple.class.getMethod("setRefs3", String[].class), type); + org.apache.tuscany.sca.assembly.Property prop = getProperty(type, "refs3"); + assertNotNull(prop); + assertSame(String.class, getBaseType(type.getPropertyMembers().get(prop.getName()))); + assertTrue(prop.isMany()); + } + + public void testMultiplicityCollectionMethod() throws Exception { + processor.visitMethod(Multiple.class.getMethod("setRefs4", Collection.class), type); + org.apache.tuscany.sca.assembly.Property prop = getProperty(type, "refs4"); + assertNotNull(prop); + assertSame(String.class, getBaseType(type.getPropertyMembers().get(prop.getName()))); + assertTrue(prop.isMany()); + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessorTestCase.java new file mode 100644 index 0000000000..d68b1530f0 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessorTestCase.java @@ -0,0 +1,221 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getReference; + +import java.util.Collection; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.osoa.sca.annotations.Reference; + +/** + * @version $Rev$ $Date$ + */ +public class ReferenceProcessorTestCase extends TestCase { + + private JavaImplementation type; + private ReferenceProcessor processor; + + public void testMethodAnnotation() throws Exception { + processor.visitMethod(ReferenceProcessorTestCase.Foo.class.getMethod("setFoo", Ref.class), type); + org.apache.tuscany.sca.assembly.Reference reference = getReference(type, "foo"); + assertNotNull(reference); + assertEquals(Ref.class, ((JavaInterface)reference.getInterfaceContract().getInterface()).getJavaClass()); + } + + public void testMethodRequired() throws Exception { + processor.visitMethod(ReferenceProcessorTestCase.Foo.class.getMethod("setFooRequired", Ref.class), type); + org.apache.tuscany.sca.assembly.Reference ref = getReference(type, "fooRequired"); + assertNotNull(ref); + assertEquals(Multiplicity.ONE_ONE, ref.getMultiplicity()); + } + + public void testMethodName() throws Exception { + processor.visitMethod(ReferenceProcessorTestCase.Foo.class.getMethod("setBarMethod", Ref.class), type); + assertNotNull(getReference(type, "bar")); + } + + public void testFieldAnnotation() throws Exception { + processor.visitField(ReferenceProcessorTestCase.Foo.class.getDeclaredField("baz"), type); + org.apache.tuscany.sca.assembly.Reference reference = getReference(type, "baz"); + assertNotNull(reference); + assertEquals(Ref.class, ((JavaInterface)reference.getInterfaceContract().getInterface()).getJavaClass()); + } + + public void testFieldRequired() throws Exception { + processor.visitField(ReferenceProcessorTestCase.Foo.class.getDeclaredField("bazRequired"), type); + org.apache.tuscany.sca.assembly.Reference ref = getReference(type, "bazRequired"); + assertNotNull(ref); + assertEquals(Multiplicity.ONE_ONE, ref.getMultiplicity()); + } + + public void testFieldName() throws Exception { + processor.visitField(ReferenceProcessorTestCase.Foo.class.getDeclaredField("bazField"), type); + assertNotNull(getReference(type, "theBaz")); + } + + public void testDuplicateFields() throws Exception { + processor.visitField(ReferenceProcessorTestCase.Bar.class.getDeclaredField("dup"), type); + try { + processor.visitField(ReferenceProcessorTestCase.Bar.class.getDeclaredField("baz"), type); + fail(); + } catch (DuplicateReferenceException e) { + // expected + } + } + + public void testDuplicateMethods() throws Exception { + processor.visitMethod(ReferenceProcessorTestCase.Bar.class.getMethod("setDupMethod", Ref.class), type); + try { + processor.visitMethod(ReferenceProcessorTestCase.Bar.class.getMethod("setDupSomeMethod", Ref.class), type); + fail(); + } catch (DuplicateReferenceException e) { + // expected + } + } + + public void testInvalidProperty() throws Exception { + try { + processor.visitMethod(ReferenceProcessorTestCase.Bar.class.getMethod("badMethod"), type); + fail(); + } catch (IllegalReferenceException e) { + // expected + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + type = javaImplementationFactory.createJavaImplementation(); + processor = new ReferenceProcessor(new DefaultAssemblyFactory(), new DefaultJavaInterfaceFactory()); + } + + private interface Ref { + } + + private class Foo { + + @Reference + protected Ref baz; + @Reference(required = true) + protected Ref bazRequired; + @Reference(name = "theBaz") + protected Ref bazField; + + @Reference + public void setFoo(Ref ref) { + } + + @Reference(required = true) + public void setFooRequired(Ref ref) { + } + + @Reference(name = "bar") + public void setBarMethod(Ref ref) { + } + + } + + private class Bar { + + @Reference + protected Ref dup; + + @Reference(name = "dup") + protected Ref baz; + + @Reference + public void setDupMethod(Ref s) { + } + + @Reference(name = "dupMethod") + public void setDupSomeMethod(Ref s) { + } + + @Reference + public void badMethod() { + } + + } + + private class Multiple { + @Reference(required = true) + protected List<Ref> refs1; + + @Reference(required = false) + protected Ref[] refs2; + + @Reference(required = true) + public void setRefs3(Ref[] refs) { + } + + @Reference(required = false) + public void setRefs4(Collection<Ref> refs) { + } + + } + + public void testMultiplicity1ToN() throws Exception { + processor.visitField(Multiple.class.getDeclaredField("refs1"), type); + org.apache.tuscany.sca.assembly.Reference ref = getReference(type, "refs1"); + assertNotNull(ref); + assertSame(Ref.class, ((JavaInterface)ref.getInterfaceContract().getInterface()).getJavaClass()); + assertEquals(Multiplicity.ONE_N, ref.getMultiplicity()); + // assertEquals(Multiplicity.ONE_ONE, ref.getMultiplicity()); + } + + public void testMultiplicityTo0ToN() throws Exception { + processor.visitField(Multiple.class.getDeclaredField("refs2"), type); + org.apache.tuscany.sca.assembly.Reference ref = getReference(type, "refs2"); + assertNotNull(ref); + assertSame(Ref.class, ((JavaInterface)ref.getInterfaceContract().getInterface()).getJavaClass()); + assertEquals(Multiplicity.ZERO_N, ref.getMultiplicity()); + // assertFalse(ref.isMustSupply()); + } + + public void testMultiplicity1ToNMethod() throws Exception { + processor.visitMethod(Multiple.class.getMethod("setRefs3", Ref[].class), type); + org.apache.tuscany.sca.assembly.Reference ref = getReference(type, "refs3"); + assertNotNull(ref); + assertSame(Ref.class, ((JavaInterface)ref.getInterfaceContract().getInterface()).getJavaClass()); + assertEquals(Multiplicity.ONE_N, ref.getMultiplicity()); + // assertEquals(Multiplicity.ONE_ONE, ref.getMultiplicity()); + } + + public void testMultiplicity0ToNMethod() throws Exception { + processor.visitMethod(Multiple.class.getMethod("setRefs4", Collection.class), type); + org.apache.tuscany.sca.assembly.Reference ref = getReference(type, "refs4"); + assertNotNull(ref); + assertSame(Ref.class, ((JavaInterface)ref.getInterfaceContract().getInterface()).getJavaClass()); + assertEquals(Multiplicity.ZERO_N, ref.getMultiplicity()); + // assertFalse(ref.isMustSupply()); + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessorTestCase.java new file mode 100644 index 0000000000..7bb8e15696 --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessorTestCase.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.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl; + +/** + * @version $Rev$ $Date$ + */ +public class ResourceProcessorTestCase extends TestCase { + + JavaImplementation type; + ResourceProcessor processor = new ResourceProcessor(new DefaultAssemblyFactory()); + + public void testVisitField() throws Exception { + Field field = Foo.class.getDeclaredField("bar"); + processor.visitField(field, type); + JavaResourceImpl resource = type.getResources().get("bar"); + assertFalse(resource.isOptional()); + assertNull(resource.getMappedName()); + assertEquals(field.getType(), resource.getElement().getType()); + } + + public void testVisitMethod() throws Exception { + Method method = Foo.class.getMethod("setBar", Bar.class); + processor.visitMethod(method, type); + JavaResourceImpl resource = type.getResources().get("bar"); + assertFalse(resource.isOptional()); + assertNull(resource.getMappedName()); + assertEquals(method.getParameterTypes()[0], resource.getElement().getType()); + } + + public void testVisitNamedMethod() throws Exception { + Method method = Foo.class.getMethod("setBar2", Bar.class); + processor.visitMethod(method, type); + JavaResourceImpl resource = type.getResources().get("someName"); + assertFalse(resource.isOptional()); + assertEquals("mapped", resource.getMappedName()); + } + + public void testVisitBadMethod() throws Exception { + Method method = Foo.class.getMethod("setBad"); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalResourceException e) { + // expected + } + } + + public void testDuplicateResources() throws Exception { + Field field = Foo.class.getDeclaredField("bar"); + processor.visitField(field, type); + try { + processor.visitField(field, type); + fail(); + } catch (DuplicateResourceException e) { + //expected + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + type = javaImplementationFactory.createJavaImplementation(); + } + + private class Foo { + + @org.apache.tuscany.sca.implementation.java.introspect.impl.Resource + protected Bar bar; + + @org.apache.tuscany.sca.implementation.java.introspect.impl.Resource(optional = true) + protected Bar barNotRequired; + + @org.apache.tuscany.sca.implementation.java.introspect.impl.Resource + public void setBar(Bar bar) { + } + + @org.apache.tuscany.sca.implementation.java.introspect.impl.Resource(name = "someName", mappedName = "mapped") + public void setBar2(Bar bar) { + } + + @org.apache.tuscany.sca.implementation.java.introspect.impl.Resource + public void setBad() { + } + + } + + private interface Bar { + + } +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessorTestCase.java new file mode 100644 index 0000000000..d7de4e522e --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessorTestCase.java @@ -0,0 +1,113 @@ +/* + * 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.java.introspect.impl; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.impl.JavaScopeImpl; +import org.easymock.EasyMock; + +/** + * @version $Rev$ $Date$ + */ +public class ScopeProcessorTestCase extends TestCase { + + Component parent; + private JavaImplementationFactory javaImplementationFactory; + + public void testCompositeScope() throws IntrospectionException { + ScopeProcessor processor = new ScopeProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + + processor.visitClass(Composite.class, type); + assertEquals(JavaScopeImpl.COMPOSITE, type.getJavaScope()); + } + + public void testSessionScope() throws IntrospectionException { + ScopeProcessor processor = new ScopeProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(Session.class, type); + assertEquals(JavaScopeImpl.SESSION, type.getJavaScope()); + } + + public void testConversationalScope() throws IntrospectionException { + ScopeProcessor processor = new ScopeProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(Conversation.class, type); + assertEquals(JavaScopeImpl.CONVERSATION, type.getJavaScope()); + } + + public void testRequestScope() throws IntrospectionException { + ScopeProcessor processor = new ScopeProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(Request.class, type); + assertEquals(JavaScopeImpl.REQUEST, type.getJavaScope()); + } + + public void testStatelessScope() throws IntrospectionException { + ScopeProcessor processor = new ScopeProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(Stateless.class, type); + assertEquals(JavaScopeImpl.STATELESS, type.getJavaScope()); + } + + public void testNoScope() throws IntrospectionException { + ScopeProcessor processor = new ScopeProcessor(new DefaultAssemblyFactory()); + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(None.class, type); + assertEquals(JavaScopeImpl.STATELESS, type.getJavaScope()); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + parent = EasyMock.createNiceMock(Component.class); + } + + @org.osoa.sca.annotations.Scope("COMPOSITE") + private class Composite { + } + + @org.osoa.sca.annotations.Scope("SESSION") + private class Session { + } + + @org.osoa.sca.annotations.Scope("CONVERSATION") + private class Conversation { + } + + @org.osoa.sca.annotations.Scope("REQUEST") + private class Request { + } + + @org.osoa.sca.annotations.Scope("STATELESS") + private class Stateless { + } + + private class None { + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceCallbackTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceCallbackTestCase.java new file mode 100644 index 0000000000..10f0500e4d --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceCallbackTestCase.java @@ -0,0 +1,183 @@ +/* + * 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.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.ModelHelper.getService; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.interfacedef.InvalidCallbackException; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.osoa.sca.CallableReference; +import org.osoa.sca.annotations.Callback; +import org.osoa.sca.annotations.Service; + +/** + * @version $Rev$ $Date$ + */ +public class ServiceCallbackTestCase extends TestCase { + private ServiceProcessor processor; + private JavaImplementationFactory javaImplementationFactory; + + @Override + protected void setUp() throws Exception { + processor = new ServiceProcessor(new DefaultAssemblyFactory(), new DefaultJavaInterfaceFactory()); + javaImplementationFactory = new DefaultJavaImplementationFactory(); + } + + public void testMethodCallbackInterface() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(FooImpl.class, type); + org.apache.tuscany.sca.assembly.Service service = getService(type, Foo.class.getSimpleName()); + assertNotNull(service); + Method method = FooImpl.class.getMethod("setCallback", FooCallback.class); + processor.visitMethod(method, type); + assertEquals(method, type.getCallbackMembers().get(FooCallback.class.getName()).iterator().next().getAnchor()); + } + + public void testFieldCallbackInterface() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(FooImpl.class, type); + org.apache.tuscany.sca.assembly.Service service = getService(type, Foo.class.getSimpleName()); + assertNotNull(service); + Field field = FooImpl.class.getDeclaredField("callback"); + processor.visitField(field, type); + assertEquals(field, type.getCallbackMembers().get(FooCallback.class.getName()).iterator().next().getAnchor()); + } + + public void testFieldCallbackInterface1() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(FooImpl1.class, type); + org.apache.tuscany.sca.assembly.Service service = getService(type, Foo.class.getSimpleName()); + assertNotNull(service); + Field field1 = FooImpl1.class.getDeclaredField("callbackRef"); + processor.visitField(field1, type); + assertEquals(field1, type.getCallbackMembers().get(FooCallback.class.getName()).iterator().next().getAnchor()); + + } + + public void testMethodDoesNotMatchCallback() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(BadBarImpl.class, type); + Method method = BadBarImpl.class.getMethod("setWrongInterfaceCallback", String.class); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalCallbackReferenceException e) { + // expected + } + } + + public void testNoParamCallback() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(BadBarImpl.class, type); + Method method = BadBarImpl.class.getMethod("setNoParamCallback"); + try { + processor.visitMethod(method, type); + fail(); + } catch (IllegalCallbackReferenceException e) { + // expected + } + } + + public void testFieldDoesNotMatchCallback() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + processor.visitClass(BadBarImpl.class, type); + Field field = BadBarImpl.class.getDeclaredField("wrongInterfaceCallback"); + try { + processor.visitField(field, type); + fail(); + } catch (IllegalCallbackReferenceException e) { + // expected + } + } + + public void testBadCallbackInterfaceAnnotation() throws Exception { + JavaImplementation type = javaImplementationFactory.createJavaImplementation(); + try { + processor.visitClass(BadFooImpl.class, type); + fail(); + } catch (IntrospectionException e) { + // expected + assertTrue(e.getCause() instanceof InvalidCallbackException); + } + } + + @Callback(FooCallback.class) + private interface Foo { + + } + + private interface FooCallback { + + } + + @Service(Foo.class) + private static class FooImpl implements Foo { + + @Callback + protected FooCallback callback; + + @Callback + public void setCallback(FooCallback cb) { + + } + } + + @Service(Foo.class) + private static class FooImpl1 implements Foo { + @Callback + protected CallableReference<FooCallback> callbackRef; + } + + private static class BadBarImpl implements Foo { + @Callback + protected String wrongInterfaceCallback; + + @Callback + public void setWrongInterfaceCallback(String cb) { + + } + + @Callback + public void setNoParamCallback() { + + } + + } + + @Callback + private interface BadFoo { + + } + + @Service(BadFoo.class) + private static class BadFooImpl implements BadFoo { + + } + +} diff --git a/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessorTestCase.java b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessorTestCase.java new file mode 100644 index 0000000000..ef4747f43a --- /dev/null +++ b/java/sca/modules/implementation-java/src/test/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessorTestCase.java @@ -0,0 +1,143 @@ +/* + * 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.java.introspect.impl; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; +import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.osoa.sca.annotations.Callback; +import org.osoa.sca.annotations.Remotable; +import org.osoa.sca.annotations.Service; + +/** + * @version $Rev$ $Date$ + */ +public class ServiceProcessorTestCase extends TestCase { + private ServiceProcessor processor; + private JavaImplementation type; + + public void testMultipleInterfaces() throws Exception { + processor.visitClass(FooMultiple.class, type); + assertEquals(2, type.getServices().size()); + org.apache.tuscany.sca.assembly.Service service = ModelHelper.getService(type, Baz.class.getSimpleName()); + assertEquals(Baz.class, ((JavaInterface)service.getInterfaceContract().getInterface()).getJavaClass()); + assertEquals(Bar.class, ((JavaInterface)service.getInterfaceContract().getCallbackInterface()).getJavaClass()); + assertNotNull(ModelHelper.getService(type, Bar.class.getSimpleName())); + } + + public void testSingleInterfaces() throws Exception { + processor.visitClass(FooSingle.class, type); + assertEquals(1, type.getServices().size()); + assertNotNull(ModelHelper.getService(type, Baz.class.getSimpleName())); + } + + public void testMultipleNoService() throws Exception { + processor.visitClass(FooMultipleNoService.class, type); + assertEquals(0, type.getServices().size()); + } + + /** + * Verifies a service with a callback annotation is recognized + */ + public void testMultipleWithCallbackAnnotation() throws Exception { + processor.visitClass(FooMultipleWithCalback.class, type); + assertEquals(1, type.getServices().size()); + } + + public void testRemotableNoService() throws Exception { + processor.visitClass(FooRemotableNoService.class, type); + assertEquals(1, type.getServices().size()); + org.apache.tuscany.sca.assembly.Service service = ModelHelper.getService(type, BazRemotable.class.getSimpleName()); + assertEquals(BazRemotable.class, ((JavaInterface)service.getInterfaceContract().getInterface()).getJavaClass()); + } + + public void testNonInterface() throws Exception { + processor.visitClass(FooServiceUsingClassImpl.class, type); + } + + public void testNoInterfaces() throws Exception { + try { + processor.visitClass(BadDefinition.class, type); + } catch (IllegalServiceDefinitionException e) { + //not expected + fail(); + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + processor = new ServiceProcessor(new DefaultAssemblyFactory(), new DefaultJavaInterfaceFactory()); + JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory(); + type = javaImplementationFactory.createJavaImplementation(); + } + + @Callback(Bar.class) + private interface Baz { + } + + private interface Bar { + } + + private interface Bar2 { + } + + @Remotable + private interface BazRemotable { + } + + @Service(interfaces = {Baz.class, Bar.class}) + private class FooMultiple implements Baz, Bar { + + } + + @Service(Baz.class) + private class FooSingle implements Baz, Bar { + + } + + private class FooMultipleNoService implements Bar, Bar2 { + + } + + private class FooMultipleWithCalback implements Baz, Bar { + + } + + private class FooRemotableNoService implements BazRemotable, Bar { + + } + + @Service(FooSingle.class) + private class FooServiceUsingClassImpl extends FooSingle { + + } + + + @Service() + private class BadDefinition extends FooSingle { + + } + +} |