Browse files

Initial Commit.

  • Loading branch information...
0 parents commit 97317d8e1025b61bd3f521f3cd3a9b687326e564 Jim Carroll committed Apr 17, 2012
Showing with 16,061 additions and 0 deletions.
  1. +202 −0 LICENSE.txt
  2. +66 −0 README.md
  3. +14 −0 lib-dempsyapi/pom.xml
  4. +48 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/Adaptor.java
  5. +41 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/DempsyException.java
  6. +33 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/Dispatcher.java
  7. +41 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/Activation.java
  8. +43 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/MessageHandler.java
  9. +36 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/MessageKey.java
  10. +42 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/MessageProcessor.java
  11. +39 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/Output.java
  12. +41 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/Passivation.java
  13. +47 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/Start.java
  14. +244 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/config/ApplicationDefinition.java
  15. +224 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/config/ClusterDefinition.java
  16. +109 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/config/ClusterId.java
  17. +63 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/config/OutputSchedule.java
  18. +63 −0 lib-dempsyapi/src/main/java/com/nokia/dempsy/internal/util/SafeString.java
  19. +257 −0 lib-dempsyapi/src/test/java/com/nokia/dempsy/config/TestConfig.java
  20. +21 −0 lib-dempsycore/pom.xml
  21. +25 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Destination.java
  22. +49 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Listener.java
  23. +40 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/MessageTransportException.java
  24. +34 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/OverflowHandler.java
  25. +27 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Receiver.java
  26. +34 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Sender.java
  27. +36 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/SenderFactory.java
  28. +52 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Transport.java
  29. +102 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/util/QueuingReceiver.java
  30. +98 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/monitoring/StatsCollector.java
  31. +28 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/monitoring/StatsCollectorFactory.java
  32. +92 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/mpcluster/MpCluster.java
  33. +26 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/mpcluster/MpClusterException.java
  34. +40 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/mpcluster/MpClusterSession.java
  35. +22 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/mpcluster/MpClusterSessionFactory.java
  36. +48 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/mpcluster/MpClusterSlot.java
  37. +22 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/mpcluster/MpClusterWatcher.java
  38. +24 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/router/ClusterInformation.java
  39. +36 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/router/CurrentClusterCheck.java
  40. +98 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/router/RoutingStrategy.java
  41. +82 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/router/SlotInformation.java
  42. +30 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/serialization/SerializationException.java
  43. +37 −0 lib-dempsycore/src/main/java/com/nokia/dempsy/serialization/Serializer.java
  44. +82 −0 lib-dempsyimpl/pom.xml
  45. +599 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/Dempsy.java
  46. +30 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/container/ContainerException.java
  47. +559 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/container/MpContainer.java
  48. +247 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/container/internal/AnnotatedMethodInvoker.java
  49. +253 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/container/internal/LifecycleHelper.java
  50. +142 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/container/internal/TimedCount.java
  51. +156 −0 ...empsyimpl/src/main/java/com/nokia/dempsy/messagetransport/blockingqueue/BlockingQueueAdaptor.java
  52. +34 −0 ...yimpl/src/main/java/com/nokia/dempsy/messagetransport/blockingqueue/BlockingQueueDestination.java
  53. +117 −0 ...dempsyimpl/src/main/java/com/nokia/dempsy/messagetransport/blockingqueue/BlockingQueueSender.java
  54. +53 −0 ...mpl/src/main/java/com/nokia/dempsy/messagetransport/blockingqueue/BlockingQueueSenderFactory.java
  55. +68 −0 ...psyimpl/src/main/java/com/nokia/dempsy/messagetransport/blockingqueue/BlockingQueueTransport.java
  56. +107 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/messagetransport/passthrough/PassthroughTransport.java
  57. +66 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/messagetransport/tcp/TcpDestination.java
  58. +444 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/messagetransport/tcp/TcpReceiver.java
  59. +135 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/messagetransport/tcp/TcpSender.java
  60. +79 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/messagetransport/tcp/TcpSenderFactory.java
  61. +57 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/messagetransport/tcp/TcpTransport.java
  62. +141 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/monitoring/coda/MetricsReporterSpec.java
  63. +21 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/monitoring/coda/MetricsReporterType.java
  64. +231 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/monitoring/coda/StatsCollectorCoda.java
  65. +155 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/monitoring/coda/StatsCollectorFactoryCoda.java
  66. +232 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/mpcluster/invm/LocalVmMpClusterSessionFactory.java
  67. +574 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/mpcluster/zookeeper/ZookeeperSession.java
  68. +64 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/mpcluster/zookeeper/ZookeeperSessionFactory.java
  69. +34 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/router/AlwaysInCurrentCluster.java
  70. +262 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/router/DefaultRoutingStrategy.java
  71. +489 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/router/Router.java
  72. +50 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/router/SpecificClusterCheck.java
  73. +64 −0 lib-dempsyimpl/src/main/java/com/nokia/dempsy/serialization/java/JavaSerializer.java
  74. +501 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/TestDempsy.java
  75. +567 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/container/TestInstanceManager.java
  76. +288 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/container/TestInvocation.java
  77. +250 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/container/TestMpContainer.java
  78. +537 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/container/TestMpContainerLoadHandling.java
  79. +43 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/container/mocks/ContainerTestMessage.java
  80. +60 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/container/mocks/MockInputMessage.java
  81. +47 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/container/mocks/MockOutputMessage.java
  82. +54 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/container/mocks/OutputMessage.java
  83. +239 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/messagetransport/blockingqueue/BlockingQueueTest.java
  84. +81 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/messagetransport/tcp/TcpTransportMockitoTest.java
  85. +607 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/messagetransport/tcp/TcpTransportTest.java
  86. +141 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/monitoring/basic/BasicStatsCollector.java
  87. +34 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/monitoring/basic/BasicStatsCollectorFactory.java
  88. +107 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/monitoring/coda/TestStatsCollectorCoda.java
  89. +343 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/mpcluster/TestAllMpClusterImpls.java
  90. +187 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/mpcluster/zookeeper/FullApplication.java
  91. +52 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/mpcluster/zookeeper/OtherNode.java
  92. +594 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/mpcluster/zookeeper/TestFullApp.java
  93. +103 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/mpcluster/zookeeper/TestZookeeperClusterImpl.java
  94. +340 −0 ...dempsyimpl/src/test/java/com/nokia/dempsy/mpcluster/zookeeper/TestZookeeperClusterResilience.java
  95. +181 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/mpcluster/zookeeper/ZookeeperTestServer.java
  96. +99 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/router/MpClusterTestImpl.java
  97. +135 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/router/TestRouterClusterManagement.java
  98. +117 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/router/TestRouterInstantiation.java
  99. +84 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/serialization/java/MockClass.java
  100. +47 −0 lib-dempsyimpl/src/test/java/com/nokia/dempsy/serialization/java/TestDefaultSerializer.java
  101. +33 −0 lib-dempsyimpl/src/test/resources/RouterConfigTest.xml
  102. +65 −0 lib-dempsyimpl/src/test/resources/TestMPContainer.xml
  103. +49 −0 lib-dempsyimpl/src/test/resources/blockingqueueTest2AppContext.xml
  104. +52 −0 lib-dempsyimpl/src/test/resources/blockingqueueTestAppContext.xml
  105. +30 −0 lib-dempsyimpl/src/test/resources/fullApp/Dempsy-FullUp.xml
  106. +30 −0 lib-dempsyimpl/src/test/resources/fullApp/Dempsy.xml
  107. +12 −0 lib-dempsyimpl/src/test/resources/fullApp/DempsyApplicationContext-FullApp.xml
  108. +22 −0 lib-dempsyimpl/src/test/resources/log4j.properties
  109. +53 −0 lib-dempsyimpl/src/test/resources/overflowTest2AppContext.xml
  110. +53 −0 lib-dempsyimpl/src/test/resources/overflowTestAppContext.xml
  111. +9 −0 lib-dempsyimpl/src/test/resources/testDempsy/ClusterManager-LocalVmActx.xml
  112. +20 −0 lib-dempsyimpl/src/test/resources/testDempsy/ClusterManager-ZookeeperActx.xml
  113. +41 −0 lib-dempsyimpl/src/test/resources/testDempsy/Dempsy-InValidClusterStart.xml
  114. +41 −0 lib-dempsyimpl/src/test/resources/testDempsy/Dempsy-IndividualClusterStart.xml
  115. +30 −0 lib-dempsyimpl/src/test/resources/testDempsy/Dempsy.xml
  116. +59 −0 lib-dempsyimpl/src/test/resources/testDempsy/MultistageApplicationExplicitDestinationsActx.xml
  117. +39 −0 lib-dempsyimpl/src/test/resources/testDempsy/SimpleMultistageApplicationActx.xml
  118. +27 −0 lib-dempsyimpl/src/test/resources/testDempsy/SinglestageApplicationActx.xml
  119. +33 −0 lib-dempsyimpl/src/test/resources/testDempsy/SinglestageOutputApplicationActx.xml
  120. +10 −0 lib-dempsyimpl/src/test/resources/testDempsy/Transport-BlockingQueueActx.xml
  121. +10 −0 lib-dempsyimpl/src/test/resources/testDempsy/Transport-PassthroughActx.xml
  122. +10 −0 lib-dempsyimpl/src/test/resources/testDempsy/Transport-TcpActx.xml
  123. +14 −0 lib-dempsyimpl/src/test/resources/testDempsy/Transport-TcpWithOverflowActx.xml
  124. +39 −0 lib-dempsyspring/pom.xml
  125. +110 −0 lib-dempsyspring/src/main/java/com/nokia/dempsy/spring/RunAppInVm.java
  126. +150 −0 lib-dempsyspring/src/main/java/com/nokia/dempsy/spring/RunNode.java
  127. +46 −0 lib-dempsyspring/src/main/resources/Dempsy-distributed.xml
  128. +35 −0 lib-dempsyspring/src/main/resources/Dempsy-localVm.xml
  129. +106 −0 lib-dempsyspring/src/test/java/com/nokia/dempsy/spring/SimpleAppForTesting.java
  130. +143 −0 lib-dempsyspring/src/test/java/com/nokia/dempsy/spring/TestRunAppInVm.java
  131. +202 −0 lib-dempsyspring/src/test/java/com/nokia/dempsy/spring/TestRunNode.java
  132. +31 −0 lib-dempsyspring/src/test/resources/DempsyApplicationContext-testApp1.xml
  133. +31 −0 lib-dempsyspring/src/test/resources/TestDempsyApplication.xml
  134. +20 −0 lib-dempsyspring/src/test/resources/log4j.properties
  135. +267 −0 pom.xml
202 LICENSE.txt
@@ -0,0 +1,202 @@
+
+ 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.
66 README.md
@@ -0,0 +1,66 @@
+# Overview
+
+## What is Dempsy?
+
+In a nutshell, Dempsy is a framework that provides for the easy implementation Stream-based, Real-time, BigData applications.
+
+Dempsy is the Nokia's "Distributed Elastic Message Processing System."
+* Dempsy is _Distributed_. That is to say a dempsy application can run on multiple JVMs on multiple physical machines.
+* Dempsy is _Elastic_. That is, it is relatively simple to scale an application to more (or fewer) nodes. This does not require code or configuration changes but allows the dynamic insertion and removal of processing nodes.
+* Dempsy is _Message Processing_. Dempsy fundamentally works by message passing. It moves messages between Message processors, which act on the messages to perform simple atomic operations such as enrichment, transformation, or other processing. Generally an application is intended to be broken down into more smaller simpler processors rather than fewer large complex processors.
+* Dempsy is a _Framework_. It is not an application container like a J2EE container, nor a simple library. Instead, like the [Spring Framework|http://www.springsource.org] it is a collection of patterns, the libraries to enable those patterns, and the interfaces one must implement to use those libraries to implement the patterns.
+
+## What Problem is Dempsy solving?
+
+Dempsy is not designed to be a general purpose framework, but is intended to solve a certain class of problems while encouraging the use of the best software development practices.
+
+Dempsy is meant to solve the problem of processing large amounts of "near real time" stream data with the lowest lag possible; problems where latency is more important that "guaranteed delivery." This class of problems includes use cases such as:
+* Real time monitoring of large distributed systems
+* Processing complete rich streams of social networking data
+* Real time analytics on log information generated from widely distributed systems
+* Statistical analytics on real-time vehicle traffic information on a global basis
+
+It is meant to provide developers with a tool that allows them to solve these problems in a simple straightforward manner by allowing them to concentrate on the analytics themselves rather than the infrastructure. Dempsy heavily emphasizes "separation of concerns" through "dependency injection" and out of the box supports both Spring and Guice. It does all of this by supporting what can be (almost) described as a "distributed actors model."
+
+In short Dempsy is a framework to enable decomposing a large class of message processing applications into flows of messages to relatively simple processing units implemented as [POJOs](http://en.wikipedia.org/wiki/Plain_Old_Java_Object)
+
+### What is a Distributed Actor Framework?
+
+Dempsy has been described as a distributed actor framework. While not strictly speaking an [actor](http://en.wikipedia.org/wiki/Actor_model) framework in the sense of [Erlang](http://www.erlang.org) or [Akka](http://akka.io) actors, in that actors typically direct messages directly to other actors, the Message Processors in Dempsy are "actor like POJOs" similar to Processor Elements in [S4](http://s4.io) and less so like Bolts in [Storm](https://github.com/nathanmarz/storm). Message processors are similar to actors in that Message processors act on a single message at a time, and need not deal with concurrency directly. Unlike actors, Message Processors also are relieved of the the need to know the destination(s) for their output messages, as this is handled inside the Dempsy Distributor.
+
+The Actors model is an approach to concurrent programming that has the following features:
+
+* **Fine-grained processing**
+
+A traditional (linear) programming model processes input sequentially, maintaining whatever state is needed to represent the entire input space. In an Actor model, input is divided into messages and distributed to a large number of independent actors. An individual actor maintains only the state needed to process the messages that it receives.
+
+* **Shared-Nothing**
+
+Each actor maintains its own state, and does not expose that state to any other actor. This eliminates concurrency bottlenecks and the potential for deadlocks. Immutable state (eg, a road network artifact) may be shared between actors.
+
+* **Message-Passing**
+
+Actors communicate by sending immutable messages to one-another. Each message has a key, and the framework is responsible for directing the message to the actor responsible for that key.
+
+A distributed actors model takes an additional step, of allowing actors to exist on multiple nodes in a cluster, and supporting communication of messages between nodes. It adds the following complexities to the Actors model:
+
+* **Distribution of Messages**
+
+A message may or may not be consumed by an actor residing in the same JVM as the actor that sent the message. The required network communication will add delay to processing, and require physical network configuration to support bandwidth requirements and minimize impact to other consumers.
+
+* **Load-Balancing**
+
+The framework must distribute work evenly between nodes, potentially using different strategies for different message types (eg: regional grouping for map-matcher, simple round-robin for vehicles).
+
+* **Node Failure**
+
+If a node fails, the workload on that node must be shifted to other nodes. All state maintained by actors on the failed node is presumed lost.
+
+* **Network Partition**
+
+If the network connection to a node temporarily drops, it will appear as a node failure to other nodes in the cluster. The node must itself recognize that it is no longer part of the cluster, and its actors must stop sending messages (which may conflict with those sent by the cluster's "replacement" node).
+
+* **Node Addition**
+
+To support elastic scalability (adding nodes on demand to service load, as well as re-integration of a previously failed node), the framework must support redistribution of actors _and their state_ based on changes to the cluster.
+
14 lib-dempsyapi/pom.xml
@@ -0,0 +1,14 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.nokia.dempsy</groupId>
+ <artifactId>dempsy-parent</artifactId>
+ <version>01.01-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>lib-dempsyapi</artifactId>
+ <name>Distributed Message Processing Framework - App developer API</name>
+
+</project>
48 lib-dempsyapi/src/main/java/com/nokia/dempsy/Adaptor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy;
+
+/**
+ * An {@link Adaptor} is used to adapt data streams from external sources
+ * into Dempsy. Most Dempsy applictations contain at least one adaptor. The
+ * Adaptor needs to simply acquire the data meant to be processed by Dempsy
+ * and use the {@link Dispatcher} to send the message onward.
+ */
+public interface Adaptor
+{
+ /**
+ * This will be called by Dempsy to provide the {@link Dispatcher} to the
+ * Adaptor. Any object that is the Dispatched will be sent to message
+ * processors.
+ */
+ public void setDispatcher(Dispatcher dispatcher);
+
+ /**
+ * start will be called by Dempsy to tell the Adaptor that it can begin
+ * dispatching messages with the {@link Dispatcher}. start() will always be
+ * called after Adpator.setDispatcher. This method is not expected to return
+ * until {@link Adaptor.stop()} is called from another thread.
+ */
+ public void start();
+
+ /**
+ * This will be called by Dempsy in order to get the Adaptor to stop. Under normal circumstances
+ * the "start()" is still executing and the "stop()" should cause the "start()" to return. If
+ * it doesn't then Dempsy will most likely hang.
+ */
+ public void stop();
+}
41 lib-dempsyapi/src/main/java/com/nokia/dempsy/DempsyException.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy;
+
+/**
+ * Checked Exception used by the Dispatch interface and also internal to
+ * the Dempsy framework.
+ */
+public class DempsyException extends Exception
+{
+ private static final long serialVersionUID = 1L;
+
+ public DempsyException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public DempsyException(String message)
+ {
+ super(message);
+ }
+
+ public DempsyException(Throwable cause)
+ {
+ super(cause);
+ }
+}
33 lib-dempsyapi/src/main/java/com/nokia/dempsy/Dispatcher.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy;
+
+import com.nokia.dempsy.annotations.MessageKey;
+
+
+/**
+ * <p>Implementations of this interface accept messages pushed from a source.
+ * This is primarily exposed to the application developer to support the
+ * development of {@link Adaptor}s. An adaptor needs to take data from an external
+ * source, and provide a routable message (one with a {@link MessageKey} to the
+ * Dempsy framework. {@link Adaptor}s will be provided a {@link Dispatcher},
+ * which constitutes a handle to the Dempsy message bus.</p>
+ */
+public interface Dispatcher
+{
+ public void dispatch(Object message);
+}
41 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/Activation.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * <p>Marker annotation to tell the Container that a method should be called
+ * during {@link MessageProcessor} activation. This method must take a single
+ * <code>byte[]</code> (this may change to an {@link Object}) containing
+ * activation data, which may be <code>null</code>.</p>
+ *
+ * <p>Only one method in a class should be marked as an activation method. If
+ * multiple methods are so annotated, the behavior is undefined. For this
+ * reason, this annotation is not inherited; subclasses must explicitly call
+ * their parent's activation methods.</p>
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Activation
+{
+ // nothing to see here, move along
+}
43 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/MessageHandler.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.nokia.dempsy.Dispatcher;
+
+
+/**
+ * <p>Marker annotation to tell the Message Dispatcher that a method is responsible
+ * for handling a message. The method must take a single parameter, which may be
+ * a concrete class or interface type. If concrete, the {@link Dispatcher} will invoke
+ * the method for messages of any concrete subclass that is not already handled
+ * by another method.</p>
+ *
+ * <p>Multiple methods may be so annotated, and the annotation is inherited.</p>
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface MessageHandler
+{
+ // nothing to see here, move along
+}
36 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/MessageKey.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Marker annotation to tell the framework which method to invoke to get the
+ * key of a message.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface MessageKey
+{
+ // nothing to see here, move along
+}
42 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/MessageProcessor.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * <p>Marker annotation to tell the message dispatcher that the annotated object
+ * can receive messages.</p>
+ *
+ * <p>This annotation is inherited; you can subclass a {@link MessageProcessor} and
+ * declare the annotation on the parent class.</p>
+ *
+ * <p>A {@link MessageProcessor} is required to have at least one method annotated
+ * as a {@link MessageHandler} to receive messages being passed through Dempsy.</p>
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface MessageProcessor
+{
+ // nothing to see here, move along
+}
39 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/Output.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Marker annotation to tell the Container that a method should be called
+ * during a container-wide output operation. This method must not take any
+ * parameters.
+ * <p>
+ * Only one method in a class should be marked as an output method. If
+ * multiple methods are so annotated, the behavior is undefined. For this
+ * reason, this annotation is not inherited.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Output
+{
+ // nothing to see here, move along
+}
41 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/Passivation.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Marker annotation to tell the Container that a method should be called
+ * during MP passivation. This method must not take any parameters, and must
+ * return a <code>byte[]</code> containing passivation data (it may return
+ * <code>null</code>).
+ * <p>
+ * Only one method in a class should be marked as an passivation method. If
+ * multiple methods are so annotated, the behavior is undefined. For this
+ * reason, this annotation is not inherited; subclasses must explicitly call
+ * their parent's passivation methods.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Passivation
+{
+ // nothing to see here, move along
+}
47 lib-dempsyapi/src/main/java/com/nokia/dempsy/annotations/Start.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate a method on a MessageProcessor that should
+ * be called during the start dempsy, after setting the prototype, but before
+ * initializing the listener or accepting any messages. That implies it is also
+ * before cloning any MessageProcessor instances.
+ *
+ * Hopefully, most MessageProcessors are stateless except for the per instance state.
+ * In some cases, however, there is shared static state for the MessageProcessor
+ * instances. In that case, this annotation guarantees that the method annotated will
+ * be called only in the cluster where that MessageProcessor is used (thus it is an
+ * improvement on using an <code>init-method</code> in Spring), and before dispatching
+ * any messages (thus it is simpler than lazy initialization on the first message in that
+ * it avoids concurrency concerns in the application code.)
+ *
+ * Only one such method may be annotated with this Annotation per MessageProcessor
+ *
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface Start {
+
+}
244 lib-dempsyapi/src/main/java/com/nokia/dempsy/config/ApplicationDefinition.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.nokia.dempsy.Adaptor;
+import com.nokia.dempsy.DempsyException;
+import com.nokia.dempsy.annotations.MessageProcessor;
+import com.nokia.dempsy.internal.util.SafeString;
+
+/**
+ * <p>Configuration should be thought of as an xpath with {@link ApplicationDefinition}
+ * at the root element and {@link ClusterDefinition}s as the child elements. It's used
+ * to layout the topology of an entire Dempsy appliation. Let's say the following simple
+ * processing pipeline constitutes a Dempsy application:</p>
+ * <pre>
+ * <code>
+ * SimpleAdaptor -> SimpleMessageProcessor
+ * </code>
+ * </pre>
+ * <p>The straightforward configuration that accepts all of the defaults would be:</p>
+ * <pre>
+ * <code>
+ * new ApplicationDefinition("my-application").add(
+ * new ClusterDefinition("adaptor-stage",new SimpleMessageAdaptor()),
+ * new ClusterDefinition("processor-stage",new SimpleMessageProcessor()));
+ * </code>
+ * </pre>
+ * <p>As an example using Spring, your application context would contain:</p>
+ * <pre>
+ * <code>
+ * &lt;bean class="com.nokia.dempsy.config.ApplicationDefinition"&gt;
+ * &lt;property name="applicationName" value="my-application" /&gt;
+ * &lt;property name="clusterDefinitions"&gt;
+ * &lt;list&gt;
+ * &lt;bean class="com.nokia.dempsy.config.ClusterDefinition"&gt;
+ * &lt;constructor-arg name="clusterName" value="adaptor-stage" /&gt;
+ * &lt;property name="adaptor" &gt;
+ * &lt;bean class="SimpleMessageAdaptor" /&gt;
+ * &lt;/property&gt;
+ * &lt;/bean&gt;
+ * &lt;bean class="com.nokia.dempsy.config.ClusterDefinition"&gt;
+ * &lt;constructor-arg name="clusterName" value="processor-stage" /&gt;
+ * &lt;property name="messageProcessorPrototype"&gt;
+ * &lt;bean class="SimpleMessageProcessor" /&gt;
+ * &lt;/property&gt;
+ * &lt;/bean&gt;
+ * &lt;/list&gt;
+ * &lt;/property&gt;
+ * &lt;/bean&gt;
+ * </code>
+ * </pre>
+ *
+ * <p>Notice, when using a dependency injection framework, you have the ability to configure
+ * your prototypes ({@link MessageProcessor}s) and {@link Adaptor}s independently from
+ * Dempsy. The Dempsy {@link ApplicationDefinition} would then be the point where you define
+ * the topology of processing chain. This nicely decouples the two concerns.</p>
+ *
+ * <p>While any DI framework can be used if you then join the {@link ApplicationDefinition} to
+ * a Dempy instance (by hand), this is unnecessary when using either Spring or Guice as both
+ * are supported out-of-the-box.</p>
+ *
+ * <p>Note: for ease of use when configuring by hand (not using a dependency injection framework
+ * like Spring or Guice) all "setters" (all 'mutators' in general) return the {@link ApplicationDefinition}
+ * itself for the purpose of chaining.</p>
+ */
+public class ApplicationDefinition
+{
+ private List<ClusterDefinition> clusterDefinitions = new ArrayList<ClusterDefinition>();
+ private String applicationName = null;
+ private boolean isInitialized = false;
+ private Object serializer;
+ private Object routingStrategy;
+ private Object statsCollectorFactory;
+
+ public ApplicationDefinition(String applicationName) { this.applicationName = applicationName; }
+
+ //------------------------------------------------------------------------
+ // Simple bean attributes/injection points
+ //------------------------------------------------------------------------
+
+ /**
+ * Get the currently set application name for this {@link ApplicationDefinition}.
+ */
+ public String getApplicationName() { return applicationName; }
+
+ /**
+ * Provides for a dependency injection framework's, setter injection of the {@link ClusterDefinition}s
+ */
+ public ApplicationDefinition setClusterDefinitions(List<ClusterDefinition> clusterDefs)
+ {
+ this.clusterDefinitions.clear();
+ this.clusterDefinitions.addAll(clusterDefs);
+ isInitialized = false;
+ return this;
+ }
+
+ /**
+ * Get the currently set {@link ClusterDefinition}s for this {@link ApplicationDefinition}.
+ */
+ public List<ClusterDefinition> getClusterDefinitions() { return Collections.unmodifiableList(clusterDefinitions); }
+
+ /**
+ * When configuring by hand, this method
+ * @param clusterDefinitions
+ * @return
+ */
+ public ApplicationDefinition add(ClusterDefinition... clusterDefinitions)
+ {
+ this.clusterDefinitions.addAll(Arrays.asList(clusterDefinitions));
+ return this;
+ }
+
+ /**
+ * Get the currently overridden serializer for this {@link ApplicationDefinition}
+ */
+ public Object getSerializer() { return serializer; }
+
+ /**
+ * Override the default serializer for this {@link ApplicationDefinition}. Note
+ * the Object passed must be an instance of {@code com.nokia.dempsy.serializer.Serializer}
+ */
+ public ApplicationDefinition setSerializer(Object serializer) { this.serializer = serializer; return this; }
+
+ /**
+ * Get the currently overridden RoutingStrategy for this {@link ApplicationDefinition}
+ */
+ public Object getRoutingStrategy() { return routingStrategy; }
+
+ /**
+ * Override the default RoutingStrategy for this {@link ApplicationDefinition}. Note
+ * the Object passed must be an instance of {@code com.nokia.dempsy.routing.RoutingStrategy}.
+ * Note that RoutingStrategy overriding is not for the faint of heart. We plan
+ * on eventually providing a standard means of selected between out-of-the-box
+ * RoutingStrategys.
+ */
+ public ApplicationDefinition setRoutingStrategy(Object routingStrategy) { this.routingStrategy = routingStrategy; return this; }
+
+ /**
+ * Get the currently overridden StatsCollector for this {@link ApplicationDefinition}
+ */
+ public Object getStatsCollectorFactory() {return statsCollectorFactory; }
+
+ /**
+ * Override the default StatsCollector for this {@link ApplicationDefinition}
+ * Note the Object passed must be an instance of {@code com.nokia.dempsy.monitoring.StatsCollectorFactory}.
+ * While this could be used to completely replace the implementation of the {@link StatsCollector},
+ * a more common use case would be to define one or more {@link MetricsReporterSpec}s to the default factory.
+ * in order to emit statistics to monitors like Graphite or Ganglia.
+ */
+ public ApplicationDefinition setStatsCollectorFactory(Object statsCollectorFactory)
+ {
+ this.statsCollectorFactory = statsCollectorFactory;
+ return this;
+ }
+//------------------------------------------------------------------------
+// Rudimentary functionality
+//------------------------------------------------------------------------
+
+ /**
+ * This is called from the Dempsy framework itself so there is no need for the
+ * user to call it.
+ */
+ public void initialize() throws DempsyException
+ {
+ if (!isInitialized)
+ {
+ for (ClusterDefinition clusterDef : clusterDefinitions)
+ {
+ if (clusterDef == null)
+ throw new DempsyException("The application definition for \"" + applicationName + "\" has a null ClusterDefinition.");
+
+ clusterDef.setParentApplicationDefinition(this);
+ }
+
+ isInitialized = true;
+ validate();
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder ret = new StringBuilder("application(");
+ ret.append(String.valueOf(applicationName)).append("):[");
+ boolean first = true;
+ for (ClusterDefinition clusterDef : getClusterDefinitions())
+ {
+ if (!first)
+ ret.append(",");
+ ret.append(String.valueOf(clusterDef));
+ first = false;
+ }
+ ret.append("]");
+ return ret.toString();
+ }
+
+ public void validate() throws DempsyException
+ {
+ initialize();
+
+ if (applicationName == null)
+ throw new DempsyException("You must set the application name while configuring a Dempsy application.");
+
+ if (clusterDefinitions == null || clusterDefinitions.size() == 0)
+ throw new DempsyException("The application \"" + SafeString.valueOf(applicationName) + "\" doesn't have any clusters defined.");
+
+ Set<ClusterId> clusterNames = new HashSet<ClusterId>();
+
+ for (ClusterDefinition clusterDef : clusterDefinitions)
+ {
+ if (clusterDef == null)
+ throw new DempsyException("The application definition for \"" + applicationName + "\" has a null ClusterDefinition.");
+
+ if (clusterNames.contains(clusterDef.getClusterId()))
+ throw new DempsyException("The application definition for \"" + applicationName + "\" has two cluster definitions with the name \"" + clusterDef.getClusterId().getMpClusterName() + "\"");
+
+ clusterNames.add(clusterDef.getClusterId());
+
+ clusterDef.validate();
+ }
+ }
+
+}
224 lib-dempsyapi/src/main/java/com/nokia/dempsy/config/ClusterDefinition.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.config;
+
+import java.lang.reflect.Method;
+
+import com.nokia.dempsy.Adaptor;
+import com.nokia.dempsy.DempsyException;
+import com.nokia.dempsy.annotations.MessageHandler;
+import com.nokia.dempsy.annotations.MessageProcessor;
+import com.nokia.dempsy.annotations.Start;
+import com.nokia.dempsy.internal.util.SafeString;
+
+/**
+ * <p>A {@link ClusterDefinition} is part of an {@link ApplicationDefinition}. For a full
+ * description of the {@link ClusterDefinition} please see the {@link ApplicationDefinition}
+ * documentation.</p>
+ *
+ * <p>Note: for ease of use when configuring by hand (not using a dependency injection framework
+ * like Spring or Guice) all "setters" (all 'mutators' in general) return the {@link ClusterDefinition}
+ * itself for the purpose of chaining.</p>
+ */
+public class ClusterDefinition
+{
+ private ClusterId clusterId;
+ private String clusterName;
+
+ private Object messageProcessorPrototype;
+ private Adaptor adaptor;
+ private ClusterId[] destinations = {};
+ private Object strategy = null;
+ private Object serializer = null;
+ private Object statsCollectorFactory = null;
+ private OutputSchedule outputScheduler = null;
+ private boolean adaptorIsDaemon = false;
+
+ private ApplicationDefinition parent;
+
+ /**
+ * Create a ClusterDefinition from a cluster name. A {@link ClusterDefinition} is to be embedded in
+ * an {@link ApplicationDefinition} so it only needs to cluster name and not the entire {@link ClusterId}.
+ */
+ public ClusterDefinition(String clusterName) { this.clusterName = clusterName; }
+
+ /**
+ * <p>Create a ClusterDefinition from a cluster name. A {@link ClusterDefinition} is to be embedded in
+ * an {@link ApplicationDefinition} so it only needs to cluster name and not the entire {@link ClusterId}.</p>
+ *
+ * <p>This Cluster will represent an {@link Adaptor} cluster. Use this constructor from a dependency injection
+ * framework supporting constructor injection.</p>
+ *
+ * @see {@link setAdaptor}
+ */
+ public ClusterDefinition(String clusterName, Adaptor adaptor) { this.clusterName = clusterName; setAdaptor(adaptor); }
+
+ /**
+ * <p>Create a ClusterDefinition from a cluster name. A {@link ClusterDefinition} is to be embedded in
+ * an {@link ApplicationDefinition} so it only needs to cluster name and not the entire {@link ClusterId}.</p>
+ *
+ * <p>This Cluster will represent a {@link MessageProcessor} cluster. Use this constructor from a dependency injection
+ * framework supporting constructor injection.</p>
+ *
+ * @see {@link setMessageProcessorPrototype}
+ */
+ public ClusterDefinition(String clusterName, Object prototype) throws DempsyException
+ {
+ this.clusterName = clusterName;
+ setMessageProcessorPrototype(prototype);
+ }
+
+ /**
+ * Get the full clusterId of this cluster.
+ */
+ public ClusterId getClusterId() { return clusterId; }
+
+ /**
+ * If this {@link ClusterDefinition} identifies specific destination for outgoing
+ * messages, this will return the list of ids of those destination clusters.
+ */
+ public ClusterId[] getDestinations() { return destinations; }
+
+ /**
+ * Set the list of explicit destination that outgoing messages should be limited to.
+ */
+ public ClusterDefinition setDestinations(ClusterId... destinations)
+ {
+ this.destinations = destinations;
+ return this;
+ }
+
+ /**
+ * Returns true if there are any explicitly defined destinations.
+ * @see {@link setDestinations}
+ */
+ public boolean hasExplicitDestinations() { return this.destinations != null && this.destinations.length > 0; }
+
+ public ClusterDefinition setRoutingStrategy(Object strategy) { this.strategy = strategy; return this; }
+ public Object getRoutingStrategy() { return strategy == null ? parent.getRoutingStrategy() : strategy; }
+
+ protected ClusterDefinition setParentApplicationDefinition(ApplicationDefinition applicationDef) throws DempsyException
+ {
+ if (clusterName == null)
+ throw new DempsyException("You must set the 'clusterName' when configuring a dempsy cluster for the application: " + String.valueOf(applicationDef));
+ clusterId = new ClusterId(applicationDef.getApplicationName(),clusterName);
+ parent = applicationDef;
+ return this;
+ }
+
+ public ApplicationDefinition getParentApplicationDefinition() { return parent; }
+
+ public Object getSerializer() { return serializer == null ? parent.getSerializer() : serializer; }
+ public ClusterDefinition setSerializer(Object serializer) { this.serializer = serializer; return this; }
+
+ public Object getStatsCollectorFactory() {return statsCollectorFactory == null ? parent.getStatsCollectorFactory() : statsCollectorFactory;}
+ public ClusterDefinition setStatsCollectorFactory(Object statsCollectorFactory)
+ {
+ this.statsCollectorFactory = statsCollectorFactory;
+ return this;
+ }
+
+ public ClusterDefinition setOutputSchedule(OutputSchedule outputScheduler)
+ {
+ this.outputScheduler = outputScheduler;
+ return this;
+ }
+
+ public OutputSchedule getOutputSchedule() { return this.outputScheduler;}
+
+ public ClusterDefinition setMessageProcessorPrototype(Object messageProcessor) throws DempsyException
+ {
+ this.messageProcessorPrototype = messageProcessor;
+ return this;
+ }
+ public Object getMessageProcessorPrototype() { return messageProcessorPrototype; }
+
+ public boolean isRouteAdaptorType(){ return (this.getAdaptor() != null); }
+ public Adaptor getAdaptor() { return adaptor; }
+ public ClusterDefinition setAdaptor(Adaptor adaptor) { this.adaptor = adaptor; return this; }
+ public boolean isAdaptorDaemon() { return adaptorIsDaemon; }
+ public ClusterDefinition setAdaptorDaemon(boolean isAdaptorDaemon) { this.adaptorIsDaemon = isAdaptorDaemon; return this; }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder("(");
+ sb.append(clusterId == null ? "(unknown cluster id)" : String.valueOf(clusterId));
+ Object obj = messageProcessorPrototype == null ? adaptor : messageProcessorPrototype;
+ boolean hasBoth = adaptor != null && messageProcessorPrototype != null;
+ sb.append(":").append(obj == null ? "(ERROR: no processor or adaptor)" : obj.getClass().getSimpleName());
+ if (hasBoth) // if validate has been called then this can't be true
+ sb.append(",").append(adaptor.getClass().getSimpleName()).append("<-ERROR");
+ if (hasExplicitDestinations())
+ sb.append("|destinations:").append(String.valueOf(destinations));
+ sb.append(")");
+ return sb.toString();
+ }
+
+ public void validate() throws DempsyException
+ {
+ if (parent == null)
+ throw new DempsyException("The parent ApplicationDefinition isn't set for the Cluster " +
+ SafeString.valueOf(clusterName) + ". You need to initialize the parent ApplicationDefinition prior to validating");
+ if (clusterName == null)
+ throw new DempsyException("You must set the 'clusterName' when configuring a dempsy cluster for the application.");
+ if (messageProcessorPrototype == null && adaptor == null)
+ throw new DempsyException("A dempsy cluster must contain either an 'adaptor' or a message processor prototype. " +
+ clusterId + " doesn't appear to be configure with either.");
+ if (messageProcessorPrototype != null && adaptor != null)
+ throw new DempsyException("A dempsy cluster must contain either an 'adaptor' or a message processor prototype but not both. " +
+ clusterId + " appears to be configured with both.");
+
+ if (messageProcessorPrototype != null)
+ {
+ if(!messageProcessorPrototype.getClass().isAnnotationPresent(MessageProcessor.class))
+ throw new DempsyException("Attempting to set an instance of \"" +
+ SafeString.valueOfClass(messageProcessorPrototype) + "\" within the " +
+ ClusterDefinition.class.getSimpleName() + " for \"" + SafeString.valueOf(clusterId) +
+ "\" but it isn't identified as a MessageProcessor. Please annotate the class.");
+
+ Method[] methods = messageProcessorPrototype.getClass().getMethods();
+
+ boolean foundAtLeastOneMethod = false;
+ for(Method method: methods)
+ {
+ if(method.isAnnotationPresent(MessageHandler.class))
+ {
+ foundAtLeastOneMethod = true;
+ break;
+ }
+ }
+
+ if (!foundAtLeastOneMethod)
+ throw new DempsyException("No method on the message processor of type \"" +
+ SafeString.valueOfClass(messageProcessorPrototype) + "\" is identified as a MessageHandler. Please annotate the appropriate method using @MessageHandler.");
+
+ int startMethods = 0;
+ for(Method method: methods)
+ {
+ if (method.isAnnotationPresent(Start.class))
+ {
+ startMethods++;
+ }
+ }
+ if (startMethods > 1)
+ throw new DempsyException("Multiple methods on the message processor of type\""
+ + SafeString.valueOf(messageProcessorPrototype) + "\" is identified as a Start method. Please annotate at most one method using @Start.");
+ }
+ }
+
+}
109 lib-dempsyapi/src/main/java/com/nokia/dempsy/config/ClusterId.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.config;
+
+
+/**
+ * <p>This class represents the Id of a message processor cluster within a Dempsy
+ * application. Cluster Id's are essentially a two level name: application name,
+ * cluster name, and they correspond to the {@link ApplicationDefinition}'s
+ * applicationName and the {@link ClusterDefinition}'s clusterName.</p>
+ *
+ * <p>A cluster Id should be unique.</p>
+ *
+ * <p>ClusterIds are immutable.</p>
+ *
+ * <p>See the User Guide for an explanation of what a 'message processor cluster' is.</p>
+ */
+public class ClusterId
+{
+ private String applicationName;
+ private String mpClusterName;
+
+ /**
+ * Create a cluster Id from the constituent parts.
+ *
+ * @param applicationName is the application name that the cluster identified with
+ * this Id is part of.
+ *
+ * @param mpClusterName is the cluster name within the given application that the
+ * cluster identified with this Id is part of.
+ */
+ public ClusterId(String applicationName, String mpClusterName)
+ {
+ this.applicationName = applicationName;
+ this.mpClusterName = mpClusterName;
+ }
+
+ /**
+ * Convenience constructor for copying an existing ClusterId.
+ *
+ * @param other is the cluster id to make a copy of.
+ */
+ public ClusterId(ClusterId other)
+ {
+ this.applicationName = other.applicationName;
+ this.mpClusterName = other.mpClusterName;
+ }
+
+ public String getApplicationName() { return applicationName; }
+
+ public String getMpClusterName() { return mpClusterName; }
+
+ @Override
+ public String toString()
+ {
+ return this.applicationName+":"+this.mpClusterName;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((applicationName == null) ? 0 : applicationName.hashCode());
+ result = prime * result + ((mpClusterName == null) ? 0 : mpClusterName.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;
+ ClusterId other = (ClusterId)obj;
+ if(applicationName == null)
+ {
+ if(other.applicationName != null)
+ return false;
+ }
+ else if(!applicationName.equals(other.applicationName))
+ return false;
+ if(mpClusterName == null)
+ {
+ if(other.mpClusterName != null)
+ return false;
+ }
+ else if(!mpClusterName.equals(other.mpClusterName))
+ return false;
+ return true;
+ }
+}
63 lib-dempsyapi/src/main/java/com/nokia/dempsy/config/OutputSchedule.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.config;
+
+import java.util.concurrent.TimeUnit;
+
+import com.nokia.dempsy.annotations.MessageProcessor;
+import com.nokia.dempsy.annotations.Output;
+
+/**
+ * This class can be configured within a {@link ClusterDefinition} in order to setup
+ * a periodic call of any {@link MessageProcessor}'s methods that are annotated with
+ * the {@link Output} annotation.
+ */
+public final class OutputSchedule
+{
+ private long interval;
+ private TimeUnit timeUnit;
+
+ /**
+ * Constuct an OutputSchedule from an inteval and timeUnit.
+ */
+ public OutputSchedule(long interval, TimeUnit timeUnit)
+ {
+ this.interval = interval;
+ this.timeUnit = timeUnit;
+ }
+
+ /**
+ * Convenience mechanism for Dependency injection containers that work from
+ * configuration files (e.g. Spring). The timeUnits parameter must be a valid
+ * String value that can be passed to {@link TimeUnit}.valueOf().
+ */
+ public OutputSchedule(long interval, String timeUnit)
+ {
+ this(interval,TimeUnit.valueOf(timeUnit));
+ }
+
+ public Long getInterval()
+ {
+ return interval;
+ }
+
+ public TimeUnit getTimeUnit()
+ {
+ return timeUnit;
+ }
+
+}
63 lib-dempsyapi/src/main/java/com/nokia/dempsy/internal/util/SafeString.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.internal.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class SafeString
+{
+ private static Logger logger = LoggerFactory.getLogger(SafeString.class);
+
+ public static String valueOf(Object o)
+ {
+ try
+ {
+ return String.valueOf(o);
+ }
+ catch (Throwable th)
+ {
+ logger.warn("Failed to determine valueOf for given object",th);
+ }
+
+ return "[error]";
+ }
+
+ public static String valueOfClass(Object o)
+ {
+ try
+ {
+ Class<?> clazz = o == null ? null : o.getClass();
+ return clazz == null ? "[null object has no class]" : clazz.getName();
+ }
+ catch (Throwable th)
+ {
+ logger.warn("Failed to determine valueOf for given object",th);
+ }
+
+ return "[error]";
+ }
+
+ public static String objectDescription(Object message)
+ {
+ return "\"" + SafeString.valueOf(message) +
+ (message != null ? "\" of type \"" + SafeString.valueOfClass(message) : "") +
+ "\"";
+ }
+
+}
257 lib-dempsyapi/src/test/java/com/nokia/dempsy/config/TestConfig.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.nokia.dempsy.Adaptor;
+import com.nokia.dempsy.DempsyException;
+import com.nokia.dempsy.Dispatcher;
+import com.nokia.dempsy.annotations.MessageHandler;
+import com.nokia.dempsy.annotations.MessageKey;
+import com.nokia.dempsy.annotations.MessageProcessor;
+import com.nokia.dempsy.annotations.Start;
+
+public class TestConfig
+{
+
+ public static class GoodMessage
+ {
+ @MessageKey
+ public String key() { return "Hello"; }
+ }
+
+ @MessageProcessor
+ public static class GoodTestMp
+ {
+ @MessageHandler
+ public void handle(GoodMessage string) {}
+
+ @Start
+ public void startMethod() {}
+ }
+
+ @MessageProcessor
+ public static class MultiStartTestMp
+ {
+ @MessageHandler
+ public void handle(GoodMessage string) {}
+
+ @Start
+ public void startMethod() {}
+
+ @Start
+ public void extraStartMethod() {}
+
+ }
+
+ public static class GoodAdaptor implements Adaptor
+ {
+ @Override
+ public void setDispatcher(Dispatcher dispatcher){ }
+
+ @Override
+ public void start() {}
+
+ @Override
+ public void stop() {}
+
+ }
+
+ @Test
+ public void testSimpleConfig() throws Throwable
+ {
+ ApplicationDefinition app = new ApplicationDefinition("test");
+ ClusterDefinition cd = new ClusterDefinition("test-slot");
+ cd.setMessageProcessorPrototype(new GoodTestMp());
+ app.add(cd);
+ app.initialize();
+
+ System.out.println(app);
+
+ // if we get to here without an error we should be okay
+ app.validate(); // this throws if there's a problem.
+
+ assertNull(cd.getSerializer());
+ assertNull(app.getSerializer());
+
+ assertNull(cd.getRoutingStrategy());
+ assertNull(app.getRoutingStrategy());
+
+ assertNull(cd.getStatsCollectorFactory());
+ assertNull(app.getStatsCollectorFactory());
+ }
+
+ @Test
+ public void testConfig() throws Throwable
+ {
+ List<ClusterDefinition> clusterDefs = new ArrayList<ClusterDefinition>();
+
+ Object appSer;
+ Object appRs;
+ Object appScf;
+ ApplicationDefinition app = new ApplicationDefinition("test").
+ setSerializer(appSer = new Object()).
+ setRoutingStrategy(appRs = new Object())
+ .setStatsCollectorFactory(appScf = new Object());
+
+ ClusterDefinition cd = new ClusterDefinition("test-slot1").setAdaptor(new GoodAdaptor());
+ clusterDefs.add(cd);
+
+ cd = new ClusterDefinition("test-slot2",new GoodTestMp()).
+ setDestinations(new ClusterId(new ClusterId("test", "test-slot3")));
+ clusterDefs.add(cd);
+
+ cd = new ClusterDefinition("test-slot3");
+ cd.setMessageProcessorPrototype(new GoodTestMp());
+ cd.setDestinations(new ClusterId[] { new ClusterId("test", "test-slot4"), new ClusterId("test", "test-slot5")});
+ clusterDefs.add(cd);
+
+ Object clusSer;
+ cd = new ClusterDefinition("test-slot4").setMessageProcessorPrototype(new GoodTestMp()).setSerializer(clusSer = new Object());
+ clusterDefs.add(cd);
+
+ Object clusRs;
+ cd = new ClusterDefinition("test-slot5").setMessageProcessorPrototype(new GoodTestMp()).setRoutingStrategy(clusRs = new Object());
+ clusterDefs.add(cd);
+
+ Object clusScf;
+ cd = new ClusterDefinition("test-slot6").setMessageProcessorPrototype(new GoodTestMp()).setStatsCollectorFactory(clusScf = new Object());
+ clusterDefs.add(cd);
+
+ cd = new ClusterDefinition("test-slot1.5", new GoodAdaptor());
+ assertNotNull(cd.getAdaptor());
+ clusterDefs.add(cd);
+
+ app.setClusterDefinitions(clusterDefs);
+
+ app.initialize();
+ // if we get to here without an error we should be okay
+ app.validate(); // this throws if there's a problem.
+
+ System.out.println(app);
+
+ assertTrue(app.getClusterDefinitions().get(0).isRouteAdaptorType());
+ assertEquals(new ClusterId("test", "test-slot2"), app.getClusterDefinitions().get(1).getClusterId());
+ assertEquals("test",app.getClusterDefinitions().get(1).getClusterId().getApplicationName());
+ assertEquals("test-slot2",app.getClusterDefinitions().get(1).getClusterId().getMpClusterName());
+ assertEquals(new ClusterId("test", "test-slot2").hashCode(), app.getClusterDefinitions().get(1).getClusterId().hashCode());
+ assertFalse(new ClusterId("test", "test-slot3").equals(new Object()));
+ assertFalse(new ClusterId("test", "test-slot3").equals(null));
+
+ assertEquals(appSer,app.getClusterDefinitions().get(0).getSerializer());
+ assertEquals(app.getSerializer(),app.getClusterDefinitions().get(1).getSerializer());
+ assertEquals(clusSer,app.getClusterDefinitions().get(3).getSerializer());
+
+ assertEquals(appRs,app.getClusterDefinitions().get(0).getRoutingStrategy());
+ assertEquals(app.getRoutingStrategy(),app.getClusterDefinitions().get(1).getRoutingStrategy());
+ assertEquals(appRs,app.getClusterDefinitions().get(3).getRoutingStrategy());
+ assertEquals(clusRs,app.getClusterDefinitions().get(4).getRoutingStrategy());
+
+ assertEquals(appScf, app.getClusterDefinitions().get(0).getStatsCollectorFactory());
+ assertEquals(app.getStatsCollectorFactory(), app.getClusterDefinitions().get(1).getStatsCollectorFactory());
+ assertEquals(clusScf, app.getClusterDefinitions().get(5).getStatsCollectorFactory());
+
+ assertTrue(app == app.getClusterDefinitions().get(4).getParentApplicationDefinition());
+
+ assertEquals(new ClusterId("test", "test-slot1"),app.getClusterDefinitions().get(0).getClusterId());
+ }
+
+ @Test(expected=DempsyException.class)
+ public void testFailNoPrototypeOrAdaptor() throws Throwable
+ {
+ ApplicationDefinition app = new ApplicationDefinition("test");
+ ClusterDefinition cd = new ClusterDefinition("test-slot1");
+ app.add(cd); // no prototype or adaptor
+ System.out.println(app);
+ app.initialize();
+ }
+
+ @Test(expected=DempsyException.class)
+ public void testFailBadPrototype() throws Throwable
+ {
+ ApplicationDefinition app = new ApplicationDefinition("test");
+ ClusterDefinition cd = new ClusterDefinition("test-slot1");
+ cd.setMessageProcessorPrototype(new Object()); // has no annotated methods
+ app.add(cd);
+ app.initialize();
+ }
+
+ @Test(expected=DempsyException.class)
+ public void testFailBothPrototypeAndAdaptor() throws Throwable
+ {
+ ApplicationDefinition app = new ApplicationDefinition("test");
+ ClusterDefinition cd = new ClusterDefinition("test-slot1");
+ cd.setMessageProcessorPrototype(new GoodTestMp());
+ cd.setAdaptor(new GoodAdaptor());
+ app.add(cd);
+ System.out.println(app);
+ app.initialize();
+ }
+
+ @Test(expected=DempsyException.class)
+ public void testFailNullClusterDefinition() throws Throwable
+ {
+ ApplicationDefinition app =
+ new ApplicationDefinition("test").add(
+ new ClusterDefinition("test-slot1").setMessageProcessorPrototype(new GoodTestMp()),
+ null,
+ new ClusterDefinition("test-slot2").setMessageProcessorPrototype(new GoodTestMp()));
+ app.initialize();
+ }
+
+ @Test(expected=DempsyException.class)
+ public void testFailNoParent() throws Throwable
+ {
+ new ClusterDefinition("test-slot1").setMessageProcessorPrototype(new GoodTestMp()).validate();
+ }
+
+ @Test(expected=DempsyException.class)
+ public void testDupCluster() throws Throwable
+ {
+ ApplicationDefinition app =
+ new ApplicationDefinition("test-tooMuchWine-needMore").add(
+ new ClusterDefinition("notTheSame").setAdaptor(new GoodAdaptor()),
+ new ClusterDefinition("mp-stage1").setMessageProcessorPrototype(new GoodTestMp()),
+ new ClusterDefinition("mp-stage2-dupped").setMessageProcessorPrototype(new GoodTestMp()),
+ new ClusterDefinition("mp-stage2-dupped").setMessageProcessorPrototype(new GoodTestMp()),
+ new ClusterDefinition("mp-stage3").setMessageProcessorPrototype(new GoodTestMp()));
+ app.validate();
+ }
+
+
+ @Test(expected=DempsyException.class)
+ public void testMultipleStartMethodsDisallowed() throws Throwable
+ {
+ ApplicationDefinition app =
+ new ApplicationDefinition("test-multiple-starts").add(
+ new ClusterDefinition("adaptor").setAdaptor(new GoodAdaptor()),
+ new ClusterDefinition("good-mp").setMessageProcessorPrototype(new GoodTestMp()),
+ new ClusterDefinition("bad-mp").setMessageProcessorPrototype(new MultiStartTestMp()));
+ app.validate();
+ }
+
+}
21 lib-dempsycore/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.nokia.dempsy</groupId>
+ <artifactId>dempsy-parent</artifactId>
+ <version>01.01-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>lib-dempsycore</artifactId>
+ <name>Distributed Message Processing Framework - Core Internal Api</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.nokia.dempsy</groupId>
+ <artifactId>lib-dempsyapi</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
25 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Destination.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport;
+
+
+/**
+ * This class represents and opaque handle to message transport implementation
+ * specific means of connecting to a destination.
+ */
+public interface Destination { }
+
49 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Listener.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport;
+
+
+/**
+ * <p>This is the core abstraction for receiving messages. The client side of
+ * a transport implementation (called an "Adaptor") needs to be wired to a
+ * MessageTransportListener</p>
+ */
+public interface Listener
+{
+ /**
+ * <p>Method that accepts the callback for received messages. Given that the
+ * transport is responsible for managing threads, the transport will also let
+ * the Listener implementation know if it should make every effort to
+ * handle the request or if it should "fail-fast."</p>
+ *
+ * <p>fail-fast means that the Listener should not attempt to handle a request
+ * if any blocking is required. In cases where the Listener determines there is
+ * going to be a delay in processing the request it should simple return 'false'
+ * as an indication that the message was not handled and allow the transport
+ * implementation to deal with it.</p>
+ *
+ * @param messageBytes The message bytes received
+ * @throws MessageTransportException
+ */
+ public boolean onMessage(byte[] messageBytes, boolean failFast) throws MessageTransportException;
+
+ /**
+ * The transport implementation is responsible for letting the MessageTransportListener
+ * know that the transport is being shut down.
+ */
+ public void shuttingDown();
+}
40 ...dempsycore/src/main/java/com/nokia/dempsy/messagetransport/MessageTransportException.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport;
+
+/**
+ * General checked Exception for MessageTransport functions
+ */
+public class MessageTransportException extends Exception
+{
+ private static final long serialVersionUID = 1L;
+
+ public MessageTransportException(String message)
+ {
+ super(message);
+ }
+
+ public MessageTransportException(Throwable e)
+ {
+ super(e);
+ }
+
+ public MessageTransportException(String message, Throwable e)
+ {
+ super(message, e);
+ }
+}
34 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/OverflowHandler.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport;
+
+
+/**
+ * Some transports allow a callback when trying to send a message overflows.
+ * Implementing this interface and setting the overflowhandler on the implementation
+ * is the way to receive these callbacks.
+ */
+public interface OverflowHandler
+{
+ /**
+ * Implement this method to receive the callback. It will be called from the
+ * appropriate transport implementation when a send attempt overflows.
+ *
+ * @param messageBytes - the message that was attempted to be sent.
+ */
+ public void overflow(byte[] messageBytes);
+}
27 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Receiver.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport;
+
+public interface Receiver
+{
+
+ public Destination getDestination() throws MessageTransportException;
+
+ public void setListener(Listener listener) throws MessageTransportException;
+
+ public void stop();
+}
34 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Sender.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport;
+
+/**
+ * A simple interface to send messages to a messaging server destination.
+ */
+public interface Sender
+{
+ /**
+ * Sends the message. The implementor needs to take special handle exceptions from the
+ * underlying system correctly. The user of the <em>Sender</em> should not be
+ * required to release the sender and reaquire it. The Sender should do that work.
+ *
+ * @param messageBytes The serialized message to send
+ * @throws MessageTransportException indicates that the message wasn't sent.
+ */
+ public void send(byte[] messageBytes) throws MessageTransportException;
+
+}
36 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/SenderFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport;
+
+/**
+ * Abstraction to create multiple sender based on destination.
+ */
+public interface SenderFactory
+{
+
+ public Sender getSender(Destination destination) throws MessageTransportException;
+
+ /**
+ * stop() must be implemented such that it doesn't throw an exception no matter what
+ * but forces the stopping of any underlying resources that require stopping. Stop
+ * is expected to stop Senders that it created.
+ *
+ * NOTE: stop() must be idempotent.
+ */
+ public void stop();
+
+}
52 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/Transport.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport;
+
+/**
+ * <p>A transport represents a handle to both the send side and the receive side. It
+ * can be instantiated in both places and should be implemented to only create the
+ * side that's asked for.</p>
+ *
+ * <p>Instances of the Transport are supposed to be stateless. Therefore each call
+ * on createOutbound or createInbound will freshly instantiate a new instance of
+ * the SenderFactory or Receiver</p>
+ */
+public interface Transport
+{
+ /**
+ * Create a new instance of the Sender factory for this transport. This
+ * SenderFactory should be able to create Senders that can connect to
+ * Receivers instantiated from the getInbound call by using the Destinations
+ * the Reciever generates.
+ */
+ public SenderFactory createOutbound() throws MessageTransportException;
+
+ /**
+ * Create a new instance of the Receiver for this transport.This
+ * Receiver should be able to create Destinations from which the SenderFactory
+ * instantiated from the getOutbound can then instantiate Senders.
+ */
+ public Receiver createInbound() throws MessageTransportException;
+
+ /**
+ * If the implementation supports overflow handling then calling this
+ * method will ensure that the provided instance is added to each newly
+ * created SenderFactory and/or Receiver. If it's not supported it will
+ * throw an exception.
+ */
+ public void setOverflowHandler(OverflowHandler overflowHandler) throws MessageTransportException;
+}
102 lib-dempsycore/src/main/java/com/nokia/dempsy/messagetransport/util/QueuingReceiver.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * 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.
+ */
+
+package com.nokia.dempsy.messagetransport.util;
+
+import java.util.concurrent.BlockingQueue;
+
+import javax.annotation.PreDestroy;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nokia.dempsy.messagetransport.Listener;
+import com.nokia.dempsy.messagetransport.MessageTransportException;
+
+/**
+ * <p>This is a concrete class that can be used by a MessageTransport client that
+ * would prefer to pull messages rather than have them pushed them. It
+ * implements the MessageTransportListener and can be wired into an implementation
+ * Adaptor and also wired into the client that wants to pull messages.</p>
+ *
+ * <p>It needs to be initialized with the BlockingQueue that will be used to
+ * pull from.</p>
+ *
+ * <p>It can optionally be wired to an MessageOverflowHandler that will be
+ * called when the blocking queue is at capacity. When the BlockingQueue
+ * is at capacity and there is no MessageOverflowHandler the MessageTransportQueuingReceiver
+ * will simply block until room becomes available.</p>
+ *
+ */
+public class QueuingReceiver implements Listener
+{
+ private static Logger logger = LoggerFactory.getLogger(QueuingReceiver.class);
+ private BlockingQueue<byte[]> queue;
+
+ /**
+ * The queue that the MessageTransportQueuingReceiver puts messages on and a client
+ * can pull messages from.
+ *
+ * @param queue is the BlockingQueue to be used.
+ */
+ public void setQueue(BlockingQueue<byte[]> queue)
+ {
+ this.queue = queue;
+ }
+
+ /**
+ * The client is expected to get the BlockingQueue from the MessageTransportQueuingReceiver
+ * and use it directly.
+ *
+ * @return the BlockingQueue that messages are being pushed to, and for the client
+ * to pull from.
+ */
+ public BlockingQueue<byte[]> getQueue()
+ {
+ return this.queue;
+ }
+
+ /**
+ * This implements the MessageTransportListener requirement. It will push the
+ * message onto the BlockingQueue. If the queue is full and there is a
+ * MessageOverflowHandler supplied then the MessageOverflowHandler will be
+ * invoked to handle the message. Otherwise it will block until there is
+ * room in the queue.
+ */
+ @Override
+ public boolean onMessage(byte[] messageBytes, boolean failFast) throws MessageTransportException
+ {
+ if (failFast)
+ return queue.offer(messageBytes);
+ else
+ {
+ try { queue.put(messageBytes); return true; }
+ catch(InterruptedException ie)
+ {
+ logger.warn("Pushing the message to the queue was interrupted.");
+ return false;
+ }
+ }
+ }
+
+ /**