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 /branches/sca-java-1.0/modules/core |
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 'branches/sca-java-1.0/modules/core')
100 files changed, 10598 insertions, 0 deletions
diff --git a/branches/sca-java-1.0/modules/core/.checkstyle b/branches/sca-java-1.0/modules/core/.checkstyle new file mode 100644 index 0000000000..3e57539570 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/.checkstyle @@ -0,0 +1,24 @@ +<?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. +--> +<fileset-config file-format-version="1.2.0" simple-config="true"> + <fileset name="all" enabled="true" check-config-name="Tuscany Checks" local="false"> + <file-match-pattern match-pattern="." include-pattern="true"/> + </fileset> +</fileset-config> diff --git a/branches/sca-java-1.0/modules/core/.pmd b/branches/sca-java-1.0/modules/core/.pmd new file mode 100644 index 0000000000..ffc4fe2bbb --- /dev/null +++ b/branches/sca-java-1.0/modules/core/.pmd @@ -0,0 +1,20 @@ +<?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. +--> +<pmd><useProjectRuleSet>true</useProjectRuleSet><rules/></pmd> diff --git a/branches/sca-java-1.0/modules/core/.ruleset b/branches/sca-java-1.0/modules/core/.ruleset new file mode 100644 index 0000000000..ba9b5ce886 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/.ruleset @@ -0,0 +1,190 @@ +<?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. +--> +<ruleset name="pmd-eclipse"> + <description>PMD Plugin preferences rule set</description> + + + <rule ref="rulesets/basic.xml/BooleanInstantiation"/> + <rule ref="rulesets/basic.xml/CollapsibleIfStatements"/> + <rule ref="rulesets/basic.xml/DoubleCheckedLocking"/> +<!--<rule ref="rulesets/basic.xml/EmptyCatchBlock"/>--> +<!--<rule ref="rulesets/basic.xml/EmptyFinallyBlock"/>--> +<!--<rule ref="rulesets/basic.xml/EmptyIfStmt"/>--> + <rule ref="rulesets/basic.xml/EmptyStatementNotInLoop"/> +<!--<rule ref="rulesets/basic.xml/EmptyStaticInitializer"/>--> +<!--<rule ref="rulesets/basic.xml/EmptySwitchStatements"/>--> +<!--<rule ref="rulesets/basic.xml/EmptySynchronizedBlock"/>--> +<!--<rule ref="rulesets/basic.xml/EmptyTryBlock"/>--> +<!--<rule ref="rulesets/basic.xml/EmptyWhileStmt"/>--> + <rule ref="rulesets/basic.xml/ForLoopShouldBeWhileLoop"/> + <rule ref="rulesets/basic.xml/JumbledIncrementer"/> +<!--<rule ref="rulesets/basic.xml/OverrideBothEqualsAndHashcode"/>--> + <rule ref="rulesets/basic.xml/ReturnFromFinallyBlock"/> + <rule ref="rulesets/basic.xml/UnconditionalIfStatement"/> + <rule ref="rulesets/basic.xml/UnnecessaryConversionTemporary"/> + <rule ref="rulesets/basic.xml/UnnecessaryFinalModifier"/> + <rule ref="rulesets/basic.xml/UnnecessaryReturn"/> +<!--<rule ref="rulesets/basic.xml/UselessOverridingMethod"/>--> + +<!--<rule ref="rulesets/braces.xml/ForLoopsMustUseBraces"/>--> +<!--<rule ref="rulesets/braces.xml/IfElseStmtsMustUseBraces"/>--> +<!--<rule ref="rulesets/braces.xml/IfStmtsMustUseBraces"/>--> +<!--<rule ref="rulesets/braces.xml/WhileLoopsMustUseBraces"/>--> + +<!--<rule ref="rulesets/clone.xml/CloneMethodMustImplementCloneable"/>--> +<!--<rule ref="rulesets/clone.xml/CloneThrowsCloneNotSupportedException"/>--> +<!--<rule ref="rulesets/clone.xml/ProperCloneImplementation"/>--> + +<!--<rule ref="rulesets/codesize.xml/CyclomaticComplexity"/>--> +<!--<rule ref="rulesets/codesize.xml/ExcessiveClassLength"/>--> +<!--<rule ref="rulesets/codesize.xml/ExcessiveMethodLength"/>--> +<!--<rule ref="rulesets/codesize.xml/ExcessiveParameterList"/>--> +<!--<rule ref="rulesets/codesize.xml/ExcessivePublicCount"/>--> +<!--<rule ref="rulesets/codesize.xml/TooManyFields"/>--> + +<rule ref="rulesets/controversial.xml/AssignmentInOperand"/> +<!--<rule ref="rulesets/controversial.xml/AtLeastOneConstructor"/>--> +<!--<rule ref="rulesets/controversial.xml/CallSuperInConstructor"/>--> +<!--<rule ref="rulesets/controversial.xml/DontImportSun"/>--> +<!--<rule ref="rulesets/controversial.xml/NullAssignment"/>--> +<!--<rule ref="rulesets/controversial.xml/OnlyOneReturn"/>--> +<!--<rule ref="rulesets/controversial.xml/SingularField"/>--> +<!--<rule ref="rulesets/controversial.xml/SuspiciousOctalEscape"/>--> +<!--<rule ref="rulesets/controversial.xml/UnnecessaryConstructor"/>--> +<rule ref="rulesets/controversial.xml/UnnecessaryParentheses"/> +<!--<rule ref="rulesets/controversial.xml/UnusedModifier"/>--> + +<!--<rule ref="rulesets/coupling.xml/CouplingBetweenObjects"/>--> +<!--<rule ref="rulesets/coupling.xml/ExcessiveImports"/>--> +<!--<rule ref="rulesets/coupling.xml/LooseCoupling"/>--> + +<!--<rule ref="rulesets/design.xml/AbstractClassWithoutAbstractMethod"/>--> +<!--<rule ref="rulesets/design.xml/AccessorClassGeneration"/>--> +<!--<rule ref="rulesets/design.xml/AssignmentToNonFinalStatic"/>--> +<!--<rule ref="rulesets/design.xml/AvoidDeeplyNestedIfStmts"/>--> +<!--<rule ref="rulesets/design.xml/AvoidInstanceofChecksInCatchClause"/>--> +<rule ref="rulesets/design.xml/AvoidProtectedFieldInFinalClass"/> +<!--<rule ref="rulesets/design.xml/AvoidReassigningParameters"/>--> +<!--<rule ref="rulesets/design.xml/AvoidSynchronizedAtMethodLevel"/>--> +<!--<rule ref="rulesets/design.xml/BadComparison"/>--> +<!--<rule ref="rulesets/design.xml/CloseConnection"/>--> +<!--<rule ref="rulesets/design.xml/CompareObjectsWithEquals"/>--> +<!--<rule ref="rulesets/design.xml/ConfusingTernary"/>--> +<rule ref="rulesets/design.xml/ConstructorCallsOverridableMethod"/> +<!--<rule ref="rulesets/design.xml/DefaultLabelNotLastInSwitchStmt"/>--> +<!--<rule ref="rulesets/design.xml/FinalFieldCouldBeStatic"/>--> +<rule ref="rulesets/design.xml/IdempotentOperations"/> +<!--<rule ref="rulesets/design.xml/ImmutableField"/>--> +<!--<rule ref="rulesets/design.xml/InstantiationToGetClass"/>--> +<!--<rule ref="rulesets/design.xml/MissingBreakInSwitch"/>--> +<!--<rule ref="rulesets/design.xml/MissingStaticMethodInNonInstantiatableClass"/>--> +<!--<rule ref="rulesets/design.xml/NonCaseLabelInSwitchStatement"/>--> +<!--<rule ref="rulesets/design.xml/NonStaticInitializer"/>--> +<rule ref="rulesets/design.xml/OptimizableToArrayCall"/> +<rule ref="rulesets/design.xml/PositionLiteralsFirstInComparisons"/> +<rule ref="rulesets/design.xml/SimplifyBooleanExpressions"/> +<rule ref="rulesets/design.xml/SimplifyBooleanReturns"/> +<rule ref="rulesets/design.xml/SimplifyConditional"/> +<!--<rule ref="rulesets/design.xml/SwitchDensity"/>--> +<!--<rule ref="rulesets/design.xml/SwitchStmtsShouldHaveDefault"/>--> +<!--<rule ref="rulesets/design.xml/UnnecessaryLocalBeforeReturn"/>--> +<!--<rule ref="rulesets/design.xml/UseLocaleWithCaseConversions"/>--> +<!--<rule ref="rulesets/design.xml/UseNotifyAllInsteadOfNotify"/>--> +<!--<rule ref="rulesets/design.xml/UseSingleton"/>--> + +<!--<rule ref="rulesets/finalizers.xml/EmptyFinalizer"/>--> +<!--<rule ref="rulesets/finalizers.xml/FinalizeOnlyCallsSuperFinalize"/>--> +<!--<rule ref="rulesets/finalizers.xml/FinalizeOverloaded"/>--> +<!--<rule ref="rulesets/finalizers.xml/FinalizeDoesNotCallSuperFinalize"/>--> +<!--<rule ref="rulesets/finalizers.xml/FinalizeShouldBeProtected"/>--> +<!--<rule ref="rulesets/finalizers.xml/AvoidCallingFinalize"/>--> + +<!--<rule ref="rulesets/imports.xml/DuplicateImports"/>--> +<!--<rule ref="rulesets/imports.xml/DontImportJavaLang"/>--> +<!--<rule ref="rulesets/imports.xml/UnusedImports"/>--> +<!--<rule ref="rulesets/imports.xml/ImportFromSamePackage"/>--> + +<!--<rule ref="rulesets/javabeans.xml/BeanMembersShouldSerialize"/>--> +<!--<rule ref="rulesets/javabeans.xml/MissingSerialVersionUID"/>--> + +<!--<rule ref="rulesets/junit.xml/JUnitStaticSuite"/>--> +<!--<rule ref="rulesets/junit.xml/JUnitSpelling"/>--> +<!--<rule ref="rulesets/junit.xml/JUnitAssertionsShouldIncludeMessage"/>--> +<!--<rule ref="rulesets/junit.xml/JUnitTestsShouldIncludeAssert"/>--> +<!--<rule ref="rulesets/junit.xml/TestClassWithoutTestCases"/>--> +<!--<rule ref="rulesets/junit.xml/UnnecessaryBooleanAssertion"/>--> +<!--<rule ref="rulesets/junit.xml/UseAssertEqualsInsteadOfAssertTrue"/>--> +<!--<rule ref="rulesets/junit.xml/UseAssertSameInsteadOfAssertTrue"/>--> + + <!--<rule ref="rulesets/logging-java.xml/AvoidPrintStackTrace"/>--> + <!--<rule ref="rulesets/logging-java.xml/LoggerIsNotStaticFinal"/>--> + <!--<rule ref="rulesets/logging-java.xml/MoreThanOneLogger"/>--> + <!--<rule ref="rulesets/logging-java.xml/LoggerIsNotStaticFinal"/>--> + <!--<rule ref="rulesets/logging-java.xml/LogBlockWithoutIf"/>--> + <!--<rule ref="rulesets/logging-java.xml/SystemPrintln"/>--> + <!--<rule ref="rulesets/logging-jakarta-commons.xml/UseCorrectExceptionLogging"/>--> + <!--<rule ref="rulesets/logging-jakarta-commons.xml/ProperLogger"/>--> + + <!--<rule ref="rulesets/naming.xml/ShortVariable"/>--> + <!--<rule ref="rulesets/naming.xml/LongVariable"/>--> + <!--<rule ref="rulesets/naming.xml/ShortMethodName"/>--> + <!--<rule ref="rulesets/naming.xml/VariableNamingConventions"/>--> + <!--<rule ref="rulesets/naming.xml/MethodNamingConventions"/>--> + <!--<rule ref="rulesets/naming.xml/ClassNamingConventions"/>--> + <!--<rule ref="rulesets/naming.xml/AbstractNaming"/>--> + <!--<rule ref="rulesets/naming.xml/AvoidDollarSigns"/>--> + <!--<rule ref="rulesets/naming.xml/MethodWithSameNameAsEnclosingClass"/>--> + <!--<rule ref="rulesets/naming.xml/SuspiciousHashcodeMethodName"/>--> + <!--<rule ref="rulesets/naming.xml/SuspiciousConstantFieldName"/>--> + <!--<rule ref="rulesets/naming.xml/AvoidFieldNameMatchingTypeName"/>--> + <!--<rule ref="rulesets/naming.xml/AvoidFieldNameMatchingMethodName"/>--> + <!--<rule ref="rulesets/naming.xml/AvoidNonConstructorMethodsWithClassName"/>--> + <!--<rule ref="rulesets/naming.xml/NoPackage"/>--> + <!--<rule ref="rulesets/naming.xml/PackageCase"/>--> + + <!--<rule ref="rulesets/optimizations.xml/LocalVariableCouldBeFinal"/>--> + <!--<rule ref="rulesets/optimizations.xml/MethodArgumentCouldBeFinal"/>--> + <!--<rule ref="rulesets/optimizations.xml/AvoidInstantiatingObjectsInLoops"/>--> + <!--<rule ref="rulesets/optimizations.xml/UseArrayListInsteadOfVector"/>--> + <!--<rule ref="rulesets/optimizations.xml/SimplifyStartsWith"/>--> + <!--<rule ref="rulesets/optimizations.xml/UseStringBufferForStringAppends"/>--> + + <!--<rule ref="rulesets/strictexception.xml/AvoidCatchingThrowable"/>--> + <!--<rule ref="rulesets/strictexception.xml/SignatureDeclareThrowsException"/>--> + <!--<rule ref="rulesets/strictexception.xml/ExceptionAsFlowControl"/>--> + <!--<rule ref="rulesets/strictexception.xml/AvoidCatchingNPE"/>--> + <!--<rule ref="rulesets/strictexception.xml/AvoidThrowingRawExceptionTypes"/>--> + <!--<rule ref="rulesets/strictexception.xml/AvoidThrowingNullPointerException"/>--> + + <!--<rule ref="rulesets/strings.xml/AvoidDuplicateLiterals"/>--> + <!--<rule ref="rulesets/strings.xml/StringInstantiation"/>--> + <!--<rule ref="rulesets/strings.xml/StringToString"/>--> + <!--<rule ref="rulesets/strings.xml/AvoidConcatenatingNonLiteralsInStringBuffer"/>--> + <!--<rule ref="rulesets/strings.xml/UnnecessaryCaseChange"/>--> + + <!--<rule ref="rulesets/sunsecure.xml/MethodReturnsInternalArray"/>--> + <!--<rule ref="rulesets/sunsecure.xml/ArrayIsStoredDirectly"/>--> + + <rule ref="rulesets/unusedcode.xml/UnusedLocalVariable"/> + <rule ref="rulesets/unusedcode.xml/UnusedPrivateField"/> + <rule ref="rulesets/unusedcode.xml/UnusedPrivateMethod"/> + <!--<rule ref="rulesets/unusedcode.xml/UnusedFormalParameter"/>--> + +</ruleset> diff --git a/branches/sca-java-1.0/modules/core/DISCLAIMER b/branches/sca-java-1.0/modules/core/DISCLAIMER new file mode 100644 index 0000000000..d68a410903 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/DISCLAIMER @@ -0,0 +1,8 @@ +Apache Tuscany is an effort undergoing incubation at The Apache Software
+Foundation (ASF), sponsored by the Apache Web Services PMC. Incubation is
+required of all newly accepted projects until a further review indicates that
+the infrastructure, communications, and decision making process have stabilized
+in a manner consistent with other successful ASF projects. While incubation
+status is not necessarily a reflection of the completeness or stability of the
+code, it does indicate that the project has yet to be fully endorsed by the ASF.
+
diff --git a/branches/sca-java-1.0/modules/core/LICENSE b/branches/sca-java-1.0/modules/core/LICENSE new file mode 100644 index 0000000000..8aa906c321 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/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/branches/sca-java-1.0/modules/core/NOTICE b/branches/sca-java-1.0/modules/core/NOTICE new file mode 100644 index 0000000000..94481d6cfa --- /dev/null +++ b/branches/sca-java-1.0/modules/core/NOTICE @@ -0,0 +1,6 @@ +${pom.name} +Copyright (c) 2005 - 2007 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + diff --git a/branches/sca-java-1.0/modules/core/pom.xml b/branches/sca-java-1.0/modules/core/pom.xml new file mode 100644 index 0000000000..b8fbf94b91 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/pom.xml @@ -0,0 +1,76 @@ +<?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.0-incubating-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>tuscany-core</artifactId> + <name>Apache Tuscany SCA Core Runtime</name> + + <dependencies> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-core-spi</artifactId> + <version>1.0-incubating-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-contribution</artifactId> + <version>1.0-incubating-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-contribution-java</artifactId> + <version>1.0-incubating-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-interface-java</artifactId> + <version>1.0-incubating-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-commonj_1.1_spec</artifactId> + <version>1.0</version> + </dependency> + + <dependency> + <groupId>org.codehaus.woodstox</groupId> + <artifactId>wstx-asl</artifactId> + <version>3.2.1</version> + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>cglib</groupId> + <artifactId>cglib-nodep</artifactId> + <version>2.1_3</version> + </dependency> + </dependencies> + +</project> diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ActivationException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ActivationException.java new file mode 100644 index 0000000000..c86c876075 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ActivationException.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.core.assembly; + + +/** + * Denotes an error starting the runtime + * + * @version $Rev$ $Date$ + */ +public class ActivationException extends Exception { + private static final long serialVersionUID = 8612661660934426123L; + + public ActivationException(String message) { + super(message); + } + + public ActivationException(Throwable cause) { + super(cause); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/CompositeActivator.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/CompositeActivator.java new file mode 100644 index 0000000000..29dcc20f0b --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/CompositeActivator.java @@ -0,0 +1,154 @@ +/* + * 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.core.assembly; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.core.context.ComponentContextHelper; +import org.apache.tuscany.sca.core.conversation.ConversationManager; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; + +/** + * Start/stop a composite + * + * @version $Rev$ $Date$ + */ +public interface CompositeActivator { + /** + * Activate a composite + * @param composite + */ + void activate(Composite composite) throws ActivationException; + + /** + * Activate a component reference + * @param component + * @param ref + */ + void start(RuntimeComponent component, RuntimeComponentReference ref); + + /** + * Activate a component reference + * @param component + * @param ref + */ + void activate(RuntimeComponent component, RuntimeComponentReference ref); + + /** + * Activate a component reference + * @param component + * @param ref + */ + void activate(RuntimeComponent component, RuntimeComponentService service); + + /** + * De-activate a component reference + * @param component + * @param ref + */ + void deactivate(RuntimeComponent component, RuntimeComponentReference ref); + + /** + * De-activate a component reference + * @param component + * @param ref + */ + void deactivate(RuntimeComponent component, RuntimeComponentService service); + + /** + * Stop a composite + * @param composite + */ + void deactivate(Composite composite) throws ActivationException; + + /** + * Start a component + * @param component + */ + void start(Component component) throws ActivationException; + + /** + * Stop a component + * @param component + */ + void stop(Component component) throws ActivationException; + + /** + * Start components in a composite + * @param composite + */ + void start(Composite composite) throws ActivationException; + + /** + * Stop components in a composite + * @param composite + */ + void stop(Composite composite) throws ActivationException; + + /** + * Get the component context helper + * @return + */ + ComponentContextHelper getComponentContextHelper(); + + /** + * Get the proxy factory + * @return + */ + ProxyFactory getProxyFactory(); + + /** + * Get the java interface factory + * @return + */ + JavaInterfaceFactory getJavaInterfaceFactory(); + + ConversationManager getConversationManager(); + + /** + * Configure the runtime component with component context + * @param component + */ + void configureComponentContext(RuntimeComponent component); + + /** + * Resolve a component by URI in the domain + * @param componentURI + * @return + */ + Component resolve(String componentURI); + + /** + * Set the domain composite + * @param domainComposite + */ + void setDomainComposite(Composite domainComposite); + + /** + * Get the domain composite + * @return + */ + Composite getDomainComposite(); + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/CompositeActivatorImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/CompositeActivatorImpl.java new file mode 100644 index 0000000000..2a52b5f272 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/CompositeActivatorImpl.java @@ -0,0 +1,841 @@ +/* + * 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.core.assembly; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.SCABindingFactory; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.OptimizableBinding; +import org.apache.tuscany.sca.context.RequestContextFactory; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.context.ComponentContextHelper; +import org.apache.tuscany.sca.core.context.ComponentContextImpl; +import org.apache.tuscany.sca.core.conversation.ConversationManager; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.core.scope.ConversationalScopeContainer; +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopeRegistry; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.provider.BindingProviderFactory; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.provider.ImplementationProviderFactory; +import org.apache.tuscany.sca.provider.ProviderFactoryExtensionPoint; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentContext; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.work.WorkScheduler; + +/** + * @version $Rev$ $Date$ + */ +public class CompositeActivatorImpl implements CompositeActivator { + private final static Logger logger = Logger.getLogger(CompositeActivatorImpl.class.getName()); + + private final AssemblyFactory assemblyFactory; + private final MessageFactory messageFactory; + private final InterfaceContractMapper interfaceContractMapper; + private final ScopeRegistry scopeRegistry; + private final WorkScheduler workScheduler; + private final RuntimeWireProcessor wireProcessor; + private final ProviderFactoryExtensionPoint providerFactories; + + private final RequestContextFactory requestContextFactory; + private final ProxyFactory proxyFactory; + private final JavaInterfaceFactory javaInterfaceFactory; + private final ConversationManager conversationManager; + + private final ComponentContextHelper componentContextHelper; + + private Composite domainComposite; + + /** + * @param assemblyFactory + * @param interfaceContractMapper + * @param workScheduler + * @param conversationManager TODO + * @param workContext + * @param wirePostProcessorRegistry + */ + public CompositeActivatorImpl(AssemblyFactory assemblyFactory, + MessageFactory messageFactory, + JavaInterfaceFactory javaInterfaceFactory, + SCABindingFactory scaBindingFactory, + InterfaceContractMapper interfaceContractMapper, + ScopeRegistry scopeRegistry, + WorkScheduler workScheduler, + RuntimeWireProcessor wireProcessor, + RequestContextFactory requestContextFactory, + ProxyFactory proxyFactory, + ProviderFactoryExtensionPoint providerFactories, + StAXArtifactProcessorExtensionPoint processors, + ConversationManager conversationManager) { + this.assemblyFactory = assemblyFactory; + this.messageFactory = messageFactory; + this.interfaceContractMapper = interfaceContractMapper; + this.scopeRegistry = scopeRegistry; + this.workScheduler = workScheduler; + this.wireProcessor = wireProcessor; + this.providerFactories = providerFactories; + this.javaInterfaceFactory = javaInterfaceFactory; + this.requestContextFactory = requestContextFactory; + this.proxyFactory = proxyFactory; + this.conversationManager = conversationManager; + this.componentContextHelper = new ComponentContextHelper(assemblyFactory, javaInterfaceFactory, processors); + } + + /** + * @see org.apache.tuscany.sca.core.assembly.CompositeActivator#activate(org.apache.tuscany.sca.runtime.RuntimeComponent, org.apache.tuscany.sca.runtime.RuntimeComponentReference) + */ + public void activate(RuntimeComponent component, RuntimeComponentReference ref) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating component reference: " + component.getURI() + "#" + ref.getName()); + } + resolveTargets(ref); + for (Binding binding : ref.getBindings()) { + addReferenceBindingProvider(component, ref, binding); + } + } + + public void start(RuntimeComponent component, RuntimeComponentReference ref) { + synchronized (ref) { + resolveTargets(ref); + for (Binding binding : ref.getBindings()) { + ReferenceBindingProvider provider = ref.getBindingProvider(binding); + if (provider == null) { + provider = addReferenceBindingProvider(component, ref, binding); + } + if (provider != null) { + provider.start(); + } + addReferenceWire(component, ref, binding); + } + } + } + + public void deactivate(RuntimeComponent component, RuntimeComponentReference ref) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating component reference: " + component.getURI() + "#" + ref.getName()); + } + removeReferenceWires(ref); + for (Binding binding : ref.getBindings()) { + removeReferenceBindingProvider(component, ref, binding); + } + + } + + /** + * @param component + * @param reference + * @param binding + */ + private ReferenceBindingProvider addReferenceBindingProvider(RuntimeComponent component, + RuntimeComponentReference reference, + Binding binding) { + BindingProviderFactory providerFactory = + (BindingProviderFactory)providerFactories.getProviderFactory(binding.getClass()); + if (providerFactory != null) { + @SuppressWarnings("unchecked") + ReferenceBindingProvider bindingProvider = + providerFactory.createReferenceBindingProvider((RuntimeComponent)component, + (RuntimeComponentReference)reference, + binding); + if (bindingProvider != null) { + ((RuntimeComponentReference)reference).setBindingProvider(binding, bindingProvider); + } + return bindingProvider; + } else { + throw new IllegalStateException("Provider factory not found for class: " + binding.getClass().getName()); + } + } + + /** + * @param reference + */ + private void resolveTargets(RuntimeComponentReference reference) { + // Support for distributed domain follows + + // go over any targets that have not been resolved yet (as they are running on other nodes) + // and try an resolve them remotely + // TODO - this should work for any kind of wired binding but the only wireable binding + // is currently the SCA binding so we assume that + for (ComponentService service : reference.getTargets()) { + if (service.isUnresolved()) { + for (Binding binding : service.getBindings()) { + // TODO - we should look at all the bindings now associated with the + // unresolved target but we assume the SCA binding here as + // its currently the only wireable one + if (binding instanceof OptimizableBinding) { + OptimizableBinding scaBinding = (OptimizableBinding)binding; + + // clone the SCA binding and fill in service details + // its cloned as each target + SCABinding clonedSCABinding = null; + try { + clonedSCABinding = (SCABinding)((OptimizableBinding)scaBinding).clone(); + clonedSCABinding.setURI(service.getName()); + // wireable binding stuff needs to go. SCA binding uses it + // currently to get to the service to work out if the service + // is resolved. + OptimizableBinding endpoint = ((OptimizableBinding)clonedSCABinding); + endpoint.setTargetComponentService(service); + //endpoint.setTargetComponent(component); - not known for unresolved target + //endpoint.setTargetBinding(serviceBinding); - not known for unresolved target + + // add the cloned SCA binding to the reference as it will be used to look up the + // provider later + reference.getBindings().remove(binding); + reference.getBindings().add(clonedSCABinding); + } catch (Exception e) { + // warning("The binding doesn't support clone: " + binding.getClass().getSimpleName(), binding); + } + } else { + throw new IllegalStateException( + "Unable to create a distributed SCA binding provider for reference: " + reference + .getName() + + " and target: " + + service.getName()); + } + } + } + } + } + + /** + * Create the runtime wires for a reference binding + * + * @param component + * @param reference + * @param binding + */ + private void addReferenceWire(Component component, ComponentReference reference, Binding binding) { + if (!(reference instanceof RuntimeComponentReference)) { + return; + } + + // create wire if binding has an endpoint + Component targetComponent = null; + ComponentService targetComponentService = null; + Binding targetBinding = null; + if (binding instanceof OptimizableBinding) { + OptimizableBinding endpoint = (OptimizableBinding)binding; + targetComponent = endpoint.getTargetComponent(); + targetComponentService = endpoint.getTargetComponentService(); + targetBinding = endpoint.getTargetBinding(); + } + + // create a forward wire, either static or dynamic + addReferenceWire(component, reference, binding, targetComponent, targetComponentService, targetBinding); + + /* + // if static forward wire (not from self-reference), try to create a static callback wire + if (targetComponentService != null && !reference.getName().startsWith("$self$.")) { + ComponentReference callbackReference = targetComponentService.getCallbackReference(); + if (callbackReference != null) { + Binding callbackBinding = null; + Binding callbackServiceBinding = null; + // select a service callback binding that can be wired back to this component + for (Binding refBinding : callbackReference.getBindings()) { + // first look for a callback binding whose name matches the target binding name + if (refBinding.getName().equals(targetBinding.getName())) { + callbackBinding = refBinding; + break; + } + } + // see if there is a matching reference callback binding + if (callbackBinding != null) { + callbackServiceBinding = reference.getCallbackService().getBinding(callbackBinding.getClass()); + } + // if there isn't an end-to-end match, try again based on target binding type + if (callbackBinding == null || callbackServiceBinding == null) { + callbackBinding = callbackReference.getBinding(targetBinding.getClass()); + if (callbackBinding != null) { + callbackServiceBinding = reference.getCallbackService().getBinding(callbackBinding.getClass()); + } + } + if (callbackBinding != null && callbackServiceBinding != null) { + // end-to-end match, so create a static callback wire as well as the static forward wire + + addReferenceWire(targetComponent, callbackReference, callbackBinding, component, reference + .getCallbackService(), callbackServiceBinding); + } else { + // no end-to-end match, so do not create a static callback wire + } + } + } + */ + } + + /** + * Create a reference wire for a forward call or a callback + * @param reference + * @param service + * @param serviceBinding + * @param component + * @param referenceBinding + */ + private RuntimeWire addReferenceWire(Component refComponent, + ComponentReference reference, + Binding refBinding, + Component serviceComponent, + ComponentService service, + Binding serviceBinding) { + RuntimeComponentReference runtimeRef = (RuntimeComponentReference)reference; + InterfaceContract bindingContract = getInterfaceContract(reference, refBinding); + + // Use the interface contract of the reference on the component type + Reference componentTypeRef = reference.getReference(); + InterfaceContract sourceContract = + componentTypeRef == null ? reference.getInterfaceContract() : componentTypeRef.getInterfaceContract(); + sourceContract = sourceContract.makeUnidirectional(false); + + EndpointReference wireSource = + new EndpointReferenceImpl((RuntimeComponent)refComponent, reference, refBinding, sourceContract); + ComponentService callbackService = reference.getCallbackService(); + if (callbackService != null) { + // select a reference callback binding to pass with invocations on this wire + Binding callbackBinding = null; + for (Binding binding : callbackService.getBindings()) { + // first look for a callback binding whose name matches the reference binding name + if (binding.getName().equals(refBinding.getName())) { + callbackBinding = binding; + break; + } + } + // if no callback binding found, try again based on reference binding type + if (callbackBinding == null) { + callbackBinding = callbackService.getBinding(refBinding.getClass()); + } + InterfaceContract callbackContract = callbackService.getInterfaceContract(); + EndpointReference callbackEndpoint = + new EndpointReferenceImpl((RuntimeComponent)refComponent, callbackService, callbackBinding, + callbackContract); + wireSource.setCallbackEndpoint(callbackEndpoint); + } + + EndpointReference wireTarget = + new EndpointReferenceImpl((RuntimeComponent)serviceComponent, service, serviceBinding, bindingContract); + + RuntimeWire wire = + new RuntimeWireImpl(wireSource, wireTarget, interfaceContractMapper, workScheduler, wireProcessor, + messageFactory, conversationManager); + runtimeRef.getRuntimeWires().add(wire); + + return wire; + } + + private void addImplementationProvider(RuntimeComponent component, Implementation implementation) { + ImplementationProviderFactory providerFactory = + (ImplementationProviderFactory)providerFactories.getProviderFactory(implementation.getClass()); + if (providerFactory != null) { + @SuppressWarnings("unchecked") + ImplementationProvider implementationProvider = + providerFactory.createImplementationProvider(component, implementation); + if (implementationProvider != null) { + component.setImplementationProvider(implementationProvider); + } + } else { + throw new IllegalStateException("Provider factory not found for class: " + implementation.getClass() + .getName()); + } + } + + private void removeImplementationProvider(RuntimeComponent component) { + component.setImplementationProvider(null); + } + + /** + * @param component + * @param service + * @param binding + */ + private ServiceBindingProvider addServiceBindingProvider(RuntimeComponent component, + RuntimeComponentService service, + Binding binding) { + BindingProviderFactory providerFactory = + (BindingProviderFactory)providerFactories.getProviderFactory(binding.getClass()); + if (providerFactory != null) { + @SuppressWarnings("unchecked") + ServiceBindingProvider bindingProvider = + providerFactory.createServiceBindingProvider((RuntimeComponent)component, + (RuntimeComponentService)service, + binding); + if (bindingProvider != null) { + ((RuntimeComponentService)service).setBindingProvider(binding, bindingProvider); + } + return bindingProvider; + } else { + throw new IllegalStateException("Provider factory not found for class: " + binding.getClass().getName()); + } + } + + private void removeServiceBindingProvider(RuntimeComponent component, + RuntimeComponentService service, + Binding binding) { + service.setBindingProvider(binding, null); + } + + private void removeReferenceBindingProvider(RuntimeComponent component, + RuntimeComponentReference reference, + Binding binding) { + reference.setBindingProvider(binding, null); + } + + public void start(Composite composite) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting composite: " + composite.getName()); + } + for (Component component : composite.getComponents()) { + start(component); + } + } + + public void stop(Composite composite) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping composite: " + composite.getName()); + } + for (Component component : composite.getComponents()) { + stop(component); + } + } + + public void start(Component component) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting component: " + component.getURI()); + } + RuntimeComponent runtimeComponent = ((RuntimeComponent)component); + configureComponentContext(runtimeComponent); + + for (ComponentReference reference : component.getReferences()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting component reference: " + component.getURI() + "#" + reference.getName()); + } + RuntimeComponentReference runtimeRef = ((RuntimeComponentReference)reference); + runtimeRef.setComponent(runtimeComponent); + for (Binding binding : reference.getBindings()) { + ReferenceBindingProvider bindingProvider = runtimeRef.getBindingProvider(binding); + if (bindingProvider != null) { + bindingProvider.start(); + } + } + } + + for (ComponentService service : component.getServices()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting component service: " + component.getURI() + "#" + service.getName()); + } + RuntimeComponentService runtimeService = (RuntimeComponentService)service; + for (Binding binding : service.getBindings()) { + ServiceBindingProvider bindingProvider = runtimeService.getBindingProvider(binding); + if (bindingProvider != null) { + bindingProvider.start(); + } + } + } + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + start((Composite)implementation); + } else { + ImplementationProvider implementationProvider = runtimeComponent.getImplementationProvider(); + if (implementationProvider != null) { + implementationProvider.start(); + } + } + + if (component instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent scopedRuntimeComponent = (ScopedRuntimeComponent)component; + if (scopedRuntimeComponent.getScopeContainer() != null) { + scopedRuntimeComponent.getScopeContainer().start(); + } + } + + runtimeComponent.setStarted(true); + } + + /** + * @param runtimeComponent + */ + public void configureComponentContext(RuntimeComponent runtimeComponent) { + RuntimeComponentContext componentContext = + new ComponentContextImpl(this, assemblyFactory, proxyFactory, interfaceContractMapper, + requestContextFactory, javaInterfaceFactory, runtimeComponent); + runtimeComponent.setComponentContext(componentContext); + } + + /** + * Stop a component + */ + public void stop(Component component) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping component: " + component.getURI()); + } + for (ComponentService service : component.getServices()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Stopping component service: " + component.getURI() + "#" + service.getName()); + } + for (Binding binding : service.getBindings()) { + ServiceBindingProvider bindingProvider = ((RuntimeComponentService)service).getBindingProvider(binding); + if (bindingProvider != null) { + bindingProvider.stop(); + } + } + } + for (ComponentReference reference : component.getReferences()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Starting component reference: " + component.getURI() + "#" + reference.getName()); + } + RuntimeComponentReference runtimeRef = ((RuntimeComponentReference)reference); + for (Binding binding : reference.getBindings()) { + ReferenceBindingProvider bindingProvider = runtimeRef.getBindingProvider(binding); + if (bindingProvider != null) { + bindingProvider.stop(); + } + } + } + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + stop((Composite)implementation); + } else { + ImplementationProvider implementationProvider = ((RuntimeComponent)component).getImplementationProvider(); + if (implementationProvider != null) { + implementationProvider.stop(); + } + } + + if (component instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component; + if (runtimeComponent.getScopeContainer() != null) { + runtimeComponent.getScopeContainer().stop(); + } + } + + ((RuntimeComponent)component).setStarted(false); + } + + /** + * Get the effective interface contract for a reference binding + * + * @param reference + * @param binding + * @return + */ + private InterfaceContract getInterfaceContract(ComponentReference reference, Binding binding) { + InterfaceContract interfaceContract = reference.getInterfaceContract(); + ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding); + if (provider != null) { + InterfaceContract bindingContract = provider.getBindingInterfaceContract(); + if (bindingContract != null) { + interfaceContract = bindingContract; + } + } + return interfaceContract.makeUnidirectional(false); + } + + /** + * Remove the runtime wires for a reference binding + * @param reference + */ + private void removeReferenceWires(ComponentReference reference) { + if (!(reference instanceof RuntimeComponentReference)) { + return; + } + // [rfeng] Comment out the following statements to avoid the on-demand activation + // RuntimeComponentReference runtimeRef = (RuntimeComponentReference)reference; + // runtimeRef.getRuntimeWires().clear(); + } + + /** + * Get the effective interface contract for the service binding + * + * @param service + * @param binding + * @return + */ + private InterfaceContract getInterfaceContract(ComponentService service, Binding binding) { + InterfaceContract interfaceContract = service.getInterfaceContract(); + + ServiceBindingProvider provider = ((RuntimeComponentService)service).getBindingProvider(binding); + if (provider != null) { + InterfaceContract bindingContract = provider.getBindingInterfaceContract(); + if (bindingContract != null) { + interfaceContract = bindingContract; + } + } + return interfaceContract.makeUnidirectional(false); + } + + /** + * Remove runtime wires for a service binding + * + * @param component + * @param service + */ + private void removeServiceWires(ComponentService service) { + if (!(service instanceof RuntimeComponentService)) { + return; + } + RuntimeComponentService runtimeService = (RuntimeComponentService)service; + runtimeService.getRuntimeWires().clear(); + } + + /** + * Create a service wire for a forward call or a callback + * @param service + * @param serviceBinding + * @param reference + * @param component + * @param referenceBinding + */ + private RuntimeWire addServiceWire(Component serviceComponent, ComponentService service, Binding serviceBinding) { + if (!(service instanceof RuntimeComponentService)) { + return null; + } + RuntimeComponentService runtimeService = (RuntimeComponentService)service; + + // FIXME: [rfeng] We might need a better way to get the impl interface contract + Service targetService = service.getService(); + if (targetService == null) { + targetService = service; + } + InterfaceContract targetContract = targetService.getInterfaceContract().makeUnidirectional(false); + + InterfaceContract sourceContract = getInterfaceContract(service, serviceBinding); + + EndpointReference wireSource = new EndpointReferenceImpl(null, null, serviceBinding, sourceContract); + + EndpointReference wireTarget = + new EndpointReferenceImpl((RuntimeComponent)serviceComponent, (RuntimeComponentService)service, + serviceBinding, targetContract); + + RuntimeWire wire = + new RuntimeWireImpl(wireSource, wireTarget, interfaceContractMapper, workScheduler, wireProcessor, + messageFactory, conversationManager); + runtimeService.getRuntimeWires().add(wire); + + return wire; + } + + public void activate(RuntimeComponent component, RuntimeComponentService service) { + if (service.getService() == null) { + if (logger.isLoggable(Level.WARNING)) { + logger.warning("Skipping component service not defined in the component type: " + component.getURI() + + "#" + + service.getName()); + } + return; + } + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating component service: " + component.getURI() + "#" + service.getName()); + } + + for (Binding binding : service.getBindings()) { + addServiceBindingProvider(component, service, binding); + addServiceWire(component, service, binding); + } + } + + public void deactivate(RuntimeComponent component, RuntimeComponentService service) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating component service: " + component.getURI() + "#" + service.getName()); + } + removeServiceWires(service); + for (Binding binding : service.getBindings()) { + removeServiceBindingProvider(component, service, binding); + } + } + + private void addScopeContainer(Component component) { + if (!(component instanceof ScopedRuntimeComponent)) { + return; + } + ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component; + ScopeContainer scopeContainer = scopeRegistry.getScopeContainer(runtimeComponent); + if (scopeContainer != null && scopeContainer.getScope() == Scope.CONVERSATION) { + conversationManager.addListener((ConversationalScopeContainer)scopeContainer); + } + runtimeComponent.setScopeContainer(scopeContainer); + } + + private void removeScopeContainer(Component component) { + if (!(component instanceof ScopedRuntimeComponent)) { + return; + } + ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component; + ScopeContainer scopeContainer = runtimeComponent.getScopeContainer(); + if(scopeContainer != null && scopeContainer.getScope() == Scope.CONVERSATION) { + conversationManager.removeListener((ConversationalScopeContainer) scopeContainer); + } + runtimeComponent.setScopeContainer(null); + } + + public void activate(Composite composite) throws ActivationException { + try { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating composite: " + composite.getName()); + } + for (Component component : composite.getComponents()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Activating component: " + component.getURI()); + } + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + activate((Composite)implementation); + } else if (implementation != null) { + addImplementationProvider((RuntimeComponent)component, implementation); + addScopeContainer(component); + } + + for (ComponentService service : component.getServices()) { + activate((RuntimeComponent)component, (RuntimeComponentService)service); + } + + for (ComponentReference reference : component.getReferences()) { + activate((RuntimeComponent)component, (RuntimeComponentReference)reference); + } + } + } catch (Exception e) { + throw new ActivationException(e); + } + } + + public void deactivate(Composite composite) throws ActivationException { + try { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating composite: " + composite.getName()); + } + for (Component component : composite.getComponents()) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Deactivating component: " + component.getURI()); + } + for (ComponentService service : component.getServices()) { + deactivate((RuntimeComponent)component, (RuntimeComponentService)service); + } + + for (ComponentReference reference : component.getReferences()) { + deactivate((RuntimeComponent)component, (RuntimeComponentReference)reference); + } + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + deactivate((Composite)implementation); + } else if (implementation != null) { + removeImplementationProvider((RuntimeComponent)component); + removeScopeContainer(component); + } + } + } catch (Exception e) { + throw new ActivationException(e); + } + } + + /** + * @return the referenceHelper + */ + public ComponentContextHelper getComponentContextHelper() { + return componentContextHelper; + } + + /** + * @return the proxyFactory + */ + public ProxyFactory getProxyFactory() { + return proxyFactory; + } + + /** + * @return the domainComposite + */ + public Composite getDomainComposite() { + return domainComposite; + } + + /** + * @param domainComposite the domainComposite to set + */ + public void setDomainComposite(Composite domainComposite) { + this.domainComposite = domainComposite; + } + + public Component resolve(String componentURI) { + for (Composite composite : domainComposite.getIncludes()) { + Component component = resolve(composite, componentURI); + if (component != null) { + return component; + } + } + return null; + } + + public Component resolve(Composite composite, String componentURI) { + String prefix = componentURI + "/"; + for (Component component : composite.getComponents()) { + String uri = component.getURI(); + if (uri.equals(componentURI)) { + return component; + } + if (componentURI.startsWith(prefix)) { + Implementation implementation = component.getImplementation(); + if (!(implementation instanceof Composite)) { + return null; + } + return resolve((Composite)implementation, componentURI); + } + } + return null; + } + + /** + * @return the javaInterfaceFactory + */ + public JavaInterfaceFactory getJavaInterfaceFactory() { + return javaInterfaceFactory; + } + + /** + * @return the conversationManager + */ + public ConversationManager getConversationManager() { + return conversationManager; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/EndpointReferenceImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/EndpointReferenceImpl.java new file mode 100644 index 0000000000..d3aebcf97a --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/EndpointReferenceImpl.java @@ -0,0 +1,184 @@ +/* + * 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.core.assembly; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * @version $Rev$ $Date$ + */ +public class EndpointReferenceImpl implements EndpointReference { + private RuntimeComponent component; + private Contract contract; + private Binding binding; + private InterfaceContract interfaceContract; + private String uri; + private EndpointReference callbackEndpoint; + private ReferenceParameters parameters = new ReferenceParametersImpl(); + + /** + * @param component + * @param contract + * @param binding + * @param interfaceContract + */ + public EndpointReferenceImpl(RuntimeComponent component, + Contract contract, + Binding binding, + InterfaceContract interfaceContract) { + super(); + this.component = component; + this.contract = contract; + this.binding = binding; + this.interfaceContract = interfaceContract; + this.uri = (component != null ? component.getURI() : "") + '/' + + (contract != null ? contract.getName() : ""); + } + + /** + * @param uri + */ + public EndpointReferenceImpl(String uri) { + super(); + this.uri = uri; + } + + public Binding getBinding() { + return binding; + } + + public void setBinding(Binding binding) { + this.binding = binding; + } + + public RuntimeComponent getComponent() { + return component; + } + + public void setComponent(RuntimeComponent component) { + this.component = component; + } + + public Contract getContract() { + return contract; + } + + public void setContract(Contract contract) { + this.contract = contract; + } + + public InterfaceContract getInterfaceContract() { + return interfaceContract; + } + + public void setInterfaceContract(InterfaceContract interfaceContract) { + this.interfaceContract = interfaceContract; + } + + public String getURI() { + return uri; + } + + public void setURI(String uri) { + this.uri = uri; + } + + public EndpointReference getCallbackEndpoint() { + return callbackEndpoint; + } + + public void setCallbackEndpoint(EndpointReference callbackEndpoint) { + this.callbackEndpoint = callbackEndpoint; + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((uri == null) ? 0 : uri.hashCode()); + 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 EndpointReferenceImpl other = (EndpointReferenceImpl)obj; + if (uri == null) { + if (other.uri != null) { + return false; + } + } else if (!uri.equals(other.uri)) { + return false; + } + return true; + } + + /** + * @see java.lang.Object#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + EndpointReferenceImpl copy = (EndpointReferenceImpl)super.clone(); + if (callbackEndpoint != null) { + copy.callbackEndpoint = (EndpointReference)callbackEndpoint.clone(); + } + if (parameters != null) { + copy.parameters = (ReferenceParameters)parameters.clone(); + } + return copy; + } + + /** + * @return the parameters + */ + public ReferenceParameters getReferenceParameters() { + return parameters; + } + + /** + * @param parameters the parameters to set + */ + public void setReferenceParameters(ReferenceParameters parameters) { + this.parameters = parameters; + } + + public void mergeEndpoint(EndpointReference epr) { + this.component = epr.getComponent(); + this.contract = epr.getContract(); + this.binding = epr.getBinding(); + this.interfaceContract = epr.getInterfaceContract(); + this.uri = epr.getURI(); + this.callbackEndpoint = epr.getCallbackEndpoint(); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ReferenceParameterProcessor.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ReferenceParameterProcessor.java new file mode 100644 index 0000000000..555eb43e4c --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ReferenceParameterProcessor.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.core.assembly; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.contribution.service.ContributionReadException; +import org.apache.tuscany.sca.contribution.service.ContributionResolveException; +import org.apache.tuscany.sca.contribution.service.ContributionWriteException; +import org.apache.tuscany.sca.runtime.ReferenceParameters; + +/** + * @version $Rev$ $Date$ + */ +public class ReferenceParameterProcessor implements StAXArtifactProcessor<ReferenceParameters> { + private final static QName REFERENCE_PARAMETERS = + new QName("http://tuscany.apache.org/xmlns/sca/1.0", "referenceParameters", "tuscany"); + + /** + * @see org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor#getArtifactType() + */ + public QName getArtifactType() { + return REFERENCE_PARAMETERS; + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor#read(javax.xml.stream.XMLStreamReader) + */ + public ReferenceParameters read(XMLStreamReader reader) throws ContributionReadException, XMLStreamException { + ReferenceParameters parameters = new ReferenceParametersImpl(); + parameters.setConversationID(reader.getAttributeValue(null, "conversationID")); + parameters.setCallbackID(reader.getAttributeValue(null, "callbackID")); + return parameters; + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor#write(java.lang.Object, javax.xml.stream.XMLStreamWriter) + */ + public void write(ReferenceParameters model, XMLStreamWriter writer) throws ContributionWriteException, + XMLStreamException { + writer.writeStartElement(REFERENCE_PARAMETERS.getPrefix(), + REFERENCE_PARAMETERS.getLocalPart(), + REFERENCE_PARAMETERS.getNamespaceURI()); + writer.writeNamespace(REFERENCE_PARAMETERS.getPrefix(), REFERENCE_PARAMETERS.getNamespaceURI()); + if (model.getConversationID() != null) { + writer.writeAttribute("conversationID", model.getConversationID().toString()); + } + if (model.getCallbackID() != null) { + writer.writeAttribute("callbackID", model.getCallbackID().toString()); + } + writer.writeEndElement(); + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.ArtifactProcessor#getModelType() + */ + public Class<ReferenceParameters> getModelType() { + return ReferenceParameters.class; + } + + /** + * @see org.apache.tuscany.sca.contribution.processor.ArtifactProcessor#resolve(java.lang.Object, org.apache.tuscany.sca.contribution.resolver.ModelResolver) + */ + public void resolve(ReferenceParameters model, ModelResolver resolver) throws ContributionResolveException { + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ReferenceParametersImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ReferenceParametersImpl.java new file mode 100644 index 0000000000..14a5f565fc --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/ReferenceParametersImpl.java @@ -0,0 +1,139 @@ +/* + * 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.core.assembly; + +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; + +/** + * @version $Rev$ $Date$ + */ +public class ReferenceParametersImpl implements ReferenceParameters { + private Object callbackID; + private Object conversationID; + private EndpointReference callbackReference; + private Object callbackObjectID; + + /** + * @return the callbackID + */ + public Object getCallbackID() { + return callbackID; + } + /** + * @param callbackID the callbackID to set + */ + public void setCallbackID(Object callbackID) { + this.callbackID = callbackID; + } + /** + * @return the conversationID + */ + public Object getConversationID() { + return conversationID; + } + /** + * @param conversationID the conversationID to set + */ + public void setConversationID(Object conversationID) { + this.conversationID = conversationID; + } + + /** + * @see org.apache.tuscany.sca.runtime.ReferenceParameters#getCallbackReference() + */ + public EndpointReference getCallbackReference() { + return callbackReference; + } + /** + * @see org.apache.tuscany.sca.runtime.ReferenceParameters#setCallback(java.lang.Object) + */ + public void setCallbackReference(EndpointReference callback) { + this.callbackReference = callback; + } + + /** + * @see java.lang.Object#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + /** + * @return the callbackObjectID + */ + public Object getCallbackObjectID() { + return callbackObjectID; + } + /** + * @param callbackObjectID the callbackObjectID to set + */ + public void setCallbackObjectID(Object callbackObjectID) { + this.callbackObjectID = callbackObjectID; + } + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((callbackID == null) ? 0 : callbackID.hashCode()); + result = prime * result + ((callbackObjectID == null) ? 0 : callbackObjectID.hashCode()); + result = prime * result + ((callbackReference == null) ? 0 : callbackReference.hashCode()); + result = prime * result + ((conversationID == null) ? 0 : conversationID.hashCode()); + return result; + } + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof ReferenceParametersImpl)) + return false; + final ReferenceParametersImpl other = (ReferenceParametersImpl)obj; + if (callbackID == null) { + if (other.callbackID != null) + return false; + } else if (!callbackID.equals(other.callbackID)) + return false; + if (callbackObjectID == null) { + if (other.callbackObjectID != null) + return false; + } else if (!callbackObjectID.equals(other.callbackObjectID)) + return false; + if (callbackReference == null) { + if (other.callbackReference != null) + return false; + } else if (!callbackReference.equals(other.callbackReference)) + return false; + if (conversationID == null) { + if (other.conversationID != null) + return false; + } else if (!conversationID.equals(other.conversationID)) + return false; + return true; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.java new file mode 100644 index 0000000000..b174dea6ce --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeAssemblyFactory.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.core.assembly; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.DefaultAssemblyFactory; + +/** + * The runtime version of assembly factory + * @version $Rev$ $Date$ + */ +public class RuntimeAssemblyFactory extends DefaultAssemblyFactory implements AssemblyFactory { + + public RuntimeAssemblyFactory() { + super(); + } + + @Override + public Component createComponent() { + return new RuntimeComponentImpl(); + } + + @Override + public ComponentReference createComponentReference() { + return new RuntimeComponentReferenceImpl(); + } + + @Override + public ComponentService createComponentService() { + return new RuntimeComponentServiceImpl(); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentImpl.java new file mode 100644 index 0000000000..e232ff63c6 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentImpl.java @@ -0,0 +1,81 @@ +/* + * 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.core.assembly; + +import org.apache.tuscany.sca.assembly.impl.ComponentImpl; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentContext; + +/** + * @version $Rev$ $Date$ + */ +public class RuntimeComponentImpl extends ComponentImpl implements RuntimeComponent, ScopedRuntimeComponent { + protected RuntimeComponentContext componentContext; + protected ImplementationProvider implementationProvider; + protected ScopeContainer scopeContainer; + protected boolean started; + + /** + */ + public RuntimeComponentImpl() { + super(); + } + + public ImplementationProvider getImplementationProvider() { + return implementationProvider; + } + + public void setImplementationProvider(ImplementationProvider provider) { + this.implementationProvider = provider; + } + + public ScopeContainer getScopeContainer() { + return scopeContainer; + } + + public void setScopeContainer(ScopeContainer scopeContainer) { + this.scopeContainer = scopeContainer; + } + + public boolean isStarted() { + return started; + } + + public void setStarted(boolean started) { + this.started = started; + } + + /** + * @return the componentContext + */ + public RuntimeComponentContext getComponentContext() { + return componentContext; + } + + /** + * @param componentContext the componentContext to set + */ + public void setComponentContext(RuntimeComponentContext componentContext) { + this.componentContext = componentContext; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentReferenceImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentReferenceImpl.java new file mode 100644 index 0000000000..c7def053ef --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentReferenceImpl.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.core.assembly; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.impl.ComponentReferenceImpl; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; + +public class RuntimeComponentReferenceImpl extends ComponentReferenceImpl implements RuntimeComponentReference { + private List<RuntimeWire> wires; + private Map<Binding, ReferenceBindingProvider> bindingProviders = new HashMap<Binding, ReferenceBindingProvider>(); + + private RuntimeComponent component; + public RuntimeComponentReferenceImpl() { + super(); + } + + public synchronized List<RuntimeWire> getRuntimeWires() { + if (wires == null) { + wires = new ArrayList<RuntimeWire>(); + component.getComponentContext().start(this); + } + return wires; + } + + public RuntimeWire getRuntimeWire(Binding binding) { + for (RuntimeWire wire : getRuntimeWires()) { + if (wire.getSource().getBinding() == binding) { + return wire; + } + } + return null; + } + + public ReferenceBindingProvider getBindingProvider(Binding binding) { + return bindingProviders.get(binding); + } + + public void setBindingProvider(Binding binding, ReferenceBindingProvider bindingProvider) { + bindingProviders.put(binding, bindingProvider); + } + + public Invoker getInvoker(Binding binding, Operation operation) { + RuntimeWire wire = getRuntimeWire(binding); + if (wire == null) { + return null; + } + InvocationChain chain = wire.getInvocationChain(operation); + return chain == null ? null : chain.getHeadInvoker(); + } + + /** + * @return the component + */ + public RuntimeComponent getComponent() { + return component; + } + + /** + * @param component the component to set + */ + public void setComponent(RuntimeComponent component) { + this.component = component; + } + + /** + * @see org.apache.tuscany.sca.assembly.impl.ComponentReferenceImpl#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeComponentReferenceImpl ref = (RuntimeComponentReferenceImpl) super.clone(); + ref.wires = null; + ref.bindingProviders = new HashMap<Binding, ReferenceBindingProvider>(); + return ref; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentServiceImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentServiceImpl.java new file mode 100644 index 0000000000..d3e722038e --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeComponentServiceImpl.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.core.assembly; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.impl.ComponentServiceImpl; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.ServiceRuntimeException; + +public class RuntimeComponentServiceImpl extends ComponentServiceImpl implements RuntimeComponentService { + private List<RuntimeWire> wires = new ArrayList<RuntimeWire>(); + private List<RuntimeWire> callbackWires = new ArrayList<RuntimeWire>(); + private Map<Binding, ServiceBindingProvider> bindingProviders = new HashMap<Binding, ServiceBindingProvider>(); + public RuntimeComponentServiceImpl() { + super(); + } + + public List<RuntimeWire> getRuntimeWires() { + return wires; + } + + public RuntimeWire getRuntimeWire(Binding binding) { + for (RuntimeWire wire : wires) { + if (wire.getTarget().getBinding() == binding) { + return wire; + } + } + return null; + } + + public List<RuntimeWire> getCallbackWires() { + return callbackWires; + } + + public ServiceBindingProvider getBindingProvider(Binding binding) { + return bindingProviders.get(binding); + } + + public void setBindingProvider(Binding binding, ServiceBindingProvider bindingProvider) { + bindingProviders.put(binding, bindingProvider); + } + + public Invoker getInvoker(Binding binding, Operation operation) { + return getInvoker(binding, null, operation); + } + + public Invoker getInvoker(Binding binding, InterfaceContract interfaceContract, Operation operation) { + InvocationChain chain = getInvocationChain(binding, interfaceContract, operation); + if (chain != null) { + return chain.getHeadInvoker(); + } else { + return null; + } + } + + public InvocationChain getInvocationChain(Binding binding, InterfaceContract interfaceContract, Operation operation) { + RuntimeWire wire = getRuntimeWire(binding); + if (wire == null) { + return null; + } + if (interfaceContract != null && interfaceContract != wire.getSource().getInterfaceContract()) { + try { + // FIXME: [rfeng] We could avoid clone() using a better comparison of the two interface contracts + wire = (RuntimeWire)wire.clone(); + wire.getSource().setInterfaceContract(interfaceContract); + wire.rebuild(); + } catch (CloneNotSupportedException e) { + throw new ServiceRuntimeException(e); + } + } + return wire.getInvocationChain(operation); + } + + public InvocationChain getInvocationChain(Binding binding, Operation operation) { + return getInvocationChain(binding, null, operation); + } + + /** + * @see org.apache.tuscany.sca.assembly.impl.ComponentServiceImpl#clone() + */ + @SuppressWarnings("unchecked") + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeComponentServiceImpl clone = (RuntimeComponentServiceImpl)super.clone(); + clone.bindingProviders = + (Map<Binding, ServiceBindingProvider>)((HashMap<Binding, ServiceBindingProvider>)bindingProviders).clone(); + clone.wires = (List<RuntimeWire>)((ArrayList<RuntimeWire>)wires).clone(); + clone.callbackWires = (List<RuntimeWire>)((ArrayList<RuntimeWire>)callbackWires).clone(); + return clone; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeWireImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeWireImpl.java new file mode 100644 index 0000000000..b47d6d43d5 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/assembly/RuntimeWireImpl.java @@ -0,0 +1,279 @@ +/* + * 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.core.assembly; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.core.conversation.ConversationManager; +import org.apache.tuscany.sca.core.invocation.InvocationChainImpl; +import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor; +import org.apache.tuscany.sca.core.invocation.RuntimeWireInvoker; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.osoa.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class RuntimeWireImpl implements RuntimeWire { + private EndpointReference wireSource; + private EndpointReference wireTarget; + + private transient RuntimeWireProcessor wireProcessor; + private transient InterfaceContractMapper interfaceContractMapper; + private transient WorkScheduler workScheduler; + private transient MessageFactory messageFactory; + private transient ConversationManager conversationManager; + private transient RuntimeWireInvoker invoker; + + private List<InvocationChain> chains; + + /** + * @param source + * @param target + * @param interfaceContractMapper + * @param workScheduler + * @param wireProcessor + * @param messageFactory + * @param conversationManager + */ + public RuntimeWireImpl(EndpointReference source, + EndpointReference target, + InterfaceContractMapper interfaceContractMapper, + WorkScheduler workScheduler, + RuntimeWireProcessor wireProcessor, + MessageFactory messageFactory, ConversationManager conversationManager) { + super(); + this.wireSource = source; + this.wireTarget = target; + this.interfaceContractMapper = interfaceContractMapper; + this.workScheduler = workScheduler; + this.wireProcessor = wireProcessor; + this.messageFactory = messageFactory; + this.conversationManager = conversationManager; + this.invoker = new RuntimeWireInvoker(this.messageFactory, this.conversationManager, this); + } + + public synchronized List<InvocationChain> getInvocationChains() { + if (chains == null) { + initInvocationChains(); + } + return chains; + } + + public InvocationChain getInvocationChain(Operation operation) { + for (InvocationChain chain : getInvocationChains()) { + Operation op = null; + if (wireSource.getContract() != null) { + // Reference chain + op = chain.getSourceOperation(); + } else { + // Service chain + op = chain.getTargetOperation(); + } + if (interfaceContractMapper.isCompatible(operation, op, op.getInterface().isRemotable())) { + return chain; + } + } + return null; + } + + public Object invoke(Operation operation, Object[] args) throws InvocationTargetException { + Message msg = messageFactory.createMessage(); + msg.setBody(args); + msg.setTo(wireTarget); + return invoker.invoke(operation, msg); + } + + public Object invoke(Operation operation, Message msg) throws InvocationTargetException { + return invoker.invoke(operation, msg); + } + + /** + * Initialize the invocation chains + */ + private void initInvocationChains() { + chains = new ArrayList<InvocationChain>(); + InterfaceContract sourceContract = wireSource.getInterfaceContract(); + InterfaceContract targetContract = wireTarget.getInterfaceContract(); + + Contract source = wireSource.getContract(); + if (source instanceof RuntimeComponentReference) { + // It's the reference wire + RuntimeComponentReference reference = (RuntimeComponentReference)wireSource.getContract(); + Binding refBinding = wireSource.getBinding(); + for (Operation operation : sourceContract.getInterface().getOperations()) { + Operation targetOperation = interfaceContractMapper.map(targetContract.getInterface(), operation); + if (targetOperation == null) { + throw new ServiceRuntimeException("No matching operation for " + operation.getName() + + " is found in reference " + + wireSource.getComponent().getURI() + + "#" + + reference.getName()); + } + InvocationChain chain = new InvocationChainImpl(operation, targetOperation); + if (operation.isNonBlocking()) { + addNonBlockingInterceptor(reference, refBinding, chain); + } + addBindingInterceptor(reference, refBinding, chain, operation); + chains.add(chain); + } + } else { + // It's the service wire + RuntimeComponentService service = (RuntimeComponentService)wireTarget.getContract(); + RuntimeComponent serviceComponent = wireTarget.getComponent(); + for (Operation operation : sourceContract.getInterface().getOperations()) { + Operation targetOperation = interfaceContractMapper.map(targetContract.getInterface(), operation); + if (targetOperation == null) { + throw new ServiceRuntimeException("No matching operation for " + operation.getName() + + " is found in service " + + serviceComponent.getURI() + + "#" + + service.getName()); + } + InvocationChain chain = new InvocationChainImpl(operation, targetOperation); + addImplementationInterceptor(serviceComponent, service, chain, targetOperation); + chains.add(chain); + } + } + wireProcessor.process(this); + } + + public EndpointReference getSource() { + return wireSource; + } + + public EndpointReference getTarget() { + return wireTarget; + } + + public void setTarget(EndpointReference target) { + if (this.wireTarget != target) { + rebuild(); + } + this.wireTarget = target; + } + + public void rebuild() { + this.chains = null; + } + + /** + * Add the interceptor for a binding + * + * @param reference + * @param binding + * @param chain + * @param operation + */ + private void addBindingInterceptor(ComponentReference reference, + Binding binding, + InvocationChain chain, + Operation operation) { + try { + ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding); + if (provider != null) { + Invoker invoker = provider.createInvoker(operation); + if (invoker != null) { + chain.addInvoker(invoker); + } + } + } catch (RuntimeException e) { + throw e; + } + } + + /** + * Add a non-blocking interceptor if the reference binding needs it + * + * @param reference + * @param binding + * @param chain + */ + private void addNonBlockingInterceptor(ComponentReference reference, Binding binding, InvocationChain chain) { + ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding); + if (provider != null) { + boolean supportsOneWayInvocation = provider.supportsOneWayInvocation(); + if (!supportsOneWayInvocation) { + chain.addInterceptor(new NonBlockingInterceptor(workScheduler)); + } + } + } + + /** + * Add the interceptor for a component implementation + * + * @param component + * @param service + * @param chain + * @param operation + */ + private void addImplementationInterceptor(Component component, + ComponentService service, + InvocationChain chain, + Operation operation) { + ImplementationProvider provider = ((RuntimeComponent)component).getImplementationProvider(); + if (provider != null) { + Invoker invoker = null; + invoker = provider.createInvoker((RuntimeComponentService)service, operation); + chain.addInvoker(invoker); + } + } + + /** + * @see java.lang.Object#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + RuntimeWireImpl copy = (RuntimeWireImpl)super.clone(); + copy.wireSource = (EndpointReference)wireSource.clone(); + copy.wireTarget = (EndpointReference)wireTarget.clone(); + copy.invoker = new RuntimeWireInvoker(copy.messageFactory, copy.conversationManager, copy); + return copy; + } + + /** + * @return the conversationManager + */ + public ConversationManager getConversationManager() { + return conversationManager; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/CallableReferenceImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/CallableReferenceImpl.java new file mode 100644 index 0000000000..d4f0962f07 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/CallableReferenceImpl.java @@ -0,0 +1,349 @@ +/* + * 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.core.context; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.UUID; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.OptimizableBinding; +import org.apache.tuscany.sca.core.assembly.CompositeActivator; +import org.apache.tuscany.sca.core.assembly.CompositeActivatorImpl; +import org.apache.tuscany.sca.core.assembly.EndpointReferenceImpl; +import org.apache.tuscany.sca.core.assembly.ReferenceParametersImpl; +import org.apache.tuscany.sca.core.conversation.ConversationManager; +import org.apache.tuscany.sca.core.conversation.ConversationState; +import org.apache.tuscany.sca.core.conversation.ExtendedConversation; +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; +import org.osoa.sca.Conversation; +import org.osoa.sca.ServiceRuntimeException; + +/** + * Base class for implementations of service and callback references. + * + * @version $Rev$ $Date$ + * @param <B> the type of the business interface + */ +public class CallableReferenceImpl<B> implements CallableReference<B>, Externalizable, ObjectFactory<B> { + protected transient CompositeActivator compositeActivator; + protected transient ProxyFactory proxyFactory; + + protected transient Class<B> businessInterface; + + // if the wire targets a conversational service this holds the conversation state + protected transient ConversationManager conversationManager; + protected transient ExtendedConversation conversation; + protected transient Object conversationID; + protected Object callbackID; // The callbackID should be serializable + + protected transient RuntimeComponent component; + protected transient RuntimeComponentReference reference; + protected transient Binding binding; + + protected String scdl; + + protected CallableReferenceImpl() { + super(); + } + + protected CallableReferenceImpl(Class<B> businessInterface, + RuntimeComponent component, + RuntimeComponentReference reference, + Binding binding, + ProxyFactory proxyFactory, + CompositeActivator compositeActivator) { + this.proxyFactory = proxyFactory; + this.businessInterface = businessInterface; + this.component = component; + this.reference = reference; + this.binding = binding; + // FIXME: The SCA spec is not clear how we should handle multiplicty for CallableReference + if (this.binding == null) { + this.binding = this.reference.getBinding(SCABinding.class); + if (this.binding == null) { + this.binding = this.reference.getBindings().get(0); + } + } + + // FIXME: Should we normalize the componentName/serviceName URI into an absolute SCA URI in the SCA binding? + // sca:component1/component11/component112/service1? + this.compositeActivator = compositeActivator; + this.conversationManager = this.compositeActivator.getConversationManager(); + RuntimeWire wire = this.reference.getRuntimeWire(this.binding); + init(wire); + } + + public CallableReferenceImpl(Class<B> businessInterface, RuntimeWire wire, ProxyFactory proxyFactory) { + this.proxyFactory = proxyFactory; + this.businessInterface = businessInterface; + bind(wire); + } + + public RuntimeWire getRuntimeWire() { + if (reference != null) { + return reference.getRuntimeWire(binding); + } else { + return null; + } + } + + protected void bind(RuntimeWire wire) { + if (wire != null) { + this.component = wire.getSource().getComponent(); + this.reference = (RuntimeComponentReference)wire.getSource().getContract(); + this.binding = wire.getSource().getBinding(); + this.compositeActivator = ((ComponentContextImpl)component.getComponentContext()).getCompositeActivator(); + this.conversationManager = this.compositeActivator.getConversationManager(); + init(wire); + } + } + + protected void init(RuntimeWire wire) { + EndpointReference target = wire.getTarget(); + + // look to see if the target is conversational and if so create a conversation + InterfaceContract contract = target.getInterfaceContract(); + if (contract == null) { + contract = reference.getInterfaceContract(); + } + Interface contractInterface = contract.getInterface(); + + if (contract.getCallbackInterface() != null) { + this.callbackID = createCallbackID(); + } + } + + public B getInstance() throws ObjectCreationException { + try { + resolve(); + //FIXME Can't we just return a single proxy + return businessInterface.cast(proxyFactory.createProxy(this)); + } catch (Exception e) { + throw new ObjectCreationException(e); + } + } + + public B getService() { + try { + return getInstance(); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public Class<B> getBusinessInterface() { + return businessInterface; + } + + public boolean isConversational() { + return reference == null ? false : reference.getInterfaceContract().getInterface().isConversational(); + } + + public Conversation getConversation() { + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + conversation = null; + } + return conversation; + } + + public Object getCallbackID() { + return callbackID; + } + + /** + * @see java.io.Externalizable#readExternal(java.io.ObjectInput) + */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + this.scdl = in.readUTF(); + } + + /** + * @throws IOException + */ + private synchronized void resolve() throws Exception { + if (scdl != null && component == null && reference == null) { + ComponentContextHelper componentContextHelper = ComponentContextHelper.getCurrentComponentContextHelper(); + if (componentContextHelper != null) { + CompositeActivator currentActivator = ComponentContextHelper.getCurrentCompositeActivator(); + this.compositeActivator = currentActivator; + this.conversationManager = this.compositeActivator.getConversationManager(); + Component c = componentContextHelper.fromXML(scdl); + this.component = (RuntimeComponent)c; + currentActivator.configureComponentContext(this.component); + this.reference = (RuntimeComponentReference)c.getReferences().get(0); + this.reference.setComponent(this.component); + ReferenceParameters parameters = null; + for (Object ext : reference.getExtensions()) { + if (ext instanceof ReferenceParameters) { + parameters = (ReferenceParameters)ext; + break; + } + } + if (parameters != null) { + this.callbackID = parameters.getCallbackID(); + this.conversationID = parameters.getConversationID(); + } + + for (Binding binding : reference.getBindings()) { + if (binding instanceof OptimizableBinding) { + String targetURI = binding.getURI(); + int index = targetURI.lastIndexOf('/'); + String serviceName = ""; + if (index > -1) { + serviceName = targetURI.substring(index + 1); + targetURI = targetURI.substring(0, index); + } + Component targetComponet = compositeActivator.resolve(targetURI); + ComponentService targetService = null; + if (targetComponet != null) { + if ("".equals(serviceName)) { + targetService = ComponentContextHelper.getSingleService(targetComponet); + } else { + for (ComponentService service : targetComponet.getServices()) { + if (service.getName().equals(serviceName)) { + targetService = service; + break; + } + } + } + } + OptimizableBinding optimizableBinding = (OptimizableBinding)binding; + optimizableBinding.setTargetComponent(targetComponet); + optimizableBinding.setTargetComponentService(targetService); + if (targetService != null) { + for (Binding serviceBinding : targetService.getBindings()) { + if (serviceBinding.getClass() == binding.getClass()) { + optimizableBinding.setTargetBinding(serviceBinding); + break; + } + } + } + } + } + // FIXME: The SCA spec is not clear how we should handle multiplicty for CallableReference + if (binding == null) { + binding = reference.getBinding(SCABinding.class); + if (binding == null) { + binding = reference.getBindings().get(0); + } + } + Interface i = reference.getInterfaceContract().getInterface(); + if (i instanceof JavaInterface) { + JavaInterface javaInterface = (JavaInterface)i; + if (javaInterface.isUnresolved()) { + javaInterface.setJavaClass(Thread.currentThread().getContextClassLoader() + .loadClass(javaInterface.getName())); + currentActivator.getJavaInterfaceFactory().createJavaInterface(javaInterface, + javaInterface.getJavaClass()); + } + this.businessInterface = (Class<B>)javaInterface.getJavaClass(); + } + this.proxyFactory = currentActivator.getProxyFactory(); + } + } + } + + /** + * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) + */ + public void writeExternal(ObjectOutput out) throws IOException { + try { + if (reference != null) { + ReferenceParameters parameters = new ReferenceParametersImpl(); + parameters.setCallbackID(callbackID); + if (conversationID != null) { + parameters.setConversationID(conversationID); + } else { + parameters.setConversationID(null); + } + reference.getExtensions().add(parameters); + scdl = + ((CompositeActivatorImpl)compositeActivator).getComponentContextHelper() + .toXML(component, reference); + reference.getExtensions().remove(parameters); + } + out.writeUTF(scdl); + } catch (Exception e) { + e.printStackTrace(); + throw new IOException(e.getMessage()); + } + } + + /** + * Create a callback id + * + * @return the callback id + */ + private String createCallbackID() { + return UUID.randomUUID().toString(); + } + + public void attachCallbackID(Object callbackID) { + this.callbackID = callbackID; + } + + public void attachConversationID(Object conversationID) { + this.conversationID = conversationID; + } + + public void attachConversation(ExtendedConversation conversation) { + this.conversation = conversation; + } + + + protected ReferenceParameters getReferenceParameters() { + ReferenceParameters parameters = new ReferenceParametersImpl(); + parameters.setCallbackID(callbackID); + if (getConversation() != null) { + parameters.setConversationID(conversation.getConversationID()); + } + return parameters; + } + + public EndpointReference getEndpointReference() { + // Use the interface contract of the reference on the component type + Reference componentTypeRef = reference.getReference(); + InterfaceContract sourceContract = + componentTypeRef == null ? reference.getInterfaceContract() : componentTypeRef.getInterfaceContract(); + sourceContract = sourceContract.makeUnidirectional(false); + EndpointReference epr = new EndpointReferenceImpl(component, reference, binding, sourceContract); + ReferenceParameters parameters = getReferenceParameters(); + epr.setReferenceParameters(parameters); + return epr; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ComponentContextHelper.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ComponentContextHelper.java new file mode 100644 index 0000000000..5bf70b2a0f --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ComponentContextHelper.java @@ -0,0 +1,295 @@ +/* + * 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.core.context; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.OptimizableBinding; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.assembly.CompositeActivator; +import org.apache.tuscany.sca.core.assembly.ReferenceParameterProcessor; +import org.apache.tuscany.sca.core.invocation.ThreadMessageContext; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.osoa.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class ComponentContextHelper { + + private final AssemblyFactory assemblyFactory; + private final JavaInterfaceFactory javaInterfaceFactory; + private final StAXArtifactProcessorExtensionPoint staxProcessors; + + /** + * @param assemblyFactory The factory to create assembly models + * @param processors The extension point for stax artifact processors + */ + public ComponentContextHelper(AssemblyFactory assemblyFactory, + JavaInterfaceFactory javaInterfaceFactory, + StAXArtifactProcessorExtensionPoint processors) { + this.assemblyFactory = assemblyFactory; + this.javaInterfaceFactory = javaInterfaceFactory; + this.staxProcessors = processors; + staxProcessors.addArtifactProcessor(new ReferenceParameterProcessor()); + } + + /** + * Create a self-reference for a component service + * @param component + * @param service + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + public ComponentReference createSelfReference(Component component, + ComponentService service, + Class<?> businessInterface) throws CloneNotSupportedException, + InvalidInterfaceException { + ComponentReference componentReference = assemblyFactory.createComponentReference(); + componentReference.setName("$self$." + service.getName()); + for (Binding binding : service.getBindings()) { + if (binding instanceof OptimizableBinding) { + OptimizableBinding optimizableBinding = (OptimizableBinding)((OptimizableBinding)binding).clone(); + optimizableBinding.setTargetBinding(binding); + optimizableBinding.setTargetComponent(component); + optimizableBinding.setTargetComponentService(service); + componentReference.getBindings().add(optimizableBinding); + } else { + componentReference.getBindings().add(binding); + } + } + + componentReference.setCallback(service.getCallback()); + componentReference.getTargets().add(service); + componentReference.getPolicySets().addAll(service.getPolicySets()); + componentReference.getRequiredIntents().addAll(service.getRequiredIntents()); + + InterfaceContract interfaceContract = service.getInterfaceContract(); + Service componentTypeService = service.getService(); + if (componentTypeService != null && componentTypeService.getInterfaceContract() != null) { + interfaceContract = componentTypeService.getInterfaceContract(); + } + interfaceContract = getInterfaceContract(interfaceContract, businessInterface); + componentReference.setInterfaceContract(interfaceContract); + componentReference.setMultiplicity(Multiplicity.ONE_ONE); + // component.getReferences().add(componentReference); + return componentReference; + } + + /** + * @param interfaceContract + * @param businessInterface + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + private InterfaceContract getInterfaceContract(InterfaceContract interfaceContract, Class<?> businessInterface) + throws CloneNotSupportedException, InvalidInterfaceException { + Interface interfaze = interfaceContract.getInterface(); + boolean compatible = false; + if (interfaze instanceof JavaInterface) { + Class<?> cls = ((JavaInterface)interfaze).getJavaClass(); + if (businessInterface.isAssignableFrom(cls)) { + compatible = true; + } + } + if (!compatible) { + // The interface is not assignable from the interface contract + interfaceContract = (InterfaceContract)interfaceContract.clone(); + interfaceContract.setInterface(javaInterfaceFactory.createJavaInterface(businessInterface)); + } + + return interfaceContract; + } + + /** + * Bind a component reference to a component service + * @param <B> + * @param businessInterface + * @param reference + * @param service + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + public RuntimeComponentReference bindComponentReference(Class<?> businessInterface, + RuntimeComponentReference reference, + RuntimeComponent component, + RuntimeComponentService service) + throws CloneNotSupportedException, InvalidInterfaceException { + RuntimeComponentReference ref = (RuntimeComponentReference)reference.clone(); + InterfaceContract interfaceContract = reference.getInterfaceContract(); + Reference componentTypeReference = reference.getReference(); + if (componentTypeReference != null && componentTypeReference.getInterfaceContract() != null) { + interfaceContract = componentTypeReference.getInterfaceContract(); + } + InterfaceContract refInterfaceContract = getInterfaceContract(interfaceContract, businessInterface); + if (refInterfaceContract != interfaceContract) { + ref = (RuntimeComponentReference)reference.clone(); + ref.setInterfaceContract(interfaceContract); + } + ref.setComponent(component); + ref.getTargets().add(service); + ref.getBindings().clear(); + for (Binding binding : service.getBindings()) { + if (binding instanceof OptimizableBinding) { + OptimizableBinding optimizableBinding = (OptimizableBinding)((OptimizableBinding)binding).clone(); + optimizableBinding.setTargetBinding(binding); + optimizableBinding.setTargetComponent(component); + optimizableBinding.setTargetComponentService(service); + ref.getBindings().add(optimizableBinding); + } else { + ref.getBindings().add(binding); + } + } + return ref; + } + + public void write(Component component, ComponentReference reference, Writer writer) throws IOException { + try { + StAXArtifactProcessor<Composite> processor = staxProcessors.getProcessor(Composite.class); + Composite composite = assemblyFactory.createComposite(); + composite.setName(new QName("http://tuscany.apache.org/xmlns/sca/1.0", "default")); + Component comp = assemblyFactory.createComponent(); + comp.setName("default"); + comp.setURI(component.getURI()); + composite.getComponents().add(comp); + comp.getReferences().add(reference); + + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer); + processor.write(composite, streamWriter); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + public String toXML(Component component, ComponentReference reference) throws IOException { + StringWriter writer = new StringWriter(); + write(component, reference, writer); + return writer.toString(); + } + + public RuntimeComponent read(Reader reader) throws IOException { + try { + StAXArtifactProcessor<Composite> processor = staxProcessors.getProcessor(Composite.class); + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(reader); + Composite composite = processor.read(streamReader); + RuntimeComponent component = (RuntimeComponent)composite.getComponents().get(0); + return component; + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + public Component fromXML(String xml) throws IOException { + return read(new StringReader(xml)); + } + + public static RuntimeComponent getCurrentComponent() { + Message message = ThreadMessageContext.getMessageContext(); + if (message != null) { + EndpointReference to = message.getTo(); + if (to == null) { + return null; + } + RuntimeComponent component = message.getTo().getComponent(); + return component; + } + return null; + } + + public static CompositeActivator getCurrentCompositeActivator() { + RuntimeComponent component = getCurrentComponent(); + if (component != null) { + ComponentContextImpl context = (ComponentContextImpl)component.getComponentContext(); + return context.getCompositeActivator(); + } + return null; + } + + public static ComponentContextHelper getCurrentComponentContextHelper() { + CompositeActivator activator = getCurrentCompositeActivator(); + if (activator != null) { + return activator.getComponentContextHelper(); + } + return null; + } + + /** + * @param component + */ + public static ComponentService getSingleService(Component component) { + ComponentService targetService; + List<ComponentService> services = component.getServices(); + List<ComponentService> regularServices = new ArrayList<ComponentService>(); + for (ComponentService service : services) { + if (service.isCallback()) { + continue; + } + String name = service.getName(); + if (!name.startsWith("$") || name.startsWith("$dynamic$")) { + regularServices.add(service); + } + } + if (regularServices.size() == 0) { + throw new ServiceRuntimeException("No service is declared on component " + component.getURI()); + } + if (regularServices.size() != 1) { + throw new ServiceRuntimeException("More than one service is declared on component " + component.getURI() + + ". Service name is required to get the service."); + } + targetService = regularServices.get(0); + return targetService; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ComponentContextImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ComponentContextImpl.java new file mode 100644 index 0000000000..4d48cbf6f2 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ComponentContextImpl.java @@ -0,0 +1,356 @@ +/* + * 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.core.context; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentProperty; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.OptimizableBinding; +import org.apache.tuscany.sca.context.RequestContextFactory; +import org.apache.tuscany.sca.core.assembly.CompositeActivator; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentContext; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.osoa.sca.CallableReference; +import org.osoa.sca.RequestContext; +import org.osoa.sca.ServiceReference; +import org.osoa.sca.ServiceRuntimeException; + +/** + * Implementation of ComponentContext that delegates to a ComponentContextProvider. + * + * @version $Rev$ $Date$ + */ +public class ComponentContextImpl implements RuntimeComponentContext { + private final RuntimeComponent component; + + private final CompositeActivator compositeActivator; + private final RequestContextFactory requestContextFactory; + private final ProxyFactory proxyFactory; + private final AssemblyFactory assemblyFactory; + private final JavaInterfaceFactory javaInterfaceFactory; + + public ComponentContextImpl(CompositeActivator compositeActivator, + AssemblyFactory assemblyFactory, + ProxyFactory proxyFactory, + InterfaceContractMapper interfaceContractMapper, + RequestContextFactory requestContextFactory, + JavaInterfaceFactory javaInterfaceFactory, + RuntimeComponent component) { + super(); + this.compositeActivator = compositeActivator; + this.assemblyFactory = assemblyFactory; + this.proxyFactory = proxyFactory; + this.requestContextFactory = requestContextFactory; + this.javaInterfaceFactory = javaInterfaceFactory; + this.component = component; + } + + public String getURI() { + return component.getURI(); + } + + public <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException { + return (R)proxyFactory.cast(target); + } + + public <B> B getService(Class<B> businessInterface, String referenceName) { + ServiceReference<B> serviceRef = getServiceReference(businessInterface, referenceName); + return serviceRef.getService(); + } + + public <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, String referenceName) { + try { + for (ComponentReference ref : component.getReferences()) { + if (referenceName.equals(ref.getName())) { + return getServiceReference(businessInterface, (RuntimeComponentReference)ref, null); + } + } + throw new ServiceRuntimeException("Reference not found: " + referenceName); + } catch (ServiceRuntimeException e) { + throw e; + } catch (Exception e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public <B> B getProperty(Class<B> type, String propertyName) { + for (ComponentProperty p : component.getProperties()) { + if (propertyName.equals(propertyName)) { + return type.cast(p.getValue()); + } + } + throw new ServiceRuntimeException("Property not found: " + propertyName); + } + + public <B> ServiceReference<B> createSelfReference(Class<B> businessInterface) { + ComponentService service = ComponentContextHelper.getSingleService(component); + try { + return createSelfReference(businessInterface, service); + } catch (Exception e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public <B> ServiceReference<B> createSelfReference(Class<B> businessInterface, String serviceName) { + try { + for (ComponentService service : component.getServices()) { + if (serviceName.equals(service.getName())) { + return createSelfReference(businessInterface, service); + } + } + throw new ServiceRuntimeException("Service not found: " + serviceName); + } catch (ServiceRuntimeException e) { + throw e; + } catch (Exception e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + /** + * @param <B> + * @param businessInterface + * @param service + * @return + */ + public <B> ServiceReference<B> createSelfReference(Class<B> businessInterface, ComponentService service) { + try { + RuntimeComponentReference ref = + (RuntimeComponentReference)createSelfReference(component, service, businessInterface); + ref.setComponent(component); + return getServiceReference(businessInterface, ref, null); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public RequestContext getRequestContext() { + if (requestContextFactory != null) { + return requestContextFactory.createRequestContext(); + } else { + return new RequestContextImpl(proxyFactory); + } + } + + /** + * @param businessInterface + * @param reference + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + public <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, RuntimeComponentReference reference, Binding binding) { + try { + RuntimeComponentReference ref = (RuntimeComponentReference)reference; + InterfaceContract interfaceContract = reference.getInterfaceContract(); + Reference componentTypeReference = reference.getReference(); + if (componentTypeReference != null && componentTypeReference.getInterfaceContract() != null) { + interfaceContract = componentTypeReference.getInterfaceContract(); + } + InterfaceContract refInterfaceContract = getInterfaceContract(interfaceContract, businessInterface); + if (refInterfaceContract != interfaceContract) { + ref = (RuntimeComponentReference)reference.clone(); + ref.setInterfaceContract(interfaceContract); + } + ref.setComponent(component); + return new ServiceReferenceImpl<B>(businessInterface, component, ref, binding, proxyFactory, compositeActivator); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * Bind a component reference to a component service + * @param <B> + * @param businessInterface + * @param reference + * @param service + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + public <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, + RuntimeComponentReference reference, + RuntimeComponent component, + RuntimeComponentService service) { + try { + RuntimeComponentReference ref = (RuntimeComponentReference)reference.clone(); + InterfaceContract interfaceContract = reference.getInterfaceContract(); + Reference componentTypeReference = reference.getReference(); + if (componentTypeReference != null && componentTypeReference.getInterfaceContract() != null) { + interfaceContract = componentTypeReference.getInterfaceContract(); + } + InterfaceContract refInterfaceContract = getInterfaceContract(interfaceContract, businessInterface); + if (refInterfaceContract != interfaceContract) { + ref = (RuntimeComponentReference)reference.clone(); + ref.setInterfaceContract(interfaceContract); + } + ref.getTargets().add(service); + ref.getBindings().clear(); + for (Binding binding : service.getBindings()) { + if (binding instanceof OptimizableBinding) { + OptimizableBinding optimizableBinding = (OptimizableBinding)((OptimizableBinding)binding).clone(); + optimizableBinding.setTargetBinding(binding); + optimizableBinding.setTargetComponent(component); + optimizableBinding.setTargetComponentService(service); + ref.getBindings().add(optimizableBinding); + } else { + ref.getBindings().add(binding); + } + } + return new ServiceReferenceImpl<B>(businessInterface, component, ref, proxyFactory, compositeActivator); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + public <B> CallableReference<B> getCallableReference(Class<B> businessInterface, + RuntimeComponent component, + RuntimeComponentService service) { + try { + if (businessInterface == null) { + InterfaceContract contract = service.getInterfaceContract(); + businessInterface = (Class<B>)((JavaInterface)contract.getInterface()).getJavaClass(); + } + RuntimeComponentReference ref = + (RuntimeComponentReference)createSelfReference(component, service, businessInterface); + ref.setComponent(component); + return new CallableReferenceImpl<B>(businessInterface, component, ref, null, proxyFactory, + compositeActivator); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * Create a self-reference for a component service + * @param component + * @param service + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + private ComponentReference createSelfReference(Component component, + ComponentService service, + Class<?> businessInterface) throws CloneNotSupportedException, + InvalidInterfaceException { + ComponentReference componentReference = assemblyFactory.createComponentReference(); + componentReference.setName("$self$." + service.getName()); + for (Binding binding : service.getBindings()) { + if (binding instanceof OptimizableBinding) { + OptimizableBinding optimizableBinding = (OptimizableBinding)((OptimizableBinding)binding).clone(); + optimizableBinding.setTargetBinding(binding); + optimizableBinding.setTargetComponent(component); + optimizableBinding.setTargetComponentService(service); + componentReference.getBindings().add(optimizableBinding); + } else { + componentReference.getBindings().add(binding); + } + } + + componentReference.setCallback(service.getCallback()); + componentReference.getTargets().add(service); + componentReference.getPolicySets().addAll(service.getPolicySets()); + componentReference.getRequiredIntents().addAll(service.getRequiredIntents()); + + InterfaceContract interfaceContract = service.getInterfaceContract(); + Service componentTypeService = service.getService(); + if (componentTypeService != null && componentTypeService.getInterfaceContract() != null) { + interfaceContract = componentTypeService.getInterfaceContract(); + } + interfaceContract = getInterfaceContract(interfaceContract, businessInterface); + componentReference.setInterfaceContract(interfaceContract); + componentReference.setMultiplicity(Multiplicity.ONE_ONE); + // component.getReferences().add(componentReference); + return componentReference; + } + + /** + * @param interfaceContract + * @param businessInterface + * @return + * @throws CloneNotSupportedException + * @throws InvalidInterfaceException + */ + private InterfaceContract getInterfaceContract(InterfaceContract interfaceContract, Class<?> businessInterface) + throws CloneNotSupportedException, InvalidInterfaceException { + Interface interfaze = interfaceContract.getInterface(); + boolean compatible = false; + if (interfaze instanceof JavaInterface) { + Class<?> cls = ((JavaInterface)interfaze).getJavaClass(); + if (businessInterface.isAssignableFrom(cls)) { + compatible = true; + } + } + if (!compatible) { + // The interface is not assignable from the interface contract + interfaceContract = (InterfaceContract)interfaceContract.clone(); + interfaceContract.setInterface(javaInterfaceFactory.createJavaInterface(businessInterface)); + } + + return interfaceContract; + } + + /** + * @return the compositeActivator + */ + public CompositeActivator getCompositeActivator() { + return compositeActivator; + } + + /** + * @see org.apache.tuscany.sca.runtime.RuntimeComponentContext#start(org.apache.tuscany.sca.runtime.RuntimeComponentReference) + */ + public void start(RuntimeComponentReference reference) { + compositeActivator.start(component, reference); + } + + /** + * @see org.apache.tuscany.sca.runtime.RuntimeComponentContext#read(java.io.Reader) + */ + public RuntimeComponent read(Reader reader) throws IOException { + RuntimeComponent component = compositeActivator.getComponentContextHelper().read(reader); + compositeActivator.configureComponentContext(component); + return component; + } + + /** + * @see org.apache.tuscany.sca.runtime.RuntimeComponentContext#write(org.apache.tuscany.sca.runtime.RuntimeComponentReference, java.io.Writer) + */ + public void write(RuntimeComponentReference reference, Writer writer) throws IOException { + compositeActivator.getComponentContextHelper().write(component, reference, writer); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.java new file mode 100644 index 0000000000..c5b68389b2 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/DefaultComponentContextFactory.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.core.context; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.context.ComponentContextFactory; +import org.apache.tuscany.sca.context.RequestContextFactory; +import org.apache.tuscany.sca.core.assembly.CompositeActivator; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.osoa.sca.ComponentContext; + +/** + * @version $Rev$ $Date$ + */ +public class DefaultComponentContextFactory implements ComponentContextFactory { + private final CompositeActivator compositeActivator; + private final RequestContextFactory requestContextFactory; + private final ProxyFactory proxyFactory; + private final AssemblyFactory assemblyFactory; + private final JavaInterfaceFactory javaInterfaceFactory; + private final InterfaceContractMapper interfaceContractMapper; + + public DefaultComponentContextFactory(CompositeActivator compositeActivator, + AssemblyFactory assemblyFactory, + ProxyFactory proxyFactory, + InterfaceContractMapper interfaceContractMapper, + RequestContextFactory requestContextFactory, + JavaInterfaceFactory javaInterfaceFactory) { + super(); + this.compositeActivator = compositeActivator; + this.assemblyFactory = assemblyFactory; + this.proxyFactory = proxyFactory; + this.requestContextFactory = requestContextFactory; + this.javaInterfaceFactory = javaInterfaceFactory; + this.interfaceContractMapper = interfaceContractMapper; + } + + /** + * @see org.apache.tuscany.sca.context.ComponentContextFactory#createComponentContext(org.apache.tuscany.sca.runtime.RuntimeComponent, org.apache.tuscany.sca.context.RequestContextFactory) + */ + public ComponentContext createComponentContext(RuntimeComponent component, + RequestContextFactory requestContextFactory) { + if (requestContextFactory == null) { + requestContextFactory = this.requestContextFactory; + } + return new ComponentContextImpl(compositeActivator, assemblyFactory, proxyFactory, interfaceContractMapper, + requestContextFactory, javaInterfaceFactory, component); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/InstanceWrapper.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/InstanceWrapper.java new file mode 100644 index 0000000000..b577180291 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/InstanceWrapper.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.core.context; + +import org.apache.tuscany.sca.core.scope.TargetDestructionException; +import org.apache.tuscany.sca.core.scope.TargetInitializationException; + + +/** + * Provides lifecycle management for an implementation instance associated with + * a component for use by the component's associated {@link org.apache.tuscany.sca.core.scope.ScopeContainer} + * + * @version $Rev$ $Date$ + */ +public interface InstanceWrapper<T> { + + /** + * @return + */ + T getInstance(); + + /** + * @throws TargetInitializationException + */ + void start() throws TargetInitializationException; + + /** + * @throws TargetDestructionException + */ + void stop() throws TargetDestructionException; + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/RequestContextImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/RequestContextImpl.java new file mode 100644 index 0000000000..7df1fa6166 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/RequestContextImpl.java @@ -0,0 +1,101 @@ +/* + * 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.core.context; + +import java.util.List; + +import javax.security.auth.Subject; + +import org.apache.tuscany.sca.core.invocation.CallbackWireObjectFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.core.invocation.ThreadMessageContext; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; +import org.osoa.sca.RequestContext; + +/** + * @version $Rev$ $Date$ + */ +public class RequestContextImpl implements RequestContext { + + private ProxyFactory proxyFactory; + + public RequestContextImpl(ProxyFactory proxyFactory) { + this.proxyFactory = proxyFactory; + } + + public Subject getSecuritySubject() { + throw new UnsupportedOperationException(); + } + + public String getServiceName() { + return ThreadMessageContext.getMessageContext().getTo().getContract().getName(); + } + + @SuppressWarnings("unchecked") + public <B> CallableReference<B> getServiceReference() { + Message msgContext = ThreadMessageContext.getMessageContext(); + // FIXME: [rfeng] Is this the service reference matching the caller side? + EndpointReference to = msgContext.getTo(); + RuntimeComponentService service = (RuntimeComponentService) to.getContract(); + RuntimeComponent component = (RuntimeComponent) to.getComponent(); + + CallableReference<B> callableReference = component.getComponentContext().getCallableReference(null, component, service); + ReferenceParameters parameters = msgContext.getTo().getReferenceParameters(); + ((CallableReferenceImpl<B>) callableReference).attachCallbackID(parameters.getCallbackID()); + if (callableReference.getConversation() != null) { + ((CallableReferenceImpl<B>) callableReference).attachConversationID(parameters.getConversationID()); + } + return callableReference; + } + + @SuppressWarnings("unchecked") + public <CB> CB getCallback() { + return (CB) getCallbackReference().getService(); + } + + @SuppressWarnings("unchecked") + public <CB> CallableReference<CB> getCallbackReference() { + Message msgContext = ThreadMessageContext.getMessageContext(); + EndpointReference to = msgContext.getTo(); + RuntimeComponentService service = (RuntimeComponentService) to.getContract(); + RuntimeComponentReference callbackReference = (RuntimeComponentReference)service.getCallbackReference(); + if (callbackReference == null) { + return null; + } + JavaInterface javaInterface = (JavaInterface) callbackReference.getInterfaceContract().getInterface(); + Class<CB> javaClass = (Class<CB>)javaInterface.getJavaClass(); + List<RuntimeWire> wires = callbackReference.getRuntimeWires(); + CallbackWireObjectFactory factory = new CallbackWireObjectFactory(javaClass, proxyFactory, wires); + factory.resolveTarget(); + ReferenceParameters parameters = msgContext.getTo().getReferenceParameters(); + factory.attachCallbackID(parameters.getCallbackID()); + if (factory.getConversation() != null) { + factory.attachConversationID(parameters.getConversationID()); + } + return factory; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceImpl.java new file mode 100644 index 0000000000..b2944b0ea7 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/context/ServiceReferenceImpl.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.core.context; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.core.assembly.CompositeActivator; +import org.apache.tuscany.sca.core.conversation.ConversationState; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; +import org.osoa.sca.ServiceReference; + +/** + * Default implementation of a ServiceReference. + * + * @version $Rev$ $Date$ + * @param <B> the type of the business interface + */ +public class ServiceReferenceImpl<B> extends CallableReferenceImpl<B> implements ServiceReference<B> { + private static final long serialVersionUID = 6763709434194361540L; + + protected transient Object callback; + + public ServiceReferenceImpl() { + super(); + } + + /** + * @param businessInterface + * @param wire + * @param proxyFactory + */ + public ServiceReferenceImpl(Class<B> businessInterface, RuntimeWire wire, ProxyFactory proxyFactory) { + super(businessInterface, wire, proxyFactory); + } + + public ServiceReferenceImpl(Class<B> businessInterface, + RuntimeComponent component, + RuntimeComponentReference reference, + ProxyFactory proxyFactory, + CompositeActivator compositeActivator) { + super(businessInterface, component, reference, null, proxyFactory, compositeActivator); + } + + public ServiceReferenceImpl(Class<B> businessInterface, + RuntimeComponent component, + RuntimeComponentReference reference, + Binding binding, + ProxyFactory proxyFactory, + CompositeActivator compositeActivator) { + super(businessInterface, component, reference, binding, proxyFactory, compositeActivator); + } + + public Object getConversationID() { + return conversationID; + } + + public void setConversationID(Object conversationID) throws IllegalStateException { + if (conversation == null || conversation.getState() != ConversationState.ENDED) { + this.conversationID = conversationID; + this.conversation = null; + } else { + throw new IllegalStateException("The state of the conversation " + conversation.getConversationID() + + " is " + + conversation.getState()); + } + } + + public void setCallbackID(Object callbackID) { + this.callbackID = callbackID; + } + + public Object getCallback() { + return callback; + } + + public void setCallback(Object callback) { + if (callback != null && !(callback instanceof CallableReference)) { + //FIXME: need to check if callback object supports the callback interface + // returned by reference.getInterfaceContract().getCallbackInterface() + } + this.callback = callback; + } + + protected ReferenceParameters getReferenceParameters() { + ReferenceParameters parameters = super.getReferenceParameters(); + if (callback != null) { + if (callback instanceof ServiceReference) { + EndpointReference callbackRef = ((CallableReferenceImpl)callback).getEndpointReference(); + parameters.setCallbackReference(callbackRef); + } else { + EndpointReference callbackRef = getRuntimeWire().getSource().getCallbackEndpoint(); + parameters.setCallbackReference(callbackRef); + parameters.setCallbackObjectID("java:" + System.identityHashCode(callback)); + } + } + return parameters; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationListener.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationListener.java new file mode 100644 index 0000000000..efa362a929 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationListener.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.core.conversation; + +/** + * Listener for the events of a conversation + * + * @version $Rev$ $Date$ + */ +public interface ConversationListener { + /** + * The conversation is started + */ + void conversationStarted(ExtendedConversation conversation); + /** + * The conversation is ended + */ + void conversationEnded(ExtendedConversation conversation); + /** + * The conversation is expired + */ + void conversationExpired(ExtendedConversation conversation); +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationManager.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationManager.java new file mode 100644 index 0000000000..97fa13ba46 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationManager.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.core.conversation; + +/** + * The manager of conversations + * + * @version $Rev$ $Date$ + */ +public interface ConversationManager { + /** + * @param conversationID + * @return + */ + ExtendedConversation startConversation(Object conversationID); + + /** + * @param conversationID + */ + void endConversation(Object conversationID); + + /** + * @param conversationID + * @return + */ + ExtendedConversation getConversation(Object conversationID); + + /** + * @param conversationID + */ + void expireConversation(Object conversationID); + + /** + * Add a listner to this conversation + * @param listener + */ + void addListener(ConversationListener listener); + + /** + * Remove a listener from this conversation + * @param listener + */ + void removeListener(ConversationListener listener); +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationManagerImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationManagerImpl.java new file mode 100644 index 0000000000..c053c9e4e8 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationManagerImpl.java @@ -0,0 +1,107 @@ +/* + * 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.core.conversation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * @version $Rev$ $Date$ + */ +public class ConversationManagerImpl implements ConversationManager { + private List<ConversationListener> listeners = Collections.synchronizedList(new ArrayList<ConversationListener>()); + private Map<Object, ExtendedConversation> converations = new ConcurrentHashMap<Object, ExtendedConversation>(); + + /** + * @see org.apache.tuscany.sca.core.conversation.ConversationManager#addListener(org.apache.tuscany.sca.core.conversation.ConversationListener) + */ + public void addListener(ConversationListener listener) { + listeners.add(listener); + } + + /** + * @see org.apache.tuscany.sca.core.conversation.ConversationManager#endConversation(org.apache.tuscany.sca.core.conversation.ExtendedConversation) + */ + public void endConversation(Object conversationID) { + ExtendedConversation conv = getConversation(conversationID); + if (conv != null) { + conv.setState(ConversationState.ENDED); + for (ConversationListener listener : listeners) { + listener.conversationEnded(conv); + } + conv.setConversationID(null); + converations.remove(conversationID); + } else { + throw new IllegalStateException("Conversation " + conversationID + " doesn't exist."); + } + } + + public void expireConversation(Object conversationID) { + ExtendedConversation conv = getConversation(conversationID); + if (conv != null) { + ((ExtendedConversationImpl)conv).setState(ConversationState.EXPIRED); + for (ConversationListener listener : listeners) { + listener.conversationExpired(conv); + } + } else { + throw new IllegalStateException("Conversation " + conversationID + " doesn't exist."); + } + + } + + /** + * @see org.apache.tuscany.sca.core.conversation.ConversationManager#getConversation(java.lang.Object) + */ + public ExtendedConversation getConversation(Object conversationID) { + return converations.get(conversationID); + } + + /** + * @see org.apache.tuscany.sca.core.conversation.ConversationManager#removeListener(org.apache.tuscany.sca.core.conversation.ConversationListener) + */ + public void removeListener(ConversationListener listener) { + listeners.remove(listener); + } + + /** + * @see org.apache.tuscany.sca.core.conversation.ConversationManager#startConversation(java.lang.Object) + */ + public ExtendedConversation startConversation(Object conversationID) { + if (conversationID == null) { + conversationID = UUID.randomUUID().toString(); + } + ExtendedConversation conversation = getConversation(conversationID); + if (conversation != null && conversation.getState() != ConversationState.ENDED) { + throw new IllegalStateException(conversation + " already exists."); + } + conversation = new ExtendedConversationImpl(this, conversationID, ConversationState.STARTED); + converations.put(conversationID, conversation); + for (ConversationListener listener : listeners) { + listener.conversationStarted(conversation); + } + return conversation; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationState.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationState.java new file mode 100644 index 0000000000..692d6861ba --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ConversationState.java @@ -0,0 +1,29 @@ +/* + * 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.core.conversation; + +/** + * The states of a conversation + * + * @version $Rev$ $Date$ + */ +public enum ConversationState { + STARTED, ENDED, EXPIRED +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ExtendedConversation.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ExtendedConversation.java new file mode 100644 index 0000000000..635b2d7cf5 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ExtendedConversation.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.core.conversation; + +import org.osoa.sca.Conversation; + +/** + * An extended interface over org.osoa.Conversation + * + * @version $Rev$ $Date$ + */ +public interface ExtendedConversation extends Conversation { + /** + * Get the state of a conversation + * @return The state + */ + ConversationState getState(); + + /** + * Mark the conversation expired + */ + void expire(); + + /** + * @param state the state to set + */ + public void setState(ConversationState state); + + /** + * @param conversationID the conversationID to set + */ + public void setConversationID(Object conversationID); +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ExtendedConversationImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ExtendedConversationImpl.java new file mode 100644 index 0000000000..256f9cc4ad --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/conversation/ExtendedConversationImpl.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.core.conversation; + + +/** + * + * @version $Rev$ $Date$ + */ +public class ExtendedConversationImpl implements ExtendedConversation { + private ConversationManager manager; + private Object conversationID; + private ConversationState state; + + /** + * @param manager + * @param conversationID + * @param state + */ + public ExtendedConversationImpl(ConversationManager manager, Object conversationID, ConversationState state) { + super(); + this.manager = manager; + this.conversationID = conversationID; + this.state = state; + } + + public void expire() { + manager.expireConversation(conversationID); + } + + public ConversationState getState() { + return state; + } + + public void end() { + manager.endConversation(conversationID); + } + + public Object getConversationID() { + return conversationID; + } + + /** + * @param state the state to set + */ + public void setState(ConversationState state) { + this.state = state; + } + + /** + * @param conversationID the conversationID to set + */ + public void setConversationID(Object conversationID) { + if (state != ConversationState.ENDED) { + throw new IllegalStateException("The state of conversation " + conversationID + " " + state); + } + this.conversationID = conversationID; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/BaseEventPublisher.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/BaseEventPublisher.java new file mode 100644 index 0000000000..517e5579a4 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/BaseEventPublisher.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.core.event; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.tuscany.sca.event.Event; +import org.apache.tuscany.sca.event.EventFilter; +import org.apache.tuscany.sca.event.EventPublisher; +import org.apache.tuscany.sca.event.RuntimeEventListener; +import org.apache.tuscany.sca.event.TrueFilter; + +/** + * Base implementation of an <code>EventPublisher</code> + * + * @version $Rev$ $Date$ + */ +public abstract class BaseEventPublisher implements EventPublisher { + protected static final EventFilter TRUE_FILTER = new TrueFilter(); + protected Map<EventFilter, List<RuntimeEventListener>> listeners; + + public void addListener(RuntimeEventListener listener) { + addListener(TRUE_FILTER, listener); + } + + public void removeListener(RuntimeEventListener listener) { + assert listener != null : "Listener cannot be null"; + synchronized (getListeners()) { + for (List<RuntimeEventListener> currentList : getListeners().values()) { + for (RuntimeEventListener current : currentList) { + if (current == listener) { + currentList.remove(current); + return; + } + } + } + } + } + + public void addListener(EventFilter filter, RuntimeEventListener listener) { + assert listener != null : "Listener cannot be null"; + synchronized (getListeners()) { + List<RuntimeEventListener> list = getListeners().get(filter); + if (list == null) { + list = new CopyOnWriteArrayList<RuntimeEventListener>(); + listeners.put(filter, list); + } + list.add(listener); + } + } + + public void publish(Event event) { + assert event != null : "Event object was null"; + for (Map.Entry<EventFilter, List<RuntimeEventListener>> entry : getListeners().entrySet()) { + if (entry.getKey().match(event)) { + for (RuntimeEventListener listener : entry.getValue()) { + listener.onEvent(event); + } + } + } + } + + protected Map<EventFilter, List<RuntimeEventListener>> getListeners() { + if (listeners == null) { + listeners = new ConcurrentHashMap<EventFilter, List<RuntimeEventListener>>(); + } + return listeners; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ComponentStart.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ComponentStart.java new file mode 100644 index 0000000000..8e90c953e5 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ComponentStart.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.event; + +import java.net.URI; + +import org.apache.tuscany.sca.event.Event; + +/** + * Propagated when a component starts + * + * @version $$Rev$$ $$Date$$ + */ +public class ComponentStart implements Event { + + private Object source; + private URI uri; + + /** + * Creates a component start event + * + * @param source the source of the event + * @param componentURI the uri of the component being started + */ + public ComponentStart(Object source, URI componentURI) { + this.source = source; + this.uri = componentURI; + } + + public URI getComponentURI() { + return uri; + } + + public Object getSource() { + return source; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ComponentStop.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ComponentStop.java new file mode 100644 index 0000000000..d879182e14 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ComponentStop.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.core.event; + +import java.net.URI; + +import org.apache.tuscany.sca.event.Event; + +/** + * Propagated when a component stops + * + * @version $$Rev$$ $$Date$$ + */ +public class ComponentStop implements Event { + + private Object source; + private URI uri; + + /** + * Creates a component stop event + * + * @param source the source of the event + * @param componentUri the composite component associated the component being stopped + */ + public ComponentStop(Object source, URI componentUri) { + this.source = source; + this.uri = componentUri; + } + + public URI getComponentURI() { + return uri; + } + + public Object getSource() { + return source; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ConversationEnd.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ConversationEnd.java new file mode 100644 index 0000000000..cd14710880 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ConversationEnd.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.core.event; + +import org.apache.tuscany.sca.event.Event; + + + +/** + * Propagated when a conversation is expired + * + * @version $$Rev$$ $$Date$$ + */ +public class ConversationEnd implements Event { + + private Object source; + private Object id; + + /** + * Creates a new event + * + * @param source the source of the event + * @param id the id of the conversation being ended + */ + public ConversationEnd(Object source, Object id) { + this.source = source; + this.id = id; + } + + public Object getSource() { + return source; + } + + public Object getConversationID() { + return id; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ConversationStart.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ConversationStart.java new file mode 100644 index 0000000000..a4cc49204e --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/ConversationStart.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.event; + +import org.apache.tuscany.sca.event.Event; + + +/** + * Propagated when a conversation has started + * + * @version $$Rev$$ $$Date$$ + */ +public class ConversationStart implements Event { + + private Object source; + private Object id; + + /** + * Creates a new event + * + * @param source the source of the event + * @param id the id of the conversation being started + */ + public ConversationStart(Object source, Object id) { + this.source = source; + this.id = id; + } + + public Object getSource() { + return source; + } + + public Object getConversationID() { + return id; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/HttpSessionEnd.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/HttpSessionEnd.java new file mode 100644 index 0000000000..4c3fd8b397 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/HttpSessionEnd.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.core.event; + +import org.apache.tuscany.sca.event.Event; + + + +/** + * Propagated when an HTTP-based session is expired + * + * @version $$Rev$$ $$Date$$ + */ +public class HttpSessionEnd implements Event { + + private Object source; + private Object id; + + /** + * Creates a new event + * + * @param source the source of the event + * @param id the id of the HTTP session being ended + */ + public HttpSessionEnd(Object source, Object id) { + this.source = source; + this.id = id; + } + + public Object getSource() { + return source; + } + + public Object getSessionID() { + return id; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/HttpSessionStart.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/HttpSessionStart.java new file mode 100644 index 0000000000..67b922b99c --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/HttpSessionStart.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.event; + +import org.apache.tuscany.sca.event.Event; + + +/** + * Propagated when an HTTP-based session has started + * + * @version $$Rev$$ $$Date$$ + */ +public class HttpSessionStart implements Event { + + private Object source; + private Object id; + + /** + * Creates a new event + * + * @param source the source of the event + * @param id the id of the HTTP session being started + */ + public HttpSessionStart(Object source, Object id) { + this.source = source; + this.id = id; + } + + public Object getSource() { + return source; + } + + public Object getSessionID() { + return id; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/RequestEnd.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/RequestEnd.java new file mode 100644 index 0000000000..8b5c512cf2 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/RequestEnd.java @@ -0,0 +1,45 @@ +/* + * 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.core.event; + +import org.apache.tuscany.sca.event.Event; + +/** + * Propagated when a request completes or is ended + * + * @version $$Rev$$ $$Date$$ + */ +public class RequestEnd implements Event { + + private Object source; + + /** + * Creates a new event + * + * @param source the source of the event + */ + public RequestEnd(Object source) { + this.source = source; + } + + public Object getSource() { + return source; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/RequestStart.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/RequestStart.java new file mode 100644 index 0000000000..974563b57c --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/event/RequestStart.java @@ -0,0 +1,45 @@ +/* + * 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.core.event; + +import org.apache.tuscany.sca.event.Event; + +/** + * Propagated when a request is started in the runtime + * + * @version $$Rev$$ $$Date$$ + */ +public class RequestStart implements Event { + + private Object source; + + /** + * Creates a new event + * + * @param source the source of the event + */ + public RequestStart(Object source) { + this.source = source; + } + + public Object getSource() { + return source; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java new file mode 100644 index 0000000000..d35b27fd24 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectCreationException.java @@ -0,0 +1,47 @@ +/* + * 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.core.factory; + + +/** + * Denotes an error creating a new object instance + * + * @version $Rev$ $Date$ + */ +public class ObjectCreationException extends RuntimeException { + private static final long serialVersionUID = -6423113430265944499L; + + public ObjectCreationException() { + super(); + } + + public ObjectCreationException(String message, Throwable cause) { + super(message, cause); + } + + public ObjectCreationException(String message) { + super(message); + } + + public ObjectCreationException(Throwable cause) { + super(cause); + } + +} + diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.java new file mode 100644 index 0000000000..3f64d2405b --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/factory/ObjectFactory.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.core.factory; + +/** + * Implementations create new instances of a particular type + * + * @version $Rev$ $Date$ + */ +public interface ObjectFactory<T> { + + /** + * Return a instance of the type that this factory creates. + * + * @return a instance from this factory + */ + T getInstance() throws ObjectCreationException; + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java new file mode 100644 index 0000000000..1ec007eacf --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.osoa.sca.CallableReference; + +/** + * Uses a wire to return a callable reference + * + * @version $Rev$ $Date$ + */ +public class CallableReferenceObjectFactory implements ObjectFactory<CallableReference<?>> { + private CallableReference<?> callableReference; + + /** + * Constructor. + * + * To support the @Reference protected CallableReference<MyService> ref; + * + * @param interfaze the interface to inject on the client + * @param wire the backing wire + * @param proxyService the wire service to create the proxy + * @throws NoMethodForOperationException + */ + public CallableReferenceObjectFactory(Class<?> businessInterface, + RuntimeComponent component, + RuntimeComponentReference reference, + Binding binding) { + this.callableReference = + component.getComponentContext().getServiceReference(businessInterface, reference, binding); + } + + public CallableReferenceObjectFactory(CallableReference<?> callableReference) { + this.callableReference = callableReference; + } + + public CallableReference<?> getInstance() throws ObjectCreationException { + return callableReference; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java new file mode 100644 index 0000000000..cd1f12a995 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.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.core.invocation; + +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.osoa.sca.NoRegisteredCallbackException; + +/** + * An interceptor applied to the forward direction of a wire that ensures the callback target implements the required + * service contract. This is required as callback targets may be set dynamically by service implementations. + * + * @version $Rev$ $Date$ + */ +public class CallbackInterfaceInterceptor implements Interceptor { + private Invoker next; + + public CallbackInterfaceInterceptor() { + } + + public Message invoke(Message msg) { + ReferenceParameters parameters = msg.getTo().getReferenceParameters(); + if (parameters.getCallbackObjectID() != null || parameters.getCallbackReference() != msg.getFrom() + .getCallbackEndpoint()) { + return next.invoke(msg); + } else { + throw new NoRegisteredCallbackException("Callback target does not implement the callback interface"); + } + } + + public void setNext(Invoker next) { + this.next = next; + } + + public Invoker getNext() { + return next; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java new file mode 100644 index 0000000000..8eb706446a --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.OptimizableBinding; +import org.apache.tuscany.sca.core.context.CallableReferenceImpl; +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.ServiceRuntimeException; + +/** + * Returns proxy instance for a wire callback + * + * @version $Rev$ $Date$ + */ +public class CallbackWireObjectFactory<B> extends CallableReferenceImpl<B> { + private RuntimeWire wire; + private List<RuntimeWire> wires; + private EndpointReference resolvedEndpoint; + + public CallbackWireObjectFactory(Class<B> interfaze, ProxyFactory proxyFactory, List<RuntimeWire> wires) { + super(interfaze, null, proxyFactory); + this.wires = wires; + } + + public void resolveTarget() { + Message msgContext = ThreadMessageContext.getMessageContext(); + wire = selectCallbackWire(msgContext); + if (wire == null) { + //FIXME: need better exception + throw new RuntimeException("No callback wire found for " + msgContext.getFrom().getURI()); + } + this.resolvedEndpoint = getCallbackEndpoint(msgContext); + bind(wire); + } + + @Override + public B getInstance() throws ObjectCreationException { + if (wire != null) { + // wire and endpoint already resolved, so return a pre-wired proxy + wire.setTarget(resolvedEndpoint); + wire.rebuild(); + return super.getInstance(); + } else { + // wire not yet selected, so return a proxy that resolves the target dynamically + return proxyFactory.createCallbackProxy(businessInterface, wires); + } + } + + public RuntimeWire selectCallbackWire(Message msgContext) { + EndpointReference callbackEPR = getCallbackEndpoint(msgContext); + if (callbackEPR == null) { + return null; + } + + //FIXME: need a cache for better performance. This requires making this + // method non-static, which means changing the signature of createCallbackProxy(). + + // first choice is wire with matching destination endpoint + for (RuntimeWire wire : wires) { + if (callbackEPR.getURI().equals(wire.getTarget().getURI())) { + try { + return (RuntimeWire)wire.clone(); + } catch (CloneNotSupportedException e) { + throw new ServiceRuntimeException(e); + } + } + } + + // no exact match, so find callback binding with same name as service binding + EndpointReference to = msgContext.getTo(); + if (to == null) { + //FIXME: need better exception + throw new RuntimeException("Destination for forward call is not available"); + } + for (RuntimeWire wire : wires) { + if (wire.getSource().getBinding().getName().equals(to.getBinding().getName())) { + //FIXME: need better way to represent dynamic wire + if (wire.getTarget().getURI().equals("/")) { // dynamic wire + //FIXME: avoid doing this for genuine dynamic wires + return cloneAndBind(msgContext, wire); + } + //FIXME: no dynamic wire, so should attempt to create a static wire + } + } + + // no match so far, so find callback binding with same type as service binding + for (RuntimeWire wire : wires) { + if (wire.getSource().getBinding().getClass() == to.getBinding().getClass()) { + //FIXME: need better way to represent dynamic wire + if (wire.getTarget().getURI().equals("/")) { // dynamic wire + //FIXME: avoid doing this for genuine dynamic wires + return cloneAndBind(msgContext, wire); + } + //FIXME: no dynamic wire, so should attempt to create a static wire + } + } + + // no suitable callback wire was found + return null; + } + + /** + * @param msgContext + */ + private static EndpointReference getCallbackEndpoint(Message msgContext) { + EndpointReference to = msgContext.getTo(); + if (to == null) { + return null; + } + return to.getReferenceParameters().getCallbackReference(); + } + + private static RuntimeWire cloneAndBind(Message msgContext, RuntimeWire wire) { + EndpointReference callback = getCallbackEndpoint(msgContext); + if (callback != null && callback.getContract() != null) { + try { + RuntimeComponentReference ref = null; + if (callback.getContract() instanceof RuntimeComponentReference) { + ref = (RuntimeComponentReference)callback.getContract(); + return ref.getRuntimeWire(callback.getBinding()); + } else { + ref = + bind((RuntimeComponentReference)wire.getSource().getContract(), + callback.getComponent(), + (RuntimeComponentService)callback.getContract()); + + return ref.getRuntimeWires().get(0); + } + } catch (CloneNotSupportedException e) { + // will not happen + return null; + } + } else { + return wire; + } + } + + private static RuntimeComponentReference bind(RuntimeComponentReference reference, + RuntimeComponent component, + RuntimeComponentService service) throws CloneNotSupportedException { + RuntimeComponentReference ref = (RuntimeComponentReference)reference.clone(); + ref.getTargets().add(service); + ref.getBindings().clear(); + for (Binding binding : service.getBindings()) { + if (binding instanceof OptimizableBinding) { + OptimizableBinding optimizableBinding = (OptimizableBinding)((OptimizableBinding)binding).clone(); + optimizableBinding.setTargetBinding(binding); + optimizableBinding.setTargetComponent(component); + optimizableBinding.setTargetComponentService(service); + ref.getBindings().add(optimizableBinding); + } else { + ref.getBindings().add(binding); + } + } + return ref; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java new file mode 100644 index 0000000000..e498717dbd --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java @@ -0,0 +1,139 @@ +/* + * 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.core.invocation; + +import java.lang.reflect.Method; +import java.util.List; + +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.Factory; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; + +import org.apache.tuscany.sca.core.context.ServiceReferenceImpl; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.impl.InterfaceContractMapperImpl; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; +import org.osoa.sca.ServiceReference; + +/** + * The implementation of a wire service that uses cglib dynamic proxies + * + * @version $Rev$ $Date$ + */ +@SuppressWarnings("unused") +public class CglibProxyFactory implements ProxyFactory { + private MessageFactory messageFactory; + + public CglibProxyFactory() { + this(new MessageFactoryImpl(), new InterfaceContractMapperImpl()); + } + + public CglibProxyFactory(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.messageFactory = messageFactory; + + } + + public <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor<T>(interfaze, wire)); + Object proxy = enhancer.create(); + return interfaze.cast(proxy); + } + + /** + * create the proxy with cglib. use the same JDKInvocationHandler as + * JDKProxyService. + */ + public <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + Class<T> interfaze = callableReference.getBusinessInterface(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor<T>(callableReference)); + Object proxy = enhancer.create(); + return interfaze.cast(proxy); + } + + /** + * create the callback proxy with cglib. use the same + * JDKCallbackInvocationHandler as JDKProxyService. + */ + public <T> T createCallbackProxy(Class<T> interfaze, final List<RuntimeWire> wires) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor<T>(interfaze, wires)); + Object proxy = enhancer.create(); + return interfaze.cast(proxy); + } + + @SuppressWarnings("unchecked") + public <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException { + if (isProxyClass(target.getClass())) { + Factory factory = (Factory)target; + Callback[] callbacks = factory.getCallbacks(); + if (callbacks.length != 1 || !(callbacks[0] instanceof CglibMethodInterceptor)) { + throw new IllegalArgumentException("The object is not a known proxy."); + } + CglibMethodInterceptor interceptor = (CglibMethodInterceptor)callbacks[0]; + return (R)interceptor.invocationHandler.getCallableReference(); + } else { + throw new IllegalArgumentException("The object is not a known proxy."); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class<?> clazz) { + return Factory.class.isAssignableFrom(clazz); + } + + private class CglibMethodInterceptor<T> implements MethodInterceptor { + private JDKInvocationHandler invocationHandler; + + public CglibMethodInterceptor(CallableReference<T> callableReference) { + invocationHandler = new JDKInvocationHandler(messageFactory, callableReference); + } + + public CglibMethodInterceptor(Class<T> interfaze, RuntimeWire wire) { + ServiceReference<T> serviceRef = new ServiceReferenceImpl<T>(interfaze, wire, CglibProxyFactory.this); + invocationHandler = new JDKInvocationHandler(messageFactory, serviceRef); + } + + public CglibMethodInterceptor(Class<T> interfaze, List<RuntimeWire> wires) { + CallbackWireObjectFactory wireFactory = new CallbackWireObjectFactory(interfaze, CglibProxyFactory.this, wires); + invocationHandler = new JDKCallbackInvocationHandler(messageFactory, wireFactory); + } + + /** + * @see net.sf.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.proxy.MethodProxy) + */ + public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + Object result = invocationHandler.invoke(proxy, method, args); + return result; + } + + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java new file mode 100644 index 0000000000..b40574394b --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.impl.InterfaceContractMapperImpl; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; + +public class DefaultProxyFactoryExtensionPoint implements ProxyFactoryExtensionPoint { + private InterfaceContractMapper interfaceContractMapper; + private MessageFactory messageFactory; + + private ProxyFactory interfaceFactory; + private ProxyFactory classFactory; + + public DefaultProxyFactoryExtensionPoint() { + this(new MessageFactoryImpl(), new InterfaceContractMapperImpl()); + } + + public DefaultProxyFactoryExtensionPoint(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.interfaceContractMapper = mapper; + this.messageFactory = messageFactory; + interfaceFactory = new JDKProxyFactory(messageFactory, mapper); + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint#getClassProxyFactory() + */ + public ProxyFactory getClassProxyFactory() { + return classFactory; + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint#getInterfaceProxyFactory() + */ + public ProxyFactory getInterfaceProxyFactory() { + return interfaceFactory; + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint#setClassProxyFactory(org.apache.tuscany.sca.core.invocation.ProxyFactory) + */ + public void setClassProxyFactory(ProxyFactory factory) { + this.classFactory = factory; + + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint#setInterfaceProxyFactory(org.apache.tuscany.sca.core.invocation.ProxyFactory) + */ + public void setInterfaceProxyFactory(ProxyFactory factory) { + this.interfaceFactory = factory; + + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#cast(java.lang.Object) + */ + @SuppressWarnings("unchecked") + public <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException { + if (interfaceFactory.isProxyClass(target.getClass())) { + return (R)interfaceFactory.cast(target); + } else if (classFactory != null && classFactory.isProxyClass(target.getClass())) { + return (R)classFactory.cast(target); + } else { + throw new IllegalArgumentException("The target is not a callable proxy"); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#createCallbackProxy(java.lang.Class, + * java.util.List) + */ + public <T> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> wires) throws ProxyCreationException { + if (interfaze.isInterface()) { + return interfaceFactory.createCallbackProxy(interfaze, wires); + } else { + return classFactory.createCallbackProxy(interfaze, wires); + } + } + + public <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException { + if (callableReference.getBusinessInterface().isInterface()) { + return interfaceFactory.createProxy(callableReference); + } else { + return classFactory.createProxy(callableReference); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#createProxy(java.lang.Class, + * org.apache.tuscany.sca.runtime.RuntimeWire) + */ + public <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException { + if (interfaze.isInterface()) { + return interfaceFactory.createProxy(interfaze, wire); + } else { + return classFactory.createProxy(interfaze, wire); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class<?> clazz) { + return interfaceFactory.isProxyClass(clazz) || (classFactory != null && classFactory.isProxyClass(clazz)); + } + + /** + * @return the interfaceContractMapper + */ + public InterfaceContractMapper getInterfaceContractMapper() { + return interfaceContractMapper; + } + + /** + * @return the messageFactory + */ + public MessageFactory getMessageFactory() { + return messageFactory; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java new file mode 100644 index 0000000000..934f2f7aa0 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java @@ -0,0 +1,44 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; + +/** + * The default implementation of an extensible <code>WireProcessor</code> + * + * @version $Rev$ $Date$ + */ +public class ExtensibleWireProcessor implements RuntimeWireProcessor { + + private RuntimeWireProcessorExtensionPoint processors; + + public ExtensibleWireProcessor(RuntimeWireProcessorExtensionPoint processors) { + this.processors = processors; + } + + public void process(RuntimeWire wire) { + for (RuntimeWireProcessor processor : processors.getWireProcessors()) { + processor.process(wire); + } + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InvocationChainImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InvocationChainImpl.java new file mode 100644 index 0000000000..72ce0f87fb --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InvocationChainImpl.java @@ -0,0 +1,130 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; + +/** + * Default implementation of an invocation chain + * + * @version $Rev$ $Date$ + */ +public class InvocationChainImpl implements InvocationChain { + private Operation sourceOperation; + private Operation targetOperation; + private Invoker invokerChainHead; + private Invoker invokerChainTail; + + public InvocationChainImpl(Operation operation) { + assert operation != null; + this.targetOperation = operation; + this.sourceOperation = operation; + } + + public InvocationChainImpl(Operation sourceOperation, Operation targetOperation) { + assert sourceOperation != null; + assert targetOperation != null; + this.targetOperation = targetOperation; + this.sourceOperation = sourceOperation; + } + + public Operation getTargetOperation() { + return targetOperation; + } + + public void setTargetOperation(Operation operation) { + this.targetOperation = operation; + } + + public void addInterceptor(Interceptor interceptor) { + if (invokerChainHead == null) { + invokerChainHead = interceptor; + } else { + if (invokerChainHead instanceof Interceptor) { + ((Interceptor)invokerChainTail).setNext(interceptor); + } + } + invokerChainTail = interceptor; + } + + public void addInvoker(Invoker invoker) { + if (invokerChainHead == null) { + invokerChainHead = invoker; + } else { + if (invokerChainTail instanceof Interceptor) { + ((Interceptor)invokerChainTail).setNext(invoker); + } + } + invokerChainTail = invoker; + } + + public Invoker getHeadInvoker() { + return invokerChainHead; + } + + public Invoker getTailInvoker() { + return invokerChainTail; + } + + /** + * @return the sourceOperation + */ + public Operation getSourceOperation() { + return sourceOperation; + } + + /** + * @param sourceOperation the sourceOperation to set + */ + public void setSourceOperation(Operation sourceOperation) { + this.sourceOperation = sourceOperation; + } + + public void addInterceptor(int index, Interceptor interceptor) { + int i = 0; + Invoker next = invokerChainHead; + Invoker prev = null; + while (next != null && i < index) { + prev = next; + if (next instanceof Interceptor) { + next = ((Interceptor)next).getNext(); + i++; + } else { + throw new ArrayIndexOutOfBoundsException(index); + } + } + if (i == index) { + if (prev != null) { + ((Interceptor)prev).setNext(interceptor); + } else { + invokerChainHead = interceptor; + } + interceptor.setNext(next); + if (next == null) { + invokerChainTail = interceptor; + } + } else { + throw new ArrayIndexOutOfBoundsException(index); + } + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKCallbackInvocationHandler.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKCallbackInvocationHandler.java new file mode 100644 index 0000000000..6442bb7bfc --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKCallbackInvocationHandler.java @@ -0,0 +1,131 @@ +/* + * 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.core.invocation; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.core.assembly.RuntimeWireImpl; +import org.apache.tuscany.sca.core.context.CallableReferenceImpl; +import org.apache.tuscany.sca.core.conversation.ConversationState; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.NoRegisteredCallbackException; +import org.osoa.sca.ServiceRuntimeException; + +/** + * Responsible for dispatching to a callback through a wire. <p/> TODO cache + * target invoker + * + * @version $Rev$ $Date$ + */ +public class JDKCallbackInvocationHandler extends JDKInvocationHandler { + private static final long serialVersionUID = -3350283555825935609L; + + public JDKCallbackInvocationHandler(MessageFactory messageFactory, CallbackWireObjectFactory wireFactory) { + super(messageFactory, wireFactory); + this.fixedWire = false; + } + + @Override + @SuppressWarnings( {"unchecked"}) + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (Object.class == method.getDeclaringClass()) { + return invokeObjectMethod(method, args); + } + + // wire not pre-selected, so select a wire now to be used for the callback + Message msgContext = ThreadMessageContext.getMessageContext(); + RuntimeWire wire = ((CallbackWireObjectFactory)callableReference).selectCallbackWire(msgContext); + if (wire == null) { + //FIXME: need better exception + throw new ServiceRuntimeException("No callback wire found for " + msgContext.getFrom().getURI()); + } + + // set the conversational state based on the interface that + // is specified for the reference that this wire belongs to + init(wire); + + // set the conversation id into the conversation object. This is + // a special case for callbacks as, unless otherwise set manually, + // the callback should use the same conversation id as was received + // on the incoming call to this component + if (conversational) { + + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + conversation = null; + } + Object convID = conversation == null ? null : conversation.getConversationID(); + + // create a conversation id if one doesn't exist + // already, i.e. the conversation is just starting + if (convID == null) { + convID = msgContext.getTo().getReferenceParameters().getConversationID(); + if (convID != null) { + conversation = ((RuntimeWireImpl)wire).getConversationManager().getConversation(convID); + if (callableReference != null) { + ((CallableReferenceImpl)callableReference).attachConversation(conversation); + } + } + } + } + + callbackID = msgContext.getTo().getReferenceParameters().getCallbackID(); + ((CallbackWireObjectFactory)callableReference).attachCallbackID(callbackID); + + EndpointReference epr = msgContext.getTo().getReferenceParameters().getCallbackReference(); + setEndpoint(epr); + + // need to set the endpoint on the binding also so that when the chains are created next + // the sca binding can decide whether to provide local or remote invokers. + // TODO - there is a problem here though in that I'm setting a target on a + // binding that may possibly be trying to point at two things in the multi threaded + // case. Need to confirm the general model here and how the clone and bind part + // is intended to work + wire.getSource().getBinding().setURI(epr.getURI()); + + // also need to set the target contract as it varies for the sca binding depending on + // whether it is local or remote + RuntimeComponentReference ref = (RuntimeComponentReference)wire.getSource().getContract(); + Binding binding = wire.getSource().getBinding(); + wire.getTarget().setInterfaceContract(ref.getBindingProvider(binding).getBindingInterfaceContract()); + + //FIXME: can we use the same code as JDKInvocationHandler to select the chain? + InvocationChain chain = getInvocationChain(method, wire); + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + method); + } + + try { + return invoke(chain, args, wire); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t instanceof NoRegisteredCallbackException) { + throw t; + } + throw e; + } + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java new file mode 100644 index 0000000000..a3cbb08691 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java @@ -0,0 +1,411 @@ +/* + * 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.core.invocation; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.tuscany.sca.core.assembly.RuntimeWireImpl; +import org.apache.tuscany.sca.core.context.CallableReferenceImpl; +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.core.conversation.ConversationManager; +import org.apache.tuscany.sca.core.conversation.ConversationState; +import org.apache.tuscany.sca.core.conversation.ExtendedConversation; +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.core.scope.TargetDestructionException; +import org.apache.tuscany.sca.core.scope.TargetResolutionException; +import org.apache.tuscany.sca.interfacedef.ConversationSequence; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; +import org.osoa.sca.ServiceReference; +import org.osoa.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class JDKInvocationHandler implements InvocationHandler, Serializable { + private static final long serialVersionUID = -3366410500152201371L; + + protected boolean conversational; + protected ExtendedConversation conversation; + protected MessageFactory messageFactory; + protected EndpointReference target; + protected Object conversationID; + protected Object callbackID; + protected Object callbackObject; + protected RuntimeWire wire; + protected CallableReference<?> callableReference; + protected Class<?> businessInterface; + + protected boolean fixedWire = true; + protected transient Map<Method, InvocationChain> chains = new HashMap<Method, InvocationChain>(); + + public JDKInvocationHandler(MessageFactory messageFactory, Class<?> businessInterface, RuntimeWire wire) { + this.messageFactory = messageFactory; + this.wire = wire; + this.businessInterface = businessInterface; + init(this.wire); + } + + public JDKInvocationHandler(MessageFactory messageFactory, CallableReference<?> callableReference) { + this.messageFactory = messageFactory; + this.callableReference = callableReference; + if (callableReference != null) { + this.businessInterface = callableReference.getBusinessInterface(); + this.callbackID = callableReference.getCallbackID(); + this.conversation = (ExtendedConversation)callableReference.getConversation(); + this.wire = ((CallableReferenceImpl<?>)callableReference).getRuntimeWire(); + if (callableReference instanceof ServiceReference) { + this.conversationID = ((ServiceReference)callableReference).getConversationID(); + this.callbackObject = ((ServiceReference)callableReference).getCallback(); + } + if (wire != null) { + init(wire); + } + } + } + + protected void init(RuntimeWire wire) { + if (wire != null) { + try { + // Clone the wire so that reference parameters can be changed + this.wire = (RuntimeWire)wire.clone(); + } catch (CloneNotSupportedException e) { + throw new ServiceRuntimeException(e); + } + } + InterfaceContract contract = wire.getSource().getInterfaceContract(); + this.conversational = contract.getInterface().isConversational(); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (Object.class == method.getDeclaringClass()) { + return invokeObjectMethod(method, args); + } + if (wire == null) { + throw new ServiceRuntimeException("No runtime wire is available"); + } + InvocationChain chain = getInvocationChain(method, wire); + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + method); + } + + // send the invocation down the wire + Object result = invoke(chain, args, wire); + + return result; + } + + /** + * Handle the methods on the Object.class + * @param method + * @param args + */ + protected Object invokeObjectMethod(Method method, Object[] args) throws Throwable { + String name = method.getName(); + if ("toString".equals(name)) { + return "[Proxy - " + toString() + "]"; + } else if ("equals".equals(name)) { + Object obj = args[0]; + if (obj == null) { + return false; + } + if (!Proxy.isProxyClass(obj.getClass())) { + return false; + } + return equals(Proxy.getInvocationHandler(obj)); + } else if ("hashCode".equals(name)) { + return hashCode(); + } else { + return method.invoke(this); + } + } + + /** + * Determines if the given operation matches the given method + * + * @return true if the operation matches, false if does not + */ + @SuppressWarnings("unchecked") + private static boolean match(Operation operation, Method method) { + Class<?>[] params = method.getParameterTypes(); + DataType<List<DataType>> inputType = operation.getInputType(); + List<DataType> types = inputType.getLogical(); + boolean matched = true; + if (types.size() == params.length && method.getName().equals(operation.getName())) { + for (int i = 0; i < params.length; i++) { + Class<?> clazz = params[i]; + if (!operation.getInputType().getLogical().get(i).getPhysical().isAssignableFrom(clazz)) { + matched = false; + } + } + } else { + matched = false; + } + return matched; + + } + + protected synchronized InvocationChain getInvocationChain(Method method, RuntimeWire wire) { + if (fixedWire && chains.containsKey(method)) { + return chains.get(method); + } + InvocationChain found = null; + for (InvocationChain chain : wire.getInvocationChains()) { + Operation operation = chain.getSourceOperation(); + if (operation.isDynamic()) { + operation.setName(method.getName()); + found = chain; + break; + } else if (match(operation, method)) { + found = chain; + break; + } + } + if (fixedWire) { + chains.put(method, found); + } + return found; + } + + protected void setEndpoint(EndpointReference endpoint) { + this.target = endpoint; + } + + protected Object invoke(InvocationChain chain, Object[] args, RuntimeWire wire) throws Throwable { + + Message msg = messageFactory.createMessage(); + msg.setFrom(wire.getSource()); + if (target != null) { + msg.setTo(target); + } else { + msg.setTo(wire.getTarget()); + } + Invoker headInvoker = chain.getHeadInvoker(); + Operation operation = chain.getTargetOperation(); + msg.setOperation(operation); + msg.setBody(args); + + Message msgContext = ThreadMessageContext.getMessageContext(); + Object currentConversationID = msgContext.getTo().getReferenceParameters().getConversationID(); + + conversationPreinvoke(msg, wire); + handleCallback(msg, wire, currentConversationID); + ThreadMessageContext.setMessageContext(msg); + try { + // dispatch the wire down the chain and get the response + Message resp = headInvoker.invoke(msg); + Object body = resp.getBody(); + if (resp.isFault()) { + throw (Throwable)body; + } + return body; + } finally { + conversationPostInvoke(msg, wire); + ThreadMessageContext.setMessageContext(msgContext); + } + } + + /** + * @param msg + * @param wire + * @param interfaze + * @throws TargetResolutionException + */ + private void handleCallback(Message msg, RuntimeWire wire, Object currentConversationID) + throws TargetResolutionException { + ReferenceParameters parameters = msg.getTo().getReferenceParameters(); + parameters.setCallbackID(callbackID); + if (wire.getSource() == null || wire.getSource().getCallbackEndpoint() == null) { + return; + } + + parameters.setCallbackReference(wire.getSource().getCallbackEndpoint()); + + // If we are passing out a callback target + // register the calling component instance against this + // new conversation id so that stateful callbacks will be + // able to find it + if (conversational && callbackObject == null) { + // the component instance is already registered + // so add another registration + ScopeContainer<Object> scopeContainer = getConversationalScopeContainer(wire); + + if (scopeContainer != null) { + scopeContainer.addWrapperReference(currentConversationID, conversation.getConversationID()); + } + } + + Interface interfaze = msg.getOperation().getInterface(); + if (callbackObject != null) { + if (callbackObject instanceof ServiceReference) { + EndpointReference callbackRef = ((CallableReferenceImpl)callbackObject).getEndpointReference(); + parameters.setCallbackReference(callbackRef); + } else { + if (interfaze != null) { + if (!interfaze.isConversational()) { + throw new IllegalArgumentException( + "Callback object for stateless callback is not a ServiceReference"); + } else { + ScopeContainer scopeContainer = getConversationalScopeContainer(wire); + if (scopeContainer != null) { + InstanceWrapper wrapper = new CallbackObjectWrapper(callbackObject); + scopeContainer.registerWrapper(wrapper, conversation.getConversationID()); + } + parameters.setCallbackObjectID("java:" + System.identityHashCode(callbackObject)); + } + } + } + } + } + + /** + * Pre-invoke for the conversation handling + * @param msg + * @throws TargetResolutionException + */ + private void conversationPreinvoke(Message msg, RuntimeWire wire) { + if (!conversational) { + // Not conversational or the conversation has been started + return; + } + ConversationManager conversationManager = ((RuntimeWireImpl)wire).getConversationManager(); + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + conversation = conversationManager.startConversation(conversationID); + if (callableReference != null) { + ((CallableReferenceImpl)callableReference).attachConversation(conversation); + } + } + // TODO - assuming that the conversation ID is a string here when + // it can be any object that is serializable to XML + msg.getTo().getReferenceParameters().setConversationID(conversation.getConversationID()); + + } + + /** + * Post-invoke for the conversation handling + * @param wire + * @param operation + * @throws TargetDestructionException + */ + @SuppressWarnings("unchecked") + private void conversationPostInvoke(Message msg, RuntimeWire wire) throws TargetDestructionException { + Operation operation = msg.getOperation(); + ConversationSequence sequence = operation.getConversationSequence(); + if (sequence == ConversationSequence.CONVERSATION_END) { + conversation.end(); + + // remove conversation id from scope container + ScopeContainer scopeContainer = getConversationalScopeContainer(wire); + + if (scopeContainer != null) { + scopeContainer.remove(conversation.getConversationID()); + } + } + } + + private ScopeContainer<Object> getConversationalScopeContainer(RuntimeWire wire) { + ScopeContainer<Object> scopeContainer = null; + + RuntimeComponent runtimeComponent = wire.getSource().getComponent(); + + if (runtimeComponent instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent scopedRuntimeComponent = (ScopedRuntimeComponent)runtimeComponent; + ScopeContainer<Object> tmpScopeContainer = scopedRuntimeComponent.getScopeContainer(); + + if ((tmpScopeContainer != null) && (tmpScopeContainer.getScope() == Scope.CONVERSATION)) { + scopeContainer = tmpScopeContainer; + } + } + + return scopeContainer; + } + + /** + * Creates a new conversational id + * + * @return the conversational id + */ + private Object createConversationID() { + if (conversationID == null) { + return UUID.randomUUID().toString(); + } + return conversationID; + } + + /** + * @return the callableReference + */ + public CallableReference<?> getCallableReference() { + return callableReference; + } + + /** + * @param callableReference the callableReference to set + */ + public void setCallableReference(CallableReference<?> callableReference) { + this.callableReference = callableReference; + } + + /** + * Minimal wrapper for a callback object contained in a ServiceReference + */ + private static class CallbackObjectWrapper<T> implements InstanceWrapper<T> { + + private T instance; + + private CallbackObjectWrapper(T instance) { + this.instance = instance; + } + + public T getInstance() { + return instance; + } + + public void start() { + // do nothing + } + + public void stop() { + // do nothing + } + + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKProxyFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKProxyFactory.java new file mode 100644 index 0000000000..20bc36c0cd --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKProxyFactory.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.List; + +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.impl.InterfaceContractMapperImpl; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; + +/** + * the default implementation of a wire service that uses JDK dynamic proxies + * + * @version $$Rev$$ $$Date: 2007-04-11 18:59:43 -0700 (Wed, 11 Apr + * 2007) $$ + */ +public class JDKProxyFactory implements ProxyFactory { + protected InterfaceContractMapper contractMapper; + private MessageFactory messageFactory; + + public JDKProxyFactory() { + this(new MessageFactoryImpl(), new InterfaceContractMapperImpl()); + } + + public JDKProxyFactory(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.contractMapper = mapper; + this.messageFactory = messageFactory; + } + + /** + * The original createProxy method assumes that the proxy doesn't want to + * share conversation state so sets the conversaton object to null + */ + public <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException { + JDKInvocationHandler handler = new JDKInvocationHandler(messageFactory, interfaze, wire); + ClassLoader cl = interfaze.getClassLoader(); + return interfaze.cast(Proxy.newProxyInstance(cl, new Class[] {interfaze}, handler)); + } + + public <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException { + assert callableReference != null; + Class<T> interfaze = callableReference.getBusinessInterface(); + JDKInvocationHandler handler = new JDKInvocationHandler(messageFactory, callableReference); + ClassLoader cl = interfaze.getClassLoader(); + return interfaze.cast(Proxy.newProxyInstance(cl, new Class[] {interfaze}, handler)); + } + + public <T> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> wires) throws ProxyCreationException { + ClassLoader cl = interfaze.getClassLoader(); + CallbackWireObjectFactory wireFactory = new CallbackWireObjectFactory(interfaze, this, wires); + JDKCallbackInvocationHandler handler = new JDKCallbackInvocationHandler(messageFactory, wireFactory); + return interfaze.cast(Proxy.newProxyInstance(cl, new Class[] {interfaze}, handler)); + } + + public <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException { + InvocationHandler handler = Proxy.getInvocationHandler(target); + if (handler instanceof JDKInvocationHandler) { + return (R)((JDKInvocationHandler)handler).getCallableReference(); + } else { + throw new IllegalArgumentException("The object is not a known proxy."); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class<?> clazz) { + return Proxy.isProxyClass(clazz); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageFactoryImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageFactoryImpl.java new file mode 100644 index 0000000000..6e182a6a14 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageFactoryImpl.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.core.invocation; + +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; + +/** + * Implementation of MessageFactory. + * + * @version $Rev$ $Date$ + */ +public class MessageFactoryImpl implements MessageFactory { + + public Message createMessage() { + return new MessageImpl(); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageImpl.java new file mode 100644 index 0000000000..1e4e8fc6a9 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageImpl.java @@ -0,0 +1,96 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.core.assembly.EndpointReferenceImpl; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.EndpointReference; + +/** + * The default implementation of a message flowed through a wire during an invocation + * + * @version $Rev $Date + */ +public class MessageImpl implements Message { + private Object body; + private Object messageID; + private boolean isFault; + private Operation operation; + + private EndpointReference from; + private EndpointReference to; + + public MessageImpl() { + this.from = new EndpointReferenceImpl("/"); + this.to = new EndpointReferenceImpl("/"); + } + + @SuppressWarnings("unchecked") + public <T> T getBody() { + return (T)body; + } + + public <T> void setBody(T body) { + this.isFault = false; + this.body = body; + } + + public Object getMessageID() { + return messageID; + } + + public void setMessageID(Object messageId) { + this.messageID = messageId; + } + + public boolean isFault() { + return isFault; + } + + public void setFaultBody(Object fault) { + this.isFault = true; + this.body = fault; + } + + public EndpointReference getFrom() { + return from; + } + + public void setFrom(EndpointReference from) { + this.from = from; + } + + public EndpointReference getTo() { + return to; + } + + public void setTo(EndpointReference to) { + this.to = to; + } + + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation op) { + this.operation = op; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NoMethodForOperationException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NoMethodForOperationException.java new file mode 100644 index 0000000000..733544d387 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NoMethodForOperationException.java @@ -0,0 +1,43 @@ +/* + * 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.core.invocation; + + +/** + * Thrown when an {@link org.apache.tuscany.sca.core.factory.model.Operation} cannot be mapped to a method on an interface + * @version $Rev$ $Date$ + */ +public class NoMethodForOperationException extends ProxyCreationException { + private static final long serialVersionUID = 5116536602309483679L; + + public NoMethodForOperationException() { + } + + public NoMethodForOperationException(String message) { + super(message); + } + + public NoMethodForOperationException(String message, Throwable cause) { + super(message, cause); + } + + public NoMethodForOperationException(Throwable cause) { + super(cause); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java new file mode 100644 index 0000000000..e8621571e4 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java @@ -0,0 +1,159 @@ +/* + * 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.core.invocation; + +import java.util.LinkedList; + +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.osoa.sca.ServiceRuntimeException; + +/** + * Adds non-blocking behavior to an invocation chain + * + * @version $$Rev$$ $$Date$$ + */ +public class NonBlockingInterceptor implements Interceptor { + + private static final Message RESPONSE = new ImmutableMessage(); + + private WorkScheduler workScheduler; + private Invoker next; + + public NonBlockingInterceptor(WorkScheduler workScheduler) { + this.workScheduler = workScheduler; + } + + public NonBlockingInterceptor(WorkScheduler workScheduler, Interceptor next) { + this.workScheduler = workScheduler; + this.next = next; + } + + /** + * Sets desired workScheduler to NonBlockingInterceptor. This is a usefull function for the extension framework + * to set desired workmanager on the InvocationChain, other than default workmanager which is set per Tuscany runtime. + * Using this function, extension framework can set desired workmanager on InvocationChain during post wire processing. + * @param workScheduler workScheduler which contains workmanager + */ + public void setWorkScheduler(WorkScheduler workScheduler){ + this.workScheduler = workScheduler; + } + + public Message invoke(final Message msg) { + // Schedule the invocation of the next interceptor in a new Work instance + try { + workScheduler.scheduleWork(new Runnable() { + public void run() { + Message context = ThreadMessageContext.setMessageContext(msg); + try { + next.invoke(msg); + } finally { + ThreadMessageContext.setMessageContext(context); + } + } + }); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + return RESPONSE; + } + + public Invoker getNext() { + return next; + } + + public void setNext(Invoker next) { + this.next = next; + } + + /** + * A dummy message passed back on an invocation + */ + private static class ImmutableMessage implements Message { + + @SuppressWarnings("unchecked") + public Object getBody() { + return null; + } + + public void setBody(Object body) { + if (body != null) { + throw new UnsupportedOperationException(); + } + } + + public void setCallbackWires(LinkedList<RuntimeWire> wires) { + + } + + public Object getMessageID() { + return null; + } + + public void setMessageID(Object messageId) { + throw new UnsupportedOperationException(); + } + + public boolean isFault() { + return false; + } + + public void setFaultBody(Object fault) { + throw new UnsupportedOperationException(); + } + + public EndpointReference getFrom() { + return null; + } + + public EndpointReference getTo() { + return null; + } + + public void setFrom(EndpointReference from) { + throw new UnsupportedOperationException(); + } + + public void setTo(EndpointReference to) { + throw new UnsupportedOperationException(); + } + + public Operation getOperation() { + return null; + } + + public void setOperation(Operation op) { + throw new UnsupportedOperationException(); + } + + /** + * @see org.apache.tuscany.sca.invocation.Message#getReplyTo() + */ + public EndpointReference getReplyTo() { + return null; + } + + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java new file mode 100644 index 0000000000..c0646f577a --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.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.core.invocation; + +import org.apache.tuscany.sca.core.factory.ObjectCreationException; + + +/** + * Denotes an error creating a proxy + * + * @version $$Rev$$ $$Date$$ + */ +public class ProxyCreationException extends ObjectCreationException { + private static final long serialVersionUID = 8002454344828513781L; + + public ProxyCreationException() { + super(); + } + + public ProxyCreationException(String message, Throwable cause) { + super(message, cause); + } + + public ProxyCreationException(String message) { + super(message); + } + + public ProxyCreationException(Throwable cause) { + super(cause); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java new file mode 100644 index 0000000000..b72730397e --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java @@ -0,0 +1,78 @@ +/* + * 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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; + +/** + * Creates proxies that implement Java interfaces and invocation handlers for fronting wires + * + * @version $$Rev$$ $$Date$$ + */ + +public interface ProxyFactory { + + /** + * Creates a Java proxy for the given wire + * + * @param interfaze the interface the proxy implements + * @param wire the wire to proxy + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException; + + /** + * Creates a Java proxy for the given callable reference + * + * @param callableReference The callable reference + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException; + + /** + * Creates a Java proxy for the service contract callback + * + * @param interfaze the interface the proxy should implement + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> wires) throws ProxyCreationException; + + /** + * Cast a proxy to a CallableReference. + * + * @param target a proxy generated by this implementation + * @return a CallableReference (or subclass) equivalent to this prozy + * @throws IllegalArgumentException if the object supplied is not a proxy + */ + <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException; + + /** + * Test if a given class is a generated proxy class by this factory + * @param clazz A java class or interface + * @return true if the class is a generated proxy class by this factory + */ + boolean isProxyClass(Class<?> clazz); + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java new file mode 100644 index 0000000000..fdd710c465 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java @@ -0,0 +1,58 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; + +/** + * The extension point to plug in proxy factories + * @version $Rev$ $Date$ + */ +public interface ProxyFactoryExtensionPoint extends ProxyFactory { + /** + * Get the proxy factory for java interfaces + * @return + */ + ProxyFactory getInterfaceProxyFactory(); + + /** + * Get the proxy factory for java classes + * @return + */ + ProxyFactory getClassProxyFactory(); + + /** + * Set the proxy factory for java interfaces + * @param factory + */ + void setInterfaceProxyFactory(ProxyFactory factory); + + /** + * Set the proxy factory for java classes + * @param factory + */ + void setClassProxyFactory(ProxyFactory factory); + + /** + * @return the interfaceContractMapper + */ + InterfaceContractMapper getInterfaceContractMapper(); + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java new file mode 100644 index 0000000000..11d03355e6 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java @@ -0,0 +1,295 @@ +/* + * 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.core.invocation; + +import java.lang.reflect.InvocationTargetException; +import java.util.UUID; + +import org.apache.tuscany.sca.core.context.CallableReferenceImpl; +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.core.conversation.ConversationManager; +import org.apache.tuscany.sca.core.conversation.ConversationState; +import org.apache.tuscany.sca.core.conversation.ExtendedConversation; +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.core.scope.TargetDestructionException; +import org.apache.tuscany.sca.core.scope.TargetResolutionException; +import org.apache.tuscany.sca.interfacedef.ConversationSequence; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.ServiceReference; +import org.osoa.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class RuntimeWireInvoker { + protected ConversationManager conversationManager; + protected boolean conversational; + protected ExtendedConversation conversation; + protected MessageFactory messageFactory; + protected EndpointReference endpoint; + protected Object conversationID; + protected Object callbackID; + protected Object callbackObject; + protected RuntimeWire wire; + + public RuntimeWireInvoker(MessageFactory messageFactory, ConversationManager conversationManager, RuntimeWire wire) { + this.messageFactory = messageFactory; + this.wire = wire; + this.conversationManager = conversationManager; + init(wire); + } + + protected void init(RuntimeWire wire) { + if (wire != null) { + ReferenceParameters parameters = wire.getSource().getReferenceParameters(); + this.callbackID = parameters.getCallbackID(); + this.callbackObject = parameters.getCallbackReference(); + this.conversationID = parameters.getConversationID(); + InterfaceContract contract = wire.getSource().getInterfaceContract(); + this.conversational = contract.getInterface().isConversational(); + } + } + + public Object invoke(Operation operation, Message msg) throws InvocationTargetException { + return invoke(wire, operation, msg); + } + + public Object invoke(RuntimeWire wire, Operation operation, Message msg) throws InvocationTargetException { + RuntimeWire runtimeWire = wire == null ? this.wire : wire; + InvocationChain chain = runtimeWire.getInvocationChain(operation); + return invoke(chain, msg, runtimeWire); + } + + protected Object invoke(InvocationChain chain, Message msg, RuntimeWire wire) throws InvocationTargetException { + + msg.setFrom(wire.getSource()); + EndpointReference epTo = null; + if (endpoint != null) { + epTo = endpoint; + } else { + epTo = wire.getTarget(); + } + if (msg.getTo() != null) { + msg.getTo().mergeEndpoint(epTo); + } else { + msg.setTo(epTo); + } + Invoker headInvoker = chain.getHeadInvoker(); + Operation operation = chain.getTargetOperation(); + msg.setOperation(operation); + + Message msgContext = ThreadMessageContext.getMessageContext(); + Object currentConversationID = msgContext.getTo().getReferenceParameters().getConversationID(); + + ThreadMessageContext.setMessageContext(msg); + try { + conversationPreinvoke(msg); + handleCallback(msg, currentConversationID); + // dispatch the wire down the chain and get the response + Message resp = headInvoker.invoke(msg); + Object body = resp.getBody(); + if (resp.isFault()) { + throw new InvocationTargetException((Throwable)body); + } + return body; + } catch (InvocationTargetException e) { + throw e; + } catch (Throwable e) { + throw new ServiceRuntimeException(e); + } finally { + try { + conversationPostInvoke(msg); + } catch (TargetDestructionException e) { + throw new ServiceRuntimeException(e); + } finally { + ThreadMessageContext.setMessageContext(msgContext); + } + } + } + + /** + * @param msgContext + */ + protected EndpointReference getCallbackEndpoint(Message msgContext) { + EndpointReference to = msgContext.getTo(); + return to == null ? null : to.getReferenceParameters().getCallbackReference(); + } + + /** + * @param msg + * @param wire + * @param interfaze + * @throws TargetResolutionException + */ + @SuppressWarnings("unchecked") + private void handleCallback(Message msg, Object currentConversationID) throws TargetResolutionException { + EndpointReference from = msg.getFrom(); + EndpointReference to = msg.getTo(); + msg.getTo().getReferenceParameters().setCallbackID(callbackID); + if (from == null || from.getCallbackEndpoint() == null) { + return; + } + // If we are passing out a callback target + // register the calling component instance against this + // new conversation id so that stateful callbacks will be + // able to find it + if (conversational && callbackObject == null) { + // the component instance is already registered + // so add another registration + ScopeContainer scopeContainer = getConversationalScopeContainer(msg); + + if (scopeContainer != null) { + scopeContainer.addWrapperReference(currentConversationID, to.getReferenceParameters() + .getConversationID()); + } + } + + ReferenceParameters parameters = msg.getTo().getReferenceParameters(); + Interface interfaze = msg.getOperation().getInterface(); + if (callbackObject != null) { + if (callbackObject instanceof ServiceReference) { + EndpointReference callbackRef = ((CallableReferenceImpl)callbackObject).getEndpointReference(); + parameters.setCallbackReference(callbackRef); + } else { + if (interfaze != null) { + if (!interfaze.isConversational()) { + throw new IllegalArgumentException( + "Callback object for stateless callback is not a ServiceReference"); + } else { + ScopeContainer scopeContainer = getConversationalScopeContainer(msg); + if (scopeContainer != null) { + InstanceWrapper wrapper = new CallbackObjectWrapper(callbackObject); + scopeContainer.registerWrapper(wrapper, conversation.getConversationID()); + } + parameters.setCallbackObjectID("java:" + System.identityHashCode(callbackObject)); + } + } + } + } + } + + /** + * Pre-invoke for the conversation handling + * @param msg + * @throws TargetResolutionException + */ + private void conversationPreinvoke(Message msg) { + if (!conversational) { + // Not conversational or the conversation has been started + return; + } + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + conversation = conversationManager.startConversation(conversationID); + } + // TODO - assuming that the conversation ID is a string here when + // it can be any object that is serializable to XML + msg.getTo().getReferenceParameters().setConversationID(conversation.getConversationID()); + + } + + /** + * Post-invoke for the conversation handling + * @param wire + * @param operation + * @throws TargetDestructionException + */ + @SuppressWarnings("unchecked") + private void conversationPostInvoke(Message msg) throws TargetDestructionException { + Operation operation = msg.getOperation(); + ConversationSequence sequence = operation.getConversationSequence(); + if (sequence == ConversationSequence.CONVERSATION_END) { + conversation.end(); + + // remove conversation id from scope container + ScopeContainer scopeContainer = getConversationalScopeContainer(msg); + + if (scopeContainer != null) { + scopeContainer.remove(conversation.getConversationID()); + } + } + } + + @SuppressWarnings("unchecked") + private ScopeContainer getConversationalScopeContainer(Message msg) { + ScopeContainer scopeContainer = null; + + RuntimeComponent component = msg.getFrom().getComponent(); + + if (component instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent scopedRuntimeComponent = (ScopedRuntimeComponent)component; + ScopeContainer container = scopedRuntimeComponent.getScopeContainer(); + + if ((container != null) && (container.getScope() == Scope.CONVERSATION)) { + scopeContainer = container; + } + } + + return scopeContainer; + } + + /** + * Creates a new conversational id + * + * @return the conversational id + */ + private Object createConversationID() { + if (conversationID == null) { + return UUID.randomUUID().toString(); + } + return conversationID; + } + + /** + * Minimal wrapper for a callback object contained in a ServiceReference + */ + private static class CallbackObjectWrapper<T> implements InstanceWrapper<T> { + + private T instance; + + private CallbackObjectWrapper(T instance) { + this.instance = instance; + } + + public T getInstance() { + return instance; + } + + public void start() { + // do nothing + } + + public void stop() { + // do nothing + } + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/TargetInvocationException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/TargetInvocationException.java new file mode 100644 index 0000000000..2c4d657882 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/TargetInvocationException.java @@ -0,0 +1,45 @@ +/* + * 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.core.invocation; + +/** + * Raised when an error is encountered during a target invocation + * + * @version $Rev$ $Date$ + */ +public class TargetInvocationException extends Exception { + + private static final long serialVersionUID = -6553427708442761743L; + + public TargetInvocationException() { + super(); + } + + public TargetInvocationException(String message, Throwable cause) { + super(message, cause); + } + + public TargetInvocationException(String message) { + super(message); + } + + public TargetInvocationException(Throwable cause) { + super(cause); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ThreadMessageContext.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ThreadMessageContext.java new file mode 100644 index 0000000000..7f419028f9 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ThreadMessageContext.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + +import org.apache.tuscany.sca.core.assembly.EndpointReferenceImpl; +import org.apache.tuscany.sca.invocation.Message; + +/** + * Class for tunneling a WorkContext through the invocation of a user class. + * + * @version $Rev$ $Date$ + */ +public final class ThreadMessageContext { + + private static final ThreadLocal<Message> CONTEXT = new ThreadLocal<Message>() { + @Override + protected synchronized Message initialValue() { + Message msg = new MessageImpl(); + msg.setFrom(new EndpointReferenceImpl("/")); + return msg; + } + }; + + private ThreadMessageContext() { + } + + /** + * Set the WorkContext for the current thread. + * The current work context is returned and must be restored after the invocation is complete. + * Typical usage would be: + * <pre> + * WorkContext old = PojoWorkContextTunnel.setThreadWorkContext(newContext); + * try { + * ... invoke user code ... + * } finally { + * PojoWorkContextTunnel.setThreadWorkContext(old); + * } + * </pre> + * @param context + * @return the current work context for the thread; this must be restored after the invocation is made + */ + public static Message setMessageContext(Message context) { + Message old = CONTEXT.get(); + CONTEXT.set(context); + return old; + } + + /** + * Returns the WorkContext for the current thread. + * + * @return the WorkContext for the current thread + */ + public static Message getMessageContext() { + return CONTEXT.get(); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java new file mode 100644 index 0000000000..0a40d49b36 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java @@ -0,0 +1,43 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.core.context.ServiceReferenceImpl; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; + +/** + * Uses a wire to return an object instance + * + * @version $Rev$ $Date$ + */ +public class WireObjectFactory<T> extends ServiceReferenceImpl<T> implements ObjectFactory<T> { + /** + * Constructor. + * + * @param interfaze the interface to inject on the client + * @param wire the backing wire + * @param proxyService the wire service to create the proxy + * @throws NoMethodForOperationException + */ + public WireObjectFactory(Class<T> interfaze, RuntimeWire wire, ProxyFactory proxyService) { + super(interfaze, wire, proxyService); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.java new file mode 100644 index 0000000000..fbc402bfe3 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainer.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.core.scope; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.event.Event; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * Implements functionality common to scope contexts. + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractScopeContainer<KEY> implements ScopeContainer<KEY> { + protected Map<KEY, InstanceWrapper<?>> wrappers = new ConcurrentHashMap<KEY, InstanceWrapper<?>>(); + protected final Scope scope; + + protected RuntimeComponent component; + protected volatile int lifecycleState = UNINITIALIZED; + + + public AbstractScopeContainer(Scope scope, RuntimeComponent component) { + this.scope = scope; + this.component = component; + } + + protected void checkInit() { + if (getLifecycleState() != RUNNING) { + throw new IllegalStateException("Scope container not running [" + getLifecycleState() + "]"); + } + } + + /** + * Creates a new physical instance of a component, wrapped in an + * InstanceWrapper. + * + * @param component the component whose instance should be created + * @return a wrapped instance that has been injected but not yet started + * @throws TargetResolutionException if there was a problem creating the + * instance + */ + protected InstanceWrapper createInstanceWrapper() throws TargetResolutionException { + ImplementationProvider implementationProvider = component.getImplementationProvider(); + if (implementationProvider instanceof ScopedImplementationProvider) { + return ((ScopedImplementationProvider)implementationProvider).createInstanceWrapper(); + } + return null; + } + + public InstanceWrapper getAssociatedWrapper(KEY contextId) throws TargetResolutionException { + return getWrapper(contextId); // TODO: what is this method spossed to do diff than getWrapper? + } + + public Scope getScope() { + return scope; + } + + public InstanceWrapper getWrapper(KEY contextId) throws TargetResolutionException { + return wrappers.get(contextId); + } + + public void addWrapperReference(KEY existingContextId, KEY newContextId) + throws TargetResolutionException + { + // do nothing here. the conversational scope container implements this + } + + public void registerWrapper(InstanceWrapper wrapper, KEY contextId) throws TargetResolutionException { + // do nothing here. the conversational scope container implements this + } + + public void onEvent(Event event) { + } + + protected boolean isEagerInit() { + ImplementationProvider implementationProvider = ((RuntimeComponent)component).getImplementationProvider(); + if (implementationProvider instanceof ScopedImplementationProvider) { + return ((ScopedImplementationProvider)implementationProvider).isEagerInit(); + } + return false; + } + + public void returnWrapper(InstanceWrapper wrapper, KEY contextId) throws TargetDestructionException { + } + + /** + * Default implmentation of remove which does nothing + * + * @param contextId the identifier of the context to remove. + */ + public void remove(KEY contextId) + throws TargetDestructionException { + } + + public synchronized void start() { + int lifecycleState = getLifecycleState(); + if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) { + throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state [" + lifecycleState + "]"); + } + setLifecycleState(RUNNING); + } + + public void startContext(KEY contextId) { + if(isEagerInit()) { + try { + getWrapper(contextId); + } catch (TargetResolutionException e) { + // + } + } + } + + public synchronized void stop() { + int lifecycleState = getLifecycleState(); + if (lifecycleState != RUNNING) { + throw new IllegalStateException("Scope in wrong state [" + lifecycleState + "]"); + } + setLifecycleState(STOPPED); + } + + public void stopContext(KEY contextId) { + wrappers.remove(contextId); + } + + @Override + public String toString() { + String s; + switch (lifecycleState) { + case ScopeContainer.CONFIG_ERROR: + s = "CONFIG_ERROR"; + break; + case ScopeContainer.ERROR: + s = "ERROR"; + break; + case ScopeContainer.INITIALIZING: + s = "INITIALIZING"; + break; + case ScopeContainer.INITIALIZED: + s = "INITIALIZED"; + break; + case ScopeContainer.RUNNING: + s = "RUNNING"; + break; + case ScopeContainer.STOPPING: + s = "STOPPING"; + break; + case ScopeContainer.STOPPED: + s = "STOPPED"; + break; + case ScopeContainer.UNINITIALIZED: + s = "UNINITIALIZED"; + break; + default: + s = "UNKNOWN"; + break; + } + return "In state [" + s + ']'; + } + + public RuntimeComponent getComponent() { + return component; + } + + public void setComponent(RuntimeComponent component) { + this.component = component; + } + + public int getLifecycleState() { + return lifecycleState; + } + + /** + * Set the current state of the Lifecycle. + * + * @param lifecycleState the new state + */ + protected void setLifecycleState(int lifecycleState) { + this.lifecycleState = lifecycleState; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/CompositeScopeContainer.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/CompositeScopeContainer.java new file mode 100644 index 0000000000..7e7ab7a9e4 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/CompositeScopeContainer.java @@ -0,0 +1,77 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * A scope context which manages atomic component instances keyed by composite + * + * @version $Rev$ $Date$ + */ +public class CompositeScopeContainer<KEY> extends AbstractScopeContainer<KEY> { + private InstanceWrapper<?> wrapper; + + public CompositeScopeContainer(RuntimeComponent component) { + super(Scope.COMPOSITE, component); + } + + @Override + public synchronized void stop() { + super.stop(); + if (wrapper != null) { + try { + wrapper.stop(); + } catch (TargetDestructionException e) { + throw new IllegalStateException(e); + } + } + wrapper = null; + } + + @Override + public synchronized InstanceWrapper getWrapper(KEY contextId) throws TargetResolutionException { + if (wrapper == null) { + wrapper = createInstanceWrapper(); + wrapper.start(); + } + return wrapper; + } + + @Override + public InstanceWrapper getAssociatedWrapper(KEY contextId) throws TargetResolutionException { + if (wrapper == null) { + throw new TargetNotFoundException(component.getURI()); + } + return wrapper; + } + + @Override + public synchronized void start() { + super.start(); + if (isEagerInit()) { + try { + getWrapper(null); + } catch (TargetResolutionException e) { + throw new IllegalStateException(e); + } + } + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/CompositeScopeContainerFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/CompositeScopeContainerFactory.java new file mode 100644 index 0000000000..786988613b --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/CompositeScopeContainerFactory.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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * @version $Rev$ $Date$ + */ +public class CompositeScopeContainerFactory implements ScopeContainerFactory { + + public ScopeContainer createScopeContainer(RuntimeComponent component) { + return new CompositeScopeContainer(component); + } + + public Scope getScope() { + return Scope.COMPOSITE; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ConversationalScopeContainer.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ConversationalScopeContainer.java new file mode 100644 index 0000000000..63968eba23 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ConversationalScopeContainer.java @@ -0,0 +1,405 @@ +/*
+ * 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.core.scope;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.tuscany.sca.core.context.InstanceWrapper;
+import org.apache.tuscany.sca.core.conversation.ConversationListener;
+import org.apache.tuscany.sca.core.conversation.ConversationManager;
+import org.apache.tuscany.sca.core.conversation.ExtendedConversation;
+import org.apache.tuscany.sca.core.invocation.ThreadMessageContext;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.store.Store;
+import org.osoa.sca.ConversationEndedException;
+
+/**
+ * A scope context which manages atomic component instances keyed on ConversationID
+ *
+ */
+public class ConversationalScopeContainer extends AbstractScopeContainer<Object> implements ConversationListener {
+ private ConversationManager conversationManager;
+ private Map<Object, InstanceLifeCycleWrapper> instanceLifecycleCollection =
+ new ConcurrentHashMap<Object, InstanceLifeCycleWrapper>();
+
+ //TODO: This needs to observe the value set by ConversationalAttributes for now we will hard code it.
+ private long max_age = 60 * 60 * 1000; // 1 hour;
+ private long max_idle_time = 60 * 60 * 1000; // 1 hour;
+ private long reaper_interval = 60; // every minute;
+ private ScheduledExecutorService scheduler;
+
+ public ConversationalScopeContainer(Store aStore, RuntimeComponent component) {
+ super(Scope.CONVERSATION, component);
+
+ // Note: aStore is here to preserve the original factory interface. It is not currently used in this
+ // implementation since we do not support instance persistence.
+
+ // Check System properties to see if timeout values have been specified. All timeout values
+ // will be specified in seconds.
+ //
+ String aProperty;
+ aProperty = System.getProperty("org.apache.tuscany.sca.core.scope.ConversationalScopeContainer.MaxIdleTime");
+ if (aProperty != null) {
+ try {
+ max_idle_time = (new Long(aProperty) * 1000);
+ } catch (NumberFormatException nfe) {
+ // Ignore
+ }
+ }
+
+ aProperty = System.getProperty("org.apache.tuscany.sca.core.scope.ConversationalScopeContainer.MaxAge");
+ if (aProperty != null) {
+ try {
+ max_age = (new Long(aProperty) * 1000);
+ } catch (NumberFormatException nfe) {
+ // Ignore
+ }
+ }
+
+ aProperty = System.getProperty("org.apache.tuscany.sca.core.scope.ConversationalScopeContainer.ReaperInterval");
+ if (aProperty != null) {
+ try {
+ reaper_interval = new Long(aProperty);
+ } catch (NumberFormatException nfe) {
+ // Ignore
+ }
+ }
+
+ // Check to see if the maxAge and/or maxIdleTime have been specified using @ConversationAttributes.
+ // Implementation annoated attributes are honored first.
+ if (this.getComponent().getImplementationProvider() instanceof ScopedImplementationProvider) {
+ ScopedImplementationProvider aScopedImpl =
+ (ScopedImplementationProvider)this.getComponent().getImplementationProvider();
+
+ long maxAge = aScopedImpl.getMaxAge();
+ if (maxAge > 0) {
+ max_age = maxAge;
+ }
+ long maxIdleTime = aScopedImpl.getMaxIdleTime();
+ if (maxIdleTime > 0) {
+ max_idle_time = maxIdleTime;
+ }
+ }
+
+ }
+
+ @Override
+ public synchronized void start() {
+ if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) {
+ throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state [" + lifecycleState + "]");
+ }
+
+ // Get a scheduler and scheduled a task to be run in the future indefinitely until its explicitly shutdown.
+ this.scheduler = Executors.newSingleThreadScheduledExecutor();
+ scheduler.scheduleAtFixedRate(new ConversationalInstanceReaper(this.instanceLifecycleCollection),
+ 3,
+ reaper_interval,
+ TimeUnit.SECONDS);
+
+ lifecycleState = RUNNING;
+ }
+
+ @Override
+ public synchronized void stop() {
+
+ // Prevent the scheduler from submitting any additional reapers, initiate an orderly shutdown if a reaper task is in progress.
+ if (this.scheduler != null)
+ this.scheduler.shutdown();
+
+ lifecycleState = STOPPED;
+ }
+
+ protected InstanceWrapper getInstanceWrapper(boolean create, Object contextId) throws TargetResolutionException {
+
+ // we might get a null context if the target service has
+ // conversational scope but only its callback interface
+ // is conversational. In this case we need to invent a
+ // conversation Id here to store the service against
+ // and populate the thread context
+ if (contextId == null) {
+ contextId = UUID.randomUUID().toString();
+ Message msgContext = ThreadMessageContext.getMessageContext();
+
+ if (msgContext != null) {
+ msgContext.getTo().getReferenceParameters().setConversationID(contextId);
+ }
+ }
+
+ InstanceLifeCycleWrapper anInstanceWrapper = this.instanceLifecycleCollection.get(contextId);
+
+ if (anInstanceWrapper == null && !create)
+ return null;
+
+ if (anInstanceWrapper == null) {
+ anInstanceWrapper = new InstanceLifeCycleWrapper(contextId);
+ this.instanceLifecycleCollection.put(contextId, anInstanceWrapper);
+ }
+ // If an existing instance is found return it only if its not expired and update its
+ // last referenced time.
+ else {
+ if (anInstanceWrapper.isExpired())
+ throw new ConversationEndedException();
+ anInstanceWrapper.updateLastReferencedTime();
+ }
+
+ return anInstanceWrapper.getInstanceWrapper(contextId);
+
+ }
+
+ @Override
+ public InstanceWrapper getWrapper(Object contextId) throws TargetResolutionException {
+ return getInstanceWrapper(true, contextId);
+ }
+
+ /**
+ * This method allows a new context id to be registered alongside an existing one. This happens in
+ * one case, when a conversation includes a stateful callback. The client component instance
+ * must be registered against all outgoing conversation ids so that the component instance
+ * can be found when the callback arrives
+ *
+ * @param existingContextId the context id against which the component is already registered
+ * @param context this should be a conversation object so that the conversation can b stored
+ * and reset when the component instance is removed
+ */
+ public void addWrapperReference(Object existingContextId, Object contextId) throws TargetResolutionException {
+ // get the instance wrapper via the existing id
+ InstanceLifeCycleWrapper existingInstanceWrapper = this.instanceLifecycleCollection.get(existingContextId);
+ InstanceLifeCycleWrapper newInstanceWrapper = this.instanceLifecycleCollection.get(contextId);
+
+ // only add the extra reference once
+ if (newInstanceWrapper == null) {
+ // add the id to the list of ids that the wrapper holds. Used for reference
+ // counting and conversation resetting on destruction.
+ existingInstanceWrapper.addCallbackConversation(contextId);
+
+ // add the reference to the collection
+ this.instanceLifecycleCollection.put(contextId, existingInstanceWrapper);
+ }
+ }
+
+ public void registerWrapper(InstanceWrapper wrapper, Object contextId) throws TargetResolutionException {
+ // if a wrapper for a different instance is already registered for this contextId, remove it
+ InstanceLifeCycleWrapper anInstanceWrapper = this.instanceLifecycleCollection.get(contextId);
+ if (anInstanceWrapper != null) {
+ if (anInstanceWrapper.getInstanceWrapper(contextId).getInstance() != wrapper.getInstance()) {
+ remove(contextId);
+ } else {
+ return;
+ }
+ }
+
+ anInstanceWrapper = new InstanceLifeCycleWrapper(wrapper, contextId);
+ this.instanceLifecycleCollection.put(contextId, anInstanceWrapper);
+ }
+
+ // The remove is invoked when a conversation is explicitly ended. This can occur by using the @EndsConversation or API.
+ // In this case the instance is immediately removed. A new conversation will be started on the next operation
+ // associated with this conversationId's service reference.
+ //
+ @Override
+ public void remove(Object contextId) throws TargetDestructionException {
+ if (contextId != null) {
+ if (this.instanceLifecycleCollection.containsKey(contextId)) {
+ InstanceLifeCycleWrapper anInstanceLifeCycleWrapper = this.instanceLifecycleCollection.get(contextId);
+ this.instanceLifecycleCollection.remove(contextId);
+ anInstanceLifeCycleWrapper.removeInstanceWrapper(contextId);
+ }
+ }
+ }
+
+ /*
+ * This is an inner class that keeps track of the lifecycle of a conversation scoped
+ * implementation instance.
+ *
+ */
+
+ private class InstanceLifeCycleWrapper {
+ private Object clientConversationId;
+ private List<Object> callbackConversations = new ArrayList<Object>();
+ private long creationTime;
+ private long lastReferencedTime;
+ private long expirationInterval;
+ private long maxIdleTime;
+
+ private InstanceLifeCycleWrapper(Object contextId) throws TargetResolutionException {
+ this.clientConversationId = contextId;
+ this.creationTime = System.currentTimeMillis();
+ this.lastReferencedTime = this.creationTime;
+ this.expirationInterval = max_age;
+ this.maxIdleTime = max_idle_time;
+ this.createInstance(contextId);
+ }
+
+ private InstanceLifeCycleWrapper(InstanceWrapper wrapper, Object contextId) throws TargetResolutionException {
+ this.clientConversationId = contextId;
+ this.creationTime = System.currentTimeMillis();
+ this.lastReferencedTime = this.creationTime;
+ this.expirationInterval = max_age;
+ this.maxIdleTime = max_idle_time;
+ wrappers.put(contextId, wrapper);
+ }
+
+ private boolean isExpired() {
+ long currentTime = System.currentTimeMillis();
+ if ((this.lastReferencedTime + this.maxIdleTime) < currentTime) // max idle time exceeded
+ return true;
+ if ((this.creationTime + this.expirationInterval) < currentTime) // max time to live exceeded
+ return true;
+
+ return false;
+ }
+
+ private void updateLastReferencedTime() {
+ this.lastReferencedTime = System.currentTimeMillis();
+ }
+
+ // Associates a callback conversation with this instance. Each time the scope container
+ // is asked to remove an object given a ontextId an associated conversation object will
+ // have its conversationId reset to null. When the list of ids is empty the component instance
+ // will be removed from the scope container
+ private void addCallbackConversation(Object conversationID) {
+ InstanceWrapper ctx = getInstanceWrapper(clientConversationId);
+ callbackConversations.add(conversationID);
+ wrappers.put(conversationID, ctx);
+ }
+
+ //
+ // Return the backing implementation instance
+ //
+ private InstanceWrapper getInstanceWrapper(Object contextId) {
+ InstanceWrapper ctx = wrappers.get(contextId);
+ return ctx;
+ }
+
+ private void removeInstanceWrapper(Object contextId) throws TargetDestructionException {
+ InstanceWrapper ctx = getInstanceWrapper(contextId);
+ wrappers.remove(contextId);
+
+ // find out if we are dealing with the original client conversation id
+ // and reset accordingly
+ if (clientConversationId.equals(contextId)) {
+ clientConversationId = null;
+ } else {
+ // reset the conversationId in the conversation object if present
+ // so that and ending callback causes the conversation in the originating
+ // service reference in the client to be reset
+ callbackConversations.remove(contextId);
+ }
+
+ // stop the component if this removes the last reference
+ if (clientConversationId == null && callbackConversations.isEmpty()) {
+ ctx.stop();
+ }
+ }
+
+ private void createInstance(Object contextId) throws TargetResolutionException {
+ InstanceWrapper instanceWrapper = createInstanceWrapper();
+ instanceWrapper.start();
+ wrappers.put(contextId, instanceWrapper);
+ }
+
+ }
+
+ //
+ // This inner class is an instance reaper. It periodically iterates over the InstanceLifeCycleCollection
+ // and for any instances that have expired removes the backing instance and the entry in the InstanceLifeCycle
+ // Collection.
+ //
+ class ConversationalInstanceReaper implements Runnable {
+ private Map<Object, InstanceLifeCycleWrapper> instanceLifecycleCollection;
+
+ public ConversationalInstanceReaper(Map<Object, InstanceLifeCycleWrapper> aMap) {
+ this.instanceLifecycleCollection = aMap;
+ }
+
+ public void run() {
+ Iterator<Map.Entry<Object, InstanceLifeCycleWrapper>> anIterator =
+ this.instanceLifecycleCollection.entrySet().iterator();
+
+ while (anIterator.hasNext()) {
+ Map.Entry<Object, InstanceLifeCycleWrapper> anEntry = anIterator.next();
+ InstanceLifeCycleWrapper anInstanceLifeCycleWrapper = anEntry.getValue();
+ if (anInstanceLifeCycleWrapper.isExpired()) {
+ try {
+ // cycle through all the references to this instance and
+ // remove them from the underlying wrappers collection and
+ // from the lifecycle wrappers collection
+ for (Object conversationID : anInstanceLifeCycleWrapper.callbackConversations) {
+ anInstanceLifeCycleWrapper.removeInstanceWrapper(conversationID);
+ this.instanceLifecycleCollection.remove(conversationID);
+ }
+
+ if (anInstanceLifeCycleWrapper.clientConversationId != null) {
+ anInstanceLifeCycleWrapper
+ .removeInstanceWrapper(anInstanceLifeCycleWrapper.clientConversationId);
+ this.instanceLifecycleCollection.remove(anInstanceLifeCycleWrapper.clientConversationId);
+ }
+ } catch (Exception ex) {
+ // TODO - what to do with any asynchronous exceptions?
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.core.conversation.ConversationListener#conversationEnded(org.apache.tuscany.sca.core.conversation.ExtendedConversation)
+ */
+ public void conversationEnded(ExtendedConversation conversation) {
+ stopContext(conversation.getConversationID());
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.core.conversation.ConversationListener#conversationExpired(org.apache.tuscany.sca.core.conversation.ExtendedConversation)
+ */
+ public void conversationExpired(ExtendedConversation conversation) {
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.core.conversation.ConversationListener#conversationStarted(org.apache.tuscany.sca.core.conversation.ExtendedConversation)
+ */
+ public void conversationStarted(ExtendedConversation conversation) {
+ startContext(conversation.getConversationID());
+ }
+
+ /**
+ * @return the conversationManager
+ */
+ public ConversationManager getConversationManager() {
+ return conversationManager;
+ }
+
+ /**
+ * @param conversationManager the conversationManager to set
+ */
+ public void setConversationManager(ConversationManager conversationManager) {
+ this.conversationManager = conversationManager;
+ }
+
+}
diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ConversationalScopeContainerFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ConversationalScopeContainerFactory.java new file mode 100644 index 0000000000..a6663aba09 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ConversationalScopeContainerFactory.java @@ -0,0 +1,44 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.store.Store; + +/** + * @version $Rev$ $Date$ + */ +public class ConversationalScopeContainerFactory implements ScopeContainerFactory { + private Store store; + + public ConversationalScopeContainerFactory(Store store) { + super(); + this.store = store; + } + + public ScopeContainer createScopeContainer(RuntimeComponent component) { + return new ConversationalScopeContainer(store, component); + } + + public Scope getScope() { + return Scope.CONVERSATION; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/HttpSessionScopeContainer.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/HttpSessionScopeContainer.java new file mode 100644 index 0000000000..5ae8b94647 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/HttpSessionScopeContainer.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.core.scope; + +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.core.event.HttpSessionEnd; +import org.apache.tuscany.sca.event.Event; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * A scope context which manages atomic component instances keyed on HTTP + * session + * + * @version $Rev$ $Date$ + */ +public class HttpSessionScopeContainer extends AbstractScopeContainer<Object> { + + public HttpSessionScopeContainer(RuntimeComponent component) { + super(Scope.SESSION, component); + } + + @Override + public void onEvent(Event event) { + checkInit(); + if (event instanceof HttpSessionEnd) { + //FIXME key is not used + //Object key = ((HttpSessionEnd)event).getSessionID(); + // FIXME: Remove the session id + } + } + + @Override + public synchronized void start() { + if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) { + throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state [" + lifecycleState + "]"); + } + lifecycleState = RUNNING; + } + + @Override + public synchronized void stop() { + lifecycleState = STOPPED; + } + + protected InstanceWrapper getInstanceWrapper(boolean create) throws TargetResolutionException { +// Object key = workContext.getIdentifier(Scope.SESSION); + // FIXME: Need to fix this + Object key ="http-session-id"; + assert key != null : "HTTP session key not bound in work context"; + InstanceWrapper ctx = wrappers.get(key); + if (ctx == null && !create) { + return null; + } + if (ctx == null) { + ctx = super.createInstanceWrapper(); + ctx.start(); + wrappers.put(key, ctx); + } + return ctx; + } + + @Override + public InstanceWrapper getWrapper(Object contextId) throws TargetResolutionException { + return getInstanceWrapper(true); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/HttpSessionScopeContainerFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/HttpSessionScopeContainerFactory.java new file mode 100644 index 0000000000..49f89661b1 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/HttpSessionScopeContainerFactory.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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * @version $Rev$ $Date$ + */ +public class HttpSessionScopeContainerFactory implements ScopeContainerFactory { + + public HttpSessionScopeContainerFactory() { + super(); + } + + public ScopeContainer createScopeContainer(RuntimeComponent component) { + return new HttpSessionScopeContainer(component); + } + + public Scope getScope() { + return Scope.SESSION; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/RequestScopeContainer.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/RequestScopeContainer.java new file mode 100644 index 0000000000..f11a61e662 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/RequestScopeContainer.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.core.scope; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.core.event.RequestEnd; +import org.apache.tuscany.sca.event.Event; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * A scope context which manages atomic component instances keyed on the current + * request context + * + * @version $Rev$ $Date$ + */ +public class RequestScopeContainer extends AbstractScopeContainer<Thread> { + private final Map<Thread, InstanceWrapper> contexts; + + public RequestScopeContainer(RuntimeComponent component) { + super(Scope.REQUEST, component); + contexts = new ConcurrentHashMap<Thread, InstanceWrapper>(); + } + + @Override + public void onEvent(Event event) { + checkInit(); + if (event instanceof RequestEnd) { + // shutdownInstances(Thread.currentThread()); + } + } + + @Override + public synchronized void start() { + if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) { + throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state [" + lifecycleState + "]"); + } + lifecycleState = RUNNING; + } + + @Override + public synchronized void stop() { + contexts.clear(); + // synchronized (destroyQueues) { + // destroyQueues.clear(); + // } + lifecycleState = STOPPED; + } + + protected InstanceWrapper getInstanceWrapper(boolean create) throws TargetResolutionException { + InstanceWrapper ctx = wrappers.get(Thread.currentThread()); + if (ctx == null && !create) { + return null; + } + if (ctx == null) { + ctx = super.createInstanceWrapper(); + ctx.start(); + wrappers.put(Thread.currentThread(), ctx); + } + return ctx; + } + + @Override + public InstanceWrapper getWrapper(Thread contextId) throws TargetResolutionException { + return getInstanceWrapper(true); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/RequestScopeContainerFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/RequestScopeContainerFactory.java new file mode 100644 index 0000000000..1cfb6b06a4 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/RequestScopeContainerFactory.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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * @version $Rev$ $Date$ + */ +public class RequestScopeContainerFactory implements ScopeContainerFactory { + + public ScopeContainer createScopeContainer(RuntimeComponent component) { + return new RequestScopeContainer(component); + } + + public Scope getScope() { + return Scope.REQUEST; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.java new file mode 100644 index 0000000000..0a20d793f7 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/Scope.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.core.scope; + +/** + * The default implementation scopes supported by assemblies. + * + * @version $Rev$ $Date$ + */ +public class Scope { + public static final Scope STATELESS = new Scope("STATELESS"); + public static final Scope REQUEST = new Scope("REQUEST"); + public static final Scope SESSION = new Scope("SESSION"); + public static final Scope CONVERSATION = new Scope("CONVERSATION"); + public static final Scope COMPOSITE = new Scope("COMPOSITE"); + public static final Scope SYSTEM = new Scope("SYSTEM"); + public static final Scope UNDEFINED = new Scope("UNDEFINED"); + + private String scope; + + public Scope(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 Scope scope1 = (Scope) 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/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java new file mode 100644 index 0000000000..6b2980b989 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainer.java @@ -0,0 +1,159 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.event.RuntimeEventListener; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + + +/** + * Manages the lifecycle and visibility of instances associated with a an {@link RuntimeComponent}. + * + * @version $Rev$ $Date$ + * @param <KEY> the type of IDs that this container uses to identify its contexts. + * For example, for COMPOSITE scope this could be the URI of the composite component, + * or for HTTP Session scope it might be the HTTP session ID. + */ +public interface ScopeContainer<KEY> extends RuntimeEventListener { + + /** + * Returns the Scope that this container supports. + * + * @return the Scope that this container supports + */ + Scope getScope(); + + /** + * Start a new context with the supplied ID. + * + * @param contextId an ID that uniquely identifies the context. + */ + void startContext(KEY contextId); + + /** + * Stop the context with the supplied ID. + * + * @param contextId an ID that uniquely identifies the context. + */ + void stopContext(KEY contextId); + + /** + * Returns an instance wrapper associated with the current scope context, creating one if necessary + * @param contextId the id for the scope context + * + * @return the wrapper for the target instance + * @throws TargetResolutionException if there was a problem instantiating the target instance + */ + InstanceWrapper getWrapper(KEY contextId) throws TargetResolutionException; + + /** + * Allows a component to be registered against more than one context id. This is required in the + * case of stateful callbacks where we want to identify the originating client component instance + * as the callback target but we don't want to reuse the clients original conversation id + * + * @param existingContextId an id that identifies an existing component instance + * @param newContextId a new id against which this component will also be registered + * @throws TargetResolutionException + */ + void addWrapperReference(KEY existingContextId, KEY newContextId) + throws TargetResolutionException; + + /** + * Register an existing instance against a context id. This is needed + * for a stateful callback where the service reference for the forward call + * contains a callback object that is not a service reference. + * + * @param wrapper the instance wrapper for the instance to be registered + * @param contextId the id for the scope context + * @throws TargetResolutionException + */ + void registerWrapper(InstanceWrapper wrapper, KEY contextId) + throws TargetResolutionException; + + /** + * Returns an implementation instance associated with the current scope context. + * If no instance is found, a {@link TargetNotFoundException} is thrown. + * @param contextId the id for the scope context + * + * @return the wrapper for the target instance + * @throws TargetResolutionException if there was a problem instantiating the target instance + */ + InstanceWrapper getAssociatedWrapper(KEY contextId) + throws TargetResolutionException; + + /** + * Return a wrapper after use (for example, after invoking the instance). + * @param wrapper the wrapper for the target instance being returned + * @param contextId the id for the scope context + * + * @throws TargetDestructionException if there was a problem returning the target instance + */ + void returnWrapper(InstanceWrapper wrapper, KEY contextId) + throws TargetDestructionException; + + /** + * Removes an identified component implementation instance associated with the current + * context from persistent storage + * + * @param contextId the identifier of the context to remove. + */ + void remove(KEY contextId) + throws TargetDestructionException; + + /* A configuration error state */ + int CONFIG_ERROR = -1; + /* Has not been initialized */ + int UNINITIALIZED = 0; + /* In the process of being configured and initialized */ + int INITIALIZING = 1; + /* Instantiated and configured */ + int INITIALIZED = 2; + /* Configured and initialized */ + int RUNNING = 4; + /* In the process of being shutdown */ + int STOPPING = 5; + /* Has been shutdown and removed from the composite */ + int STOPPED = 6; + /* In an error state */ + int ERROR = 7; + + /** + * Returns the lifecycle state + * + * @see #UNINITIALIZED + * @see #INITIALIZING + * @see #INITIALIZED + * @see #RUNNING + * @see #STOPPING + * @see #STOPPED + */ + int getLifecycleState(); + + /** + * Starts the Lifecycle. + */ + void start(); + + /** + * Stops the Lifecycle. + */ + void stop(); + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java new file mode 100644 index 0000000000..b19c14b3e0 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeContainerFactory.java @@ -0,0 +1,32 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * Factory to create ScopeContainer for components + * + * @version $Rev$ $Date$ + */ +public interface ScopeContainerFactory { + ScopeContainer createScopeContainer(RuntimeComponent component); + Scope getScope(); +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java new file mode 100644 index 0000000000..43a3288ff2 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistry.java @@ -0,0 +1,43 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + + +/** + * Manages {@link ScopeContainer}s in the runtime + * + * @version $$Rev$$ $$Date$$ + */ +public interface ScopeRegistry { + + /** + * Returns the scope container for the given scope or null if one not found + * + * @param scope the scope + * @return the scope container for the given scope or null if one not found + */ + ScopeContainer getScopeContainer(RuntimeComponent component); + + /** + * @param factory + */ + void register(ScopeContainerFactory factory); +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistryImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistryImpl.java new file mode 100644 index 0000000000..75261e11a8 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopeRegistryImpl.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.scope; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * The default implementation of a scope registry + * + * @version $Rev$ $Date$ + */ +public class ScopeRegistryImpl implements ScopeRegistry { + private final Map<Scope, ScopeContainerFactory> scopeCache = new ConcurrentHashMap<Scope, ScopeContainerFactory>(); + + public void register(ScopeContainerFactory factory) { + scopeCache.put(factory.getScope(), factory); + } + + public ScopeContainer getScopeContainer(RuntimeComponent runtimeComponent) { + if (!(runtimeComponent instanceof ScopedRuntimeComponent)) { + return null; + } + ScopedRuntimeComponent component = (ScopedRuntimeComponent)runtimeComponent; + if (component.getScopeContainer() != null) { + return component.getScopeContainer(); + } + ImplementationProvider implementationProvider = component.getImplementationProvider(); + if (implementationProvider instanceof ScopedImplementationProvider) { + ScopedImplementationProvider provider = (ScopedImplementationProvider)implementationProvider; + Scope scope = provider.getScope(); + if (scope == null) { + scope = Scope.STATELESS; + } + ScopeContainerFactory factory = scopeCache.get(scope); + ScopeContainer container = factory.createScopeContainer(component); + component.setScopeContainer(container); + return container; + } + return null; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java new file mode 100644 index 0000000000..85a6626cdd --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedImplementationProvider.java @@ -0,0 +1,65 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.provider.ImplementationProvider; + +/** + * A component implementation can implement this interface to provide scope + * management for the components + * + * @version $Rev$ $Date$ + */ +public interface ScopedImplementationProvider extends ImplementationProvider { + /** + * Get the scope for the component implementation + * + * @return The scope for the component implementation, if null is returned, + * STATELESS will be used + */ + Scope getScope(); + + /** + * Indicate if the component needs to be eagerly initialized + * + * @return true if the component is marked to be eagerly initialized, false + * otherwise + */ + boolean isEagerInit(); + + /** + * @return the maxAge + */ + long getMaxAge(); + + /** + * @return the maxIdleTime + */ + long getMaxIdleTime(); + + /** + * Create a wrapper for the component instance for the scope management + * + * @return A wrapper for the component instance + */ + InstanceWrapper createInstanceWrapper(); + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.java new file mode 100644 index 0000000000..c27b112f8a --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/ScopedRuntimeComponent.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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * Scoped runtime component + * + * @version $Rev$ $Date$ + */ +public interface ScopedRuntimeComponent extends RuntimeComponent { + /** + * Set the associated scope container + * @param scopeContainer + */ + void setScopeContainer(ScopeContainer scopeContainer); + /** + * Get the assoicated scope container + * @return + */ + ScopeContainer getScopeContainer(); +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/StatelessScopeContainer.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/StatelessScopeContainer.java new file mode 100644 index 0000000000..a2c0edb9b4 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/StatelessScopeContainer.java @@ -0,0 +1,55 @@ +/* + * 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.core.scope; + +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * A scope context which manages stateless atomic component instances in a non-pooled fashion. + * + * @version $Rev$ $Date$ + */ +public class StatelessScopeContainer<KEY> extends AbstractScopeContainer<KEY> { + + public StatelessScopeContainer(RuntimeComponent component) { + super(Scope.STATELESS, component); + } + + @Override + public InstanceWrapper getWrapper(KEY contextId) + throws TargetResolutionException { + InstanceWrapper ctx = createInstanceWrapper(); + ctx.start(); + return ctx; + } + + @Override + public InstanceWrapper getAssociatedWrapper(KEY contextId) + throws TargetResolutionException { + return getWrapper(contextId); + } + + @Override + public void returnWrapper(InstanceWrapper wrapper, KEY contextId) + throws TargetDestructionException { + wrapper.stop(); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/StatelessScopeContainerFactory.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/StatelessScopeContainerFactory.java new file mode 100644 index 0000000000..0471b2c52e --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/StatelessScopeContainerFactory.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.core.scope; + +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * @version $Rev$ $Date$ + */ +public class StatelessScopeContainerFactory implements ScopeContainerFactory { + + public ScopeContainer createScopeContainer(RuntimeComponent component) { + return new StatelessScopeContainer(component); + } + + public Scope getScope() { + return Scope.STATELESS; + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java new file mode 100644 index 0000000000..0f83dad97d --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetDestructionException.java @@ -0,0 +1,44 @@ +/* + * 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.core.scope; + +/** + * Denotes an error destroying a target + * + * @version $Rev$ $Date$ + */ +public class TargetDestructionException extends TargetResolutionException { + private static final long serialVersionUID = -6126684147851674709L; + + public TargetDestructionException() { + super(); + } + + public TargetDestructionException(String message, Throwable cause) { + super(message, cause); + } + + public TargetDestructionException(String message) { + super(message); + } + + public TargetDestructionException(Throwable cause) { + super(cause); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java new file mode 100644 index 0000000000..15959c0608 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetInitializationException.java @@ -0,0 +1,44 @@ +/* + * 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.core.scope; + +/** + * Denotes an error initializing a target + * + * @version $Rev$ $Date$ + */ +public class TargetInitializationException extends TargetResolutionException { + private static final long serialVersionUID = -6228778208649752698L; + + public TargetInitializationException() { + super(); + } + + public TargetInitializationException(String message, Throwable cause) { + super(message, cause); + } + + public TargetInitializationException(String message) { + super(message); + } + + public TargetInitializationException(Throwable cause) { + super(cause); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java new file mode 100644 index 0000000000..6e51a8c9ec --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetNotFoundException.java @@ -0,0 +1,44 @@ +/* + * 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.core.scope; + +/** + * Thrown when a target of an operation cannot be found + * + * @version $$Rev$$ $$Date$$ + */ +public class TargetNotFoundException extends TargetResolutionException { + private static final long serialVersionUID = 5541830480658471186L; + + public TargetNotFoundException() { + super(); + } + + public TargetNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public TargetNotFoundException(String message) { + super(message); + } + + public TargetNotFoundException(Throwable cause) { + super(cause); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java new file mode 100644 index 0000000000..ea8d0e876c --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/scope/TargetResolutionException.java @@ -0,0 +1,44 @@ +/* + * 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.core.scope; + +/** + * Denotes an error retrieving a target instance + * + * @version $Rev$ $Date$ + */ +public class TargetResolutionException extends Exception { + private static final long serialVersionUID = 2912513650522019405L; + + public TargetResolutionException() { + super(); + } + + public TargetResolutionException(String message, Throwable cause) { + super(message, cause); + } + + public TargetResolutionException(String message) { + super(message); + } + + public TargetResolutionException(Throwable cause) { + super(cause); + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/store/MemoryStore.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/store/MemoryStore.java new file mode 100644 index 0000000000..5b838116c5 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/store/MemoryStore.java @@ -0,0 +1,195 @@ +/* + * 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.core.store; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.apache.tuscany.sca.core.event.BaseEventPublisher; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.store.DuplicateRecordException; +import org.apache.tuscany.sca.store.RecoveryListener; +import org.apache.tuscany.sca.store.Store; +import org.apache.tuscany.sca.store.StoreExpirationEvent; +import org.apache.tuscany.sca.store.StoreMonitor; +import org.apache.tuscany.sca.store.StoreWriteException; +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.EagerInit; +import org.osoa.sca.annotations.Init; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Service; + +/** + * Implements a non-durable, non-transactional store using a simple in-memory map + * + * @version $Rev$ $Date$ + */ +@Service(Store.class) +@EagerInit +public class MemoryStore extends BaseEventPublisher implements Store { + private Map<RuntimeComponent, Map<String, Record>> store; + // TODO integrate with a core threading scheme + private ScheduledExecutorService scheduler; + private long reaperInterval = 300000; + private StoreMonitor monitor; + private long defaultExpirationOffset = 600000; // 10 minutes + + public MemoryStore(StoreMonitor monitor) { + this.monitor = monitor; + this.store = new ConcurrentHashMap<RuntimeComponent, Map<String, Record>>(); + this.scheduler = Executors.newSingleThreadScheduledExecutor(); + } + + /** + * Returns the maximum default expiration offset for records in the store + * + * @return the maximum default expiration offset for records in the store + */ + public long getDefaultExpirationOffset() { + return defaultExpirationOffset; + } + + /** + * Sets the maximum default expiration offset for records in the store + */ + @Property + public void setDefaultExpirationOffset(long defaultExpirationOffset) { + this.defaultExpirationOffset = defaultExpirationOffset; + } + + /** + * Sets the interval for expired entry scanning to be performed + */ + @Property + public void setReaperInterval(long reaperInterval) { + this.reaperInterval = reaperInterval; + } + + public long getReaperInterval() { + return reaperInterval; + } + + @Init + public void init() { + scheduler.scheduleWithFixedDelay(new Reaper(), reaperInterval, reaperInterval, TimeUnit.MILLISECONDS); + monitor.start("In-memory store started"); + } + + @Destroy + public void destroy() { + scheduler.shutdown(); + monitor.stop("In-memory store stopped"); + } + + public void insertRecord(RuntimeComponent owner, String id, Object object, long expiration) throws StoreWriteException { + Map<String, Record> map = store.get(owner); + if (map == null) { + map = new ConcurrentHashMap<String, Record>(); + store.put(owner, map); + } + if (map.containsKey(id)) { + throw new DuplicateRecordException("Duplicate record: " + owner.getURI() +" : " + id); + } + map.put(id, new Record(object, expiration)); + } + + public void updateRecord(RuntimeComponent owner, String id, Object object, long expiration) throws StoreWriteException { + Map<String, Record> map = store.get(owner); + if (map == null) { + throw new StoreWriteException("Record not found: " + owner.getURI() +" : " + id); + } + Record record = map.get(id); + if (record == null) { + throw new StoreWriteException("Record not found: " + owner.getURI() +" : " + id); + } + record.data = object; + } + + public Object readRecord(RuntimeComponent owner, String id) { + Map<String, Record> map = store.get(owner); + if (map == null) { + return null; + } + Record record = map.get(id); + if (record != null) { + return record.data; + } + return null; + } + + public void removeRecords() { + store.clear(); + } + + public void removeRecord(RuntimeComponent owner, String id) throws StoreWriteException { + Map<String, Record> map = store.get(owner); + if (map == null) { + throw new StoreWriteException("Owner not found: " + owner.getURI() +" : " + id); + } + if (map.remove(id) == null) { + throw new StoreWriteException("Owner not found: " + owner.getURI() +" : " + id); + } + } + + public void recover(RecoveryListener listener) { + throw new UnsupportedOperationException(); + } + + private class Record { + private Object data; + private long expiration = NEVER; + + public Record(Object data, long expiration) { + this.data = data; + this.expiration = expiration; + } + + public Object getData() { + return data; + } + + public long getExpiration() { + return expiration; + } + } + + private class Reaper implements Runnable { + + public void run() { + long now = System.currentTimeMillis(); + for (Map.Entry<RuntimeComponent, Map<String, Record>> entries : store.entrySet()) { + for (Map.Entry<String, Record> entry : entries.getValue().entrySet()) { + final long expiration = entry.getValue().expiration; + if (expiration != NEVER && now >= expiration) { + RuntimeComponent owner = entries.getKey(); + Object instance = entry.getValue().getData(); + // notify listeners of the expiration + StoreExpirationEvent event = new StoreExpirationEvent(this, owner, instance); + publish(event); + entries.getValue().remove(entry.getKey()); + } + } + } + } + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/Jsr237Work.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/Jsr237Work.java new file mode 100644 index 0000000000..6fe883157f --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/Jsr237Work.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.core.work; + +/* + * JCA work wrapper. + */ +public class Jsr237Work<T extends Runnable> implements commonj.work.Work { + + // Work that is being executed. + private T work; + + /* + * Initializes the work instance. + */ + public Jsr237Work(T work) { + this.work = work; + } + + /* + * Returns the completed work. + */ + public T getWork() { + return work; + } + + /* + * Release the work. + */ + public void release() { + } + + /* + * Work attributes are not daemon. + */ + public boolean isDaemon() { + return false; + } + + /* + * Runs the work. + */ + public void run() { + work.run(); + } +}
\ No newline at end of file diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/Jsr237WorkScheduler.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/Jsr237WorkScheduler.java new file mode 100644 index 0000000000..1abe040c14 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/Jsr237WorkScheduler.java @@ -0,0 +1,165 @@ +/* + * 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.core.work; + +import org.apache.tuscany.sca.work.NotificationListener; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.apache.tuscany.sca.work.WorkSchedulerException; + +import commonj.work.WorkEvent; +import commonj.work.WorkListener; + +/** + * A work scheduler implementation based on a JSR 237 work manager. + * <p/> + * <p/> + * This needs a JSR 237 work manager implementation available for scheduling work. Instances can be configured with a + * work manager implementation that is injected in. It is the responsibility of the runtime environment to make a work + * manager implementaion available. For example, if the managed environment supports work manager the runtime can use + * the appropriate lookup mechanism to inject the work manager implementation. </p> + */ +public class Jsr237WorkScheduler implements WorkScheduler { + + /** + * Underlying JSR-237 work manager + */ + private ThreadPoolWorkManager jsr237WorkManager; + + /** + * Initializes the JSR 237 work manager. + * + * @param jsr237WorkManager JSR 237 work manager. + */ + public Jsr237WorkScheduler() { + jsr237WorkManager = new ThreadPoolWorkManager(10); + } + + /** + * Schedules a unit of work for future execution. The notification listener is used to register interest in + * callbacks regarding the status of the work. + * + * @param work The unit of work that needs to be asynchronously executed. + */ + public <T extends Runnable> void scheduleWork(T work) { + scheduleWork(work, null); + } + + /** + * Schedules a unit of work for future execution. The notification listener is used to register interest in + * callbacks regarding the status of the work. + * + * @param work The unit of work that needs to be asynchronously executed. + * @param listener Notification listener for callbacks. + */ + public <T extends Runnable> void scheduleWork(T work, NotificationListener<T> listener) { + + if (work == null) { + throw new IllegalArgumentException("Work cannot be null"); + } + + Jsr237Work<T> jsr237Work = new Jsr237Work<T>(work); + try { + if (listener == null) { + jsr237WorkManager.schedule(jsr237Work); + } else { + Jsr237WorkListener<T> jsr237WorkListener = new Jsr237WorkListener<T>(listener, work); + jsr237WorkManager.schedule(jsr237Work, jsr237WorkListener); + } + } catch (IllegalArgumentException ex) { + if (listener != null) { + listener.workRejected(work); + } else { + throw new WorkSchedulerException(ex); + } + } catch (Exception ex) { + throw new WorkSchedulerException(ex); + } + + } + + public void destroy() { + jsr237WorkManager.destroy(); + } + + /* + * Worklistener for keeping track of work status callbacks. + * + */ + private class Jsr237WorkListener<T extends Runnable> implements WorkListener { + + // Notification listener + private NotificationListener<T> listener; + + // Work + private T work; + + /* + * Initializes the notification listener. + */ + public Jsr237WorkListener(NotificationListener<T> listener, T work) { + this.listener = listener; + this.work = work; + } + + /* + * Callback when the work is accepted. + */ + public void workAccepted(WorkEvent workEvent) { + T work = getWork(); + listener.workAccepted(work); + } + + /* + * Callback when the work is rejected. + */ + public void workRejected(WorkEvent workEvent) { + T work = getWork(); + listener.workRejected(work); + } + + /* + * Callback when the work is started. + */ + public void workStarted(WorkEvent workEvent) { + T work = getWork(); + listener.workStarted(work); + } + + /* + * Callback when the work is completed. + */ + public void workCompleted(WorkEvent workEvent) { + T work = getWork(); + Exception exception = workEvent.getException(); + if (exception != null) { + listener.workFailed(work, exception); + } else { + listener.workCompleted(work); + } + } + + /* + * Gets the underlying work from the work event. + */ + private T getWork() { + return work; + } + + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/ThreadPoolWorkManager.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/ThreadPoolWorkManager.java new file mode 100644 index 0000000000..60696692e1 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/ThreadPoolWorkManager.java @@ -0,0 +1,219 @@ +/* + * 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.core.work; + +import java.rmi.server.UID; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; + +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.Property; + +import commonj.work.Work; +import commonj.work.WorkEvent; +import commonj.work.WorkException; +import commonj.work.WorkItem; +import commonj.work.WorkListener; +import commonj.work.WorkManager; + +/** + * A thread-pool based implementation for the JSR-237 work manager. + * <p/> + * <p/> + * This implementation supports only local work. + * <p/> + * TODO Elaborate the implementation. </p> + */ +public class ThreadPoolWorkManager implements WorkManager { + + // Map of work items currently handled by the work manager + private Map<WorkItemImpl, WorkListener> workItems = new ConcurrentHashMap<WorkItemImpl, WorkListener>(); + + // Thread-pool + private ExecutorService executor; + + /** + * Initializes the thread-pool. + * + * @param threadPoolSize Thread-pool size. + */ + public ThreadPoolWorkManager(@Property(name = "poolSize") int threadPoolSize) { + executor = Executors.newFixedThreadPool(threadPoolSize); + } + + /** + * Schedules a unit of work asynchronously. + * + * @param work Work that needs to be scheduled. + * @return Work Work item representing the asynchronous work + */ + public WorkItem schedule(Work work) throws IllegalArgumentException { + return schedule(work, null); + } + + /** + * Schedules a unit of work asynchronously. + * + * @param work Work that needs to be scheduled. + * @param workListener Work listener for callbacks. + * @return Work Work item representing the asynchronous work + */ + public WorkItem schedule(Work work, WorkListener workListener) throws IllegalArgumentException { + + WorkItemImpl workItem = new WorkItemImpl(new UID().toString(), work); + if (workListener != null) { + workItems.put(workItem, workListener); + } + workAccepted(workItem, work); + if (scheduleWork(work, workItem)) { + return workItem; + } else { + workItem.setStatus(WorkEvent.WORK_REJECTED); + if (workListener != null) { + workListener.workRejected(new WorkEventImpl(workItem)); + } + throw new IllegalArgumentException("Unable to schedule work"); + } + } + + /** + * Wait for all the specified units of work to finish. + * + * @param works Units of the work that need to finish. + * @param timeout Timeout for waiting for the units of work to finish. + */ + public boolean waitForAll(Collection works, long timeout) { + throw new UnsupportedOperationException("waitForAll not supported"); + } + + /** + * Wait for any of the specified units of work to finish. + * + * @param works Units of the work that need to finish. + * @param timeout Timeout for waiting for the units of work to finish. + */ + public Collection waitForAny(Collection works, long timeout) { + throw new UnsupportedOperationException("waitForAny not supported"); + } + + /** + * Method provided for subclasses to indicate a work accptance. + * + * @param workItem Work item representing the work that was accepted. + * @param work Work that was accepted. + */ + private void workAccepted(final WorkItemImpl workItem, final Work work) { + WorkListener listener = workItems.get(workItem); + if (listener != null) { + workItem.setStatus(WorkEvent.WORK_ACCEPTED); + WorkEvent event = new WorkEventImpl(workItem); + listener.workAccepted(event); + } + } + + /* + * Method to indicate a work start. + */ + private void workStarted(final WorkItemImpl workItem, final Work work) { + WorkListener listener = workItems.get(workItem); + if (listener != null) { + workItem.setStatus(WorkEvent.WORK_STARTED); + WorkEvent event = new WorkEventImpl(workItem); + listener.workStarted(event); + } + } + + /* + * Method to indicate a work completion. + */ + private void workCompleted(final WorkItemImpl workItem, final Work work) { + workCompleted(workItem, work, null); + } + + /* + * Method to indicate a work completion. + */ + private void workCompleted(final WorkItemImpl workItem, final Work work, final WorkException exception) { + WorkListener listener = workItems.get(workItem); + if (listener != null) { + workItem.setStatus(WorkEvent.WORK_COMPLETED); + workItem.setResult(work); + workItem.setException(exception); + WorkEvent event = new WorkEventImpl(workItem); + listener.workCompleted(event); + workItems.remove(workItem); + } + } + + /* + * Schedules the work using the threadpool. + */ + private boolean scheduleWork(final Work work, final WorkItemImpl workItem) { + try { + executor.execute(new DecoratingWork(workItem, work)); + return true; + } catch (RejectedExecutionException ex) { + return false; + } + } + + /* + * Class that decorates the original worker so that it can get callbacks when work is done. + */ + private final class DecoratingWork implements Runnable { + + // Work item for this work. + private WorkItemImpl workItem; + + // The original work. + private Work decoratedWork; + + /* + * Initializes the work item and underlying work. + */ + private DecoratingWork(final WorkItemImpl workItem, final Work decoratedWork) { + this.workItem = workItem; + this.decoratedWork = decoratedWork; + } + + /* + * Overrides the run method. + */ + public void run() { + workStarted(workItem, decoratedWork); + try { + decoratedWork.run(); + workCompleted(workItem, decoratedWork); + } catch (Throwable th) { + workCompleted(workItem, decoratedWork, new WorkException(th.getMessage(), th)); + } + } + + } + + @Destroy + public void destroy() { + executor.shutdown(); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/WorkEventImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/WorkEventImpl.java new file mode 100644 index 0000000000..62ebeea1fb --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/WorkEventImpl.java @@ -0,0 +1,74 @@ +/* + * 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.core.work; + + +import commonj.work.WorkEvent; +import commonj.work.WorkException; +import commonj.work.WorkItem; + +/** + * Default immutable implementation of the <code>WorkEvent</code> class. + */ +class WorkEventImpl implements WorkEvent { + + // Work item for this event + private WorkItem workItem; + + // Exception if something has gone wrong + private WorkException exception; + + /** + * Instantiates the event. + * + * @param workItem Work item for this event. + */ + public WorkEventImpl(final WorkItemImpl workItem) { + this.workItem = workItem; + this.exception = workItem.getException(); + } + + /** + * Returns the work type based on whether the work was accepted, started, + * rejected or completed. + * + * @return Work type. + */ + public int getType() { + return workItem.getStatus(); + } + + /** + * Returns the work item associated with this work type. + * + * @return Work item. + */ + public WorkItem getWorkItem() { + return workItem; + } + + /** + * Returns the exception if the work completed with an exception. + * + * @return Work exception. + */ + public WorkException getException() { + return exception; + } +} diff --git a/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/WorkItemImpl.java b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/WorkItemImpl.java new file mode 100644 index 0000000000..39a7c647f7 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/main/java/org/apache/tuscany/sca/core/work/WorkItemImpl.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.core.work; + +import commonj.work.Work; +import commonj.work.WorkException; +import commonj.work.WorkItem; + +/** + * An identity based immutable implementation of the <code>WorkItem</code> + * interface. + * + */ +class WorkItemImpl implements WorkItem { + + // Id scoped for the VM + private String id; + + // Status + private int status = -1; + + // Result + private Work result; + + // Original work + private Work originalWork; + + // Exception + private WorkException exception; + + /** + * Instantiates an id for this item. + * + * @param id of this work event. + */ + protected WorkItemImpl(final String id, final Work orginalWork) { + this.id = id; + this.originalWork = orginalWork; + } + + /** + * Returns the id. + * + * @return Id of this item. + */ + public String getId() { + return id; + } + + /** + * Returns the original work. + * + * @return Original work. + */ + public Work getOriginalWork() { + return originalWork; + } + + /** + * Returns the work result if the work completed. + * + * @return Work. + * @throws WorkException If the work completed with an exception. + */ + public Work getResult() { + return result; + } + + /** + * Sets the result. + * + * @param result Result. + */ + protected void setResult(final Work result) { + this.result = result; + } + + /** + * Returns the exception if work completed with an exception. + * + * @return Work exception. + */ + protected WorkException getException() { + return exception; + } + + /** + * Sets the exception. + * + * @param exception Exception. + */ + protected void setException(final WorkException exception) { + this.exception = exception; + } + + /** + * Returns the work type based on whether the work was accepted, started, + * rejected or completed. + * + * @return Work status. + */ + public int getStatus() { + return status; + } + + /** + * Sets the status. + * + * @param status Status. + */ + protected void setStatus(final int status) { + this.status = status; + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * Indicates whether some other object is "equal to" this one. + * + * @param obj Object to be compared. + * @return true if this object is the same as the obj argument; false + * otherwise.. + */ + @Override + public boolean equals(final Object obj) { + return (obj != null) && (obj.getClass() == WorkItemImpl.class) && ((WorkItemImpl) obj).id.equals(id); + } + + /** + * Compares this object with the specified object for order. Returns a + * negative integer, zero, or a positive integer as this object is less + * than, equal to, or greater than the specified object. + * + * @param o Object to be compared. + * @return A negative integer, zero, or a positive integer as this object + * is less than, equal to, or greater than the specified object. + * @throws ClassCastException needs better documentation. + */ + public int compareTo(final Object o) { + if (o.getClass() != WorkItemImpl.class) { + throw new ClassCastException(o.getClass().getName()); + } else { + return ((WorkItemImpl) o).getId().compareTo(getId()); + } + } +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/DefaultExtensionPointRegistryTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/DefaultExtensionPointRegistryTestCase.java new file mode 100644 index 0000000000..7b44736d4b --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/DefaultExtensionPointRegistryTestCase.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.core; + +import junit.framework.TestCase; + +public class DefaultExtensionPointRegistryTestCase extends TestCase { + private ExtensionPointRegistry registry; + + @Override + protected void setUp() throws Exception { + super.setUp(); + registry = new DefaultExtensionPointRegistry(); + } + + public void testRegistry() { + MyRegistry service = new MyREgistryImpl(); + registry.addExtensionPoint(service); + assertSame(service, registry.getExtensionPoint(MyRegistry.class)); + registry.removeExtensionPoint(service); + assertNull(registry.getExtensionPoint(MyRegistry.class)); + } + + public static interface MyRegistry { + void doSomething(); + } + + private static class MyREgistryImpl implements MyRegistry { + + public void doSomething() { + } + + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/event/BaseEventPublisherTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/event/BaseEventPublisherTestCase.java new file mode 100644 index 0000000000..2bc78c3d35 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/event/BaseEventPublisherTestCase.java @@ -0,0 +1,98 @@ +/* + * 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.core.event; + + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.event.Event; +import org.apache.tuscany.sca.event.EventFilter; +import org.apache.tuscany.sca.event.EventPublisher; +import org.apache.tuscany.sca.event.RuntimeEventListener; +import org.apache.tuscany.sca.event.TrueFilter; +import org.easymock.EasyMock; + +/** + * @version $Rev$ $Date$ + */ +public class BaseEventPublisherTestCase extends TestCase { + EventPublisher publisher; + + public void testFireListener() { + Event event = new TestEvent(); + RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class); + listener.onEvent(EasyMock.same(event)); + EasyMock.expectLastCall(); + EasyMock.replay(listener); + publisher.addListener(listener); + publisher.publish(event); + EasyMock.verify(listener); + } + + public void testRemoveListener() { + Event event = new TestEvent(); + RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class); + EasyMock.replay(listener); + publisher.addListener(listener); + publisher.removeListener(listener); + publisher.publish(event); + EasyMock.verify(listener); + } + + public void testFalseFilterListener() { + Event event = new TestEvent(); + RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class); + EasyMock.replay(listener); + publisher.addListener(new FalseFilter(), listener); + publisher.publish(event); + EasyMock.verify(listener); + } + + public void testTrueFilterListener() { + Event event = new TestEvent(); + RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class); + listener.onEvent(EasyMock.same(event)); + EasyMock.expectLastCall(); + EasyMock.replay(listener); + publisher.addListener(new TrueFilter(), listener); + publisher.publish(event); + EasyMock.verify(listener); + } + + @Override + protected void setUp() throws Exception { + publisher = new BaseEventPublisher() { + }; + } + + private class TestEvent implements Event { + public Object getSource() { + return null; + } + } + + private class FalseFilter implements EventFilter { + + public boolean match(Event event) { + return false; + } + } + + +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/event/EventTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/event/EventTestCase.java new file mode 100644 index 0000000000..48dcf8df07 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/event/EventTestCase.java @@ -0,0 +1,69 @@ +/* + * 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.core.event; + +import java.net.URI; + +import junit.framework.TestCase; + +/** + * @version $Rev$ $Date$ + */ +public class EventTestCase extends TestCase { + private URI uri = URI.create("foo"); + + public void testCompositeStart() { + ComponentStart event = new ComponentStart(this, uri); + assertEquals(uri, event.getComponentURI()); + } + + public void testCompositeStop() { + ComponentStop event = new ComponentStop(this, uri); + assertEquals(uri, event.getComponentURI()); + } + + public void testHttpSessionStart() { + Object id = new Object(); + HttpSessionStart event = new HttpSessionStart(this, id); + assertEquals(this, event.getSource()); + assertEquals(id, event.getSessionID()); + } + + public void testHttpSessionEnd() { + Object id = new Object(); + HttpSessionEnd event = new HttpSessionEnd(this, id); + assertEquals(this, event.getSource()); + assertEquals(id, event.getSessionID()); + } + + public void testRequestStart() { + RequestStart event = new RequestStart(this); + assertEquals(this, event.getSource()); + } + + public void testReequestEnd() { + RequestEnd event = new RequestEnd(this); + assertEquals(this, event.getSource()); + } + + + @Override + protected void setUp() throws Exception { + } +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainerTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainerTestCase.java new file mode 100644 index 0000000000..64114f7fb2 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/scope/AbstractScopeContainerTestCase.java @@ -0,0 +1,69 @@ +/* + * 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.core.scope; + +import java.net.URI; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.easymock.EasyMock; +import org.easymock.IMocksControl; + +/** + * @version $Rev$ $Date$ + */ +public abstract class AbstractScopeContainerTestCase<T, KEY> extends TestCase { + protected IMocksControl control; + protected ScopeContainer<KEY> scopeContainer; + protected URI groupId; + protected KEY contextId; + protected RuntimeComponent component; + protected ScopedImplementation implementation; + protected InstanceWrapper<T> wrapper; + + @SuppressWarnings("unchecked") + @Override + protected void setUp() throws Exception { + super.setUp(); + control = EasyMock.createStrictControl(); + component = control.createMock(RuntimeComponent.class); + wrapper = control.createMock(InstanceWrapper.class); + implementation = control.createMock(ScopedImplementation.class); + EasyMock.expect(component.getImplementation()).andReturn(implementation).anyTimes(); + } + + protected void preRegisterComponent() throws Exception { + scopeContainer.start(); + EasyMock.expect(implementation.isEagerInit()).andStubReturn(false); + } + + protected void expectCreateWrapper() throws Exception { + EasyMock.expect(implementation.createInstanceWrapper()).andReturn(wrapper); + wrapper.start(); + } + + protected static interface ScopedImplementation extends ScopedImplementationProvider, Implementation { + + } + + +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/store/MemoryStoreTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/store/MemoryStoreTestCase.java new file mode 100644 index 0000000000..d46d77b4b8 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/store/MemoryStoreTestCase.java @@ -0,0 +1,165 @@ +/* + * 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.core.store; + +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.event.RuntimeEventListener; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.store.DuplicateRecordException; +import org.apache.tuscany.sca.store.Store; +import org.apache.tuscany.sca.store.StoreExpirationEvent; +import org.apache.tuscany.sca.store.StoreMonitor; +import org.easymock.EasyMock; +import org.easymock.IAnswer; + +/** + * @version $Rev$ $Date$ + */ +public class MemoryStoreTestCase extends TestCase { + private StoreMonitor monitor; + + public void testEviction() throws Exception { + MemoryStore store = new MemoryStore(monitor); + store.setReaperInterval(10); + store.init(); + RuntimeComponent component = EasyMock.createNiceMock(RuntimeComponent.class); + EasyMock.replay(component); + String id = UUID.randomUUID().toString(); + Object value = new Object(); + store.insertRecord(component, id, value, 1); + Thread.sleep(200); + assertNull(store.readRecord(component, id)); + store.destroy(); + } + + public void testNotifyOnEviction() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class); + listener.onEvent(EasyMock.isA(StoreExpirationEvent.class)); + EasyMock.expectLastCall().andStubAnswer(new IAnswer<Object>() { + public Object answer() throws Throwable { + latch.countDown(); + return null; + } + }); + EasyMock.replay(listener); + MemoryStore store = new MemoryStore(monitor); + store.addListener(listener); + store.setReaperInterval(10); + store.init(); + RuntimeComponent component = EasyMock.createNiceMock(RuntimeComponent.class); + EasyMock.replay(component); + String id = UUID.randomUUID().toString(); + Object value = new Object(); + store.insertRecord(component, id, value, 1); + if (!latch.await(1000, TimeUnit.MILLISECONDS)) { + // failed to notify listener + fail(); + } + EasyMock.verify(listener); + } + + public void testNoEviction() throws Exception { + MemoryStore store = new MemoryStore(monitor); + store.setReaperInterval(10); + store.init(); + RuntimeComponent component = EasyMock.createNiceMock(RuntimeComponent.class); + EasyMock.replay(component); + String id = UUID.randomUUID().toString(); + Object value = new Object(); + store.insertRecord(component, id, value, Store.NEVER); + Thread.sleep(100); + assertNotNull(store.readRecord(component, id)); + store.destroy(); + } + + public void testInsertRecord() throws Exception { + MemoryStore store = new MemoryStore(monitor); + store.setReaperInterval(10); + store.init(); + RuntimeComponent component = EasyMock.createNiceMock(RuntimeComponent.class); + EasyMock.replay(component); + String id = UUID.randomUUID().toString(); + Object value = new Object(); + store.insertRecord(component, id, value, Store.NEVER); + store.destroy(); + } + + public void testInsertAlreadyExists() throws Exception { + MemoryStore store = new MemoryStore(monitor); + store.setReaperInterval(10); + store.init(); + RuntimeComponent component = EasyMock.createMock(RuntimeComponent.class); + EasyMock.expect(component.getURI()).andReturn("component"); + EasyMock.replay(component); + String id = UUID.randomUUID().toString(); + Object value = new Object(); + store.insertRecord(component, id, value, Store.NEVER); + try { + store.insertRecord(component, id, value, Store.NEVER); + fail(); + } catch (DuplicateRecordException e) { + //expected + } + store.destroy(); + } + + public void testUpdateRecord() throws Exception { + MemoryStore store = new MemoryStore(monitor); + store.setReaperInterval(10); + store.init(); + RuntimeComponent component = EasyMock.createNiceMock(RuntimeComponent.class); + EasyMock.replay(component); + String id = UUID.randomUUID().toString(); + Object value = new Object(); + Object newValue = new Object(); + + store.insertRecord(component, id, value, Store.NEVER); + store.updateRecord(component, id, newValue, 1L); + assertEquals(newValue, store.readRecord(component, id)); + store.destroy(); + } + + public void testDeleteRecord() throws Exception { + MemoryStore store = new MemoryStore(monitor); + store.setReaperInterval(10); + store.init(); + RuntimeComponent component = EasyMock.createNiceMock(RuntimeComponent.class); + EasyMock.replay(component); + String id = UUID.randomUUID().toString(); + Object value = new Object(); + + store.insertRecord(component, id, value, Store.NEVER); + store.removeRecord(component, id); + assertNull(store.readRecord(component, id)); + store.destroy(); + } + + @Override + protected void setUp() throws Exception { + monitor = EasyMock.createNiceMock(StoreMonitor.class); + EasyMock.replay(monitor); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/CallbackInterfaceInterceptorTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/CallbackInterfaceInterceptorTestCase.java new file mode 100644 index 0000000000..bc5d426a9f --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/CallbackInterfaceInterceptorTestCase.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.wire; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.core.assembly.EndpointReferenceImpl; +import org.apache.tuscany.sca.core.invocation.CallbackInterfaceInterceptor; +import org.apache.tuscany.sca.core.invocation.MessageFactoryImpl; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Message; +import org.easymock.EasyMock; +import org.osoa.sca.NoRegisteredCallbackException; + +/** + * @version $Rev$ $Date$ + */ +public class CallbackInterfaceInterceptorTestCase extends TestCase { + + public void testHasCallbackObject() { + CallbackInterfaceInterceptor interceptor = new CallbackInterfaceInterceptor(); + Interceptor next = EasyMock.createMock(Interceptor.class); + EasyMock.expect(next.invoke(EasyMock.isA(Message.class))).andReturn(null); + EasyMock.replay(next); + interceptor.setNext(next); + Message msg = new MessageFactoryImpl().createMessage(); + msg.setFrom(new EndpointReferenceImpl("uri")); + msg.getTo().getReferenceParameters().setCallbackObjectID("java:" + System.identityHashCode("ABC")); + interceptor.invoke(msg); + EasyMock.verify(next); + } + + public void testNoCallbackObject() { + CallbackInterfaceInterceptor interceptor = new CallbackInterfaceInterceptor(); + Message msg = new MessageFactoryImpl().createMessage(); + msg.setFrom(new EndpointReferenceImpl("uri")); + msg.getTo().getReferenceParameters().setCallbackObjectID(null); + try { + interceptor.invoke(msg); + fail(); + } catch (NoRegisteredCallbackException e) { + // expected + } + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/InvocationChainImplTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/InvocationChainImplTestCase.java new file mode 100644 index 0000000000..83f7bdd887 --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/InvocationChainImplTestCase.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.core.wire; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.core.invocation.InvocationChainImpl; +import org.apache.tuscany.sca.interfacedef.impl.OperationImpl; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; + +/** + * @version $Rev$ $Date$ + */ +public class InvocationChainImplTestCase extends TestCase { + + public void testInsertAtEnd() throws Exception { + InvocationChain chain = new InvocationChainImpl(new OperationImpl("foo")); + Interceptor inter2 = new MockInterceptor(); + Interceptor inter1 = new MockInterceptor(); + chain.addInterceptor(inter1); + chain.addInterceptor(inter2); + Interceptor head = (Interceptor)chain.getHeadInvoker(); + assertEquals(inter1, head); + assertEquals(inter2, head.getNext()); + assertEquals(inter2, chain.getTailInvoker()); + + } + + private class MockInterceptor implements Interceptor { + + private Invoker next; + + public Message invoke(Message msg) { + return null; + } + + public void setNext(Invoker next) { + this.next = next; + } + + public Invoker getNext() { + return next; + } + + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/NonBlockingInterceptorTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/NonBlockingInterceptorTestCase.java new file mode 100644 index 0000000000..e3fdf483ad --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/core/wire/NonBlockingInterceptorTestCase.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.wire; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.getCurrentArguments; +import static org.easymock.EasyMock.isA; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import junit.framework.TestCase; + +import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor; +import org.apache.tuscany.sca.core.invocation.ThreadMessageContext; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.easymock.EasyMock; +import org.easymock.IAnswer; + +/** + * @version $Rev$ $Date$ + */ +public class NonBlockingInterceptorTestCase extends TestCase { + + public void testInvoke() throws Exception { + WorkScheduler scheduler = createMock(WorkScheduler.class); + scheduler.scheduleWork(isA(Runnable.class)); + expectLastCall().andStubAnswer(new IAnswer<Object>() { + public Object answer() throws Throwable { + Runnable runnable = (Runnable) getCurrentArguments()[0]; + runnable.run(); + return null; + } + }); + replay(scheduler); + Message context = createMock(Message.class); + //String convID = "convID"; + //TODO port to the new way of dealing with conversation IDs later + //EasyMock.expect(context.getConversationID()).andReturn(convID); + EasyMock.replay(context); + ThreadMessageContext.setMessageContext(context); + Message msg = createMock(Message.class); + //TODO port to the new way of dealing with conversation IDs later + //msg.setConversationID(convID); + Interceptor next = EasyMock.createMock(Interceptor.class); + EasyMock.expect(next.invoke(EasyMock.eq(msg))).andReturn(msg); + EasyMock.replay(next); + EasyMock.replay(msg); + Interceptor interceptor = new NonBlockingInterceptor(scheduler, next); + interceptor.invoke(msg); + verify(context); + verify(next); + verify(msg); + } + +} diff --git a/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/scope/ScopeTestCase.java b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/scope/ScopeTestCase.java new file mode 100644 index 0000000000..341d889b7d --- /dev/null +++ b/branches/sca-java-1.0/modules/core/src/test/java/org/apache/tuscany/sca/scope/ScopeTestCase.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.scope; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.core.scope.Scope; + +/** + * @version $Rev$ $Date$ + */ +public class ScopeTestCase extends TestCase { + + public void testEquals() throws Exception { + Scope scope = new Scope("COMPOSITE"); + assertTrue(scope.equals(Scope.COMPOSITE)); + } + + public void testEqualsNew() throws Exception { + Scope foo = new Scope("foo"); + Scope foo2 = new Scope("FOO"); + assertTrue(foo.equals(foo2)); + } + + public void testNotEquals() throws Exception { + Scope foo = new Scope("BAR"); + Scope foo2 = new Scope("FOO"); + assertFalse(foo.equals(foo2)); + } + + public void testNotEqualsDifferent() throws Exception { + Scope foo = new Scope("FOO"); + assertFalse(foo.equals(new Bar("FOO"))); + } + + public class Bar { + String scope; + + public Bar(String scope) { + this.scope = scope; + } + } + + +} |