Hello. I have created a library to inject dependencies remotely, I call it Service Architecture Model (SAM).
Logically it works as a injector that is split over several JVM machines. The modules used to create the remote injector are standard guice modules. To build the remote injector some additional information is needed, I call this a "Service Architecture" because it defined what type of services are available and which injection keys they provide. A important feature on SAM is the execution model. When a call is realized to a remote interface, the execution is delayed if the method returns void or a nested interface. This means, that a loop that calls a remote object many times can be translated to only one remote call. Also, it is possible to pass references between injected services without any direct connection between the services. This execution model can change program semantic!!!. I know when this happens, so a good architecture definition can ensure that semantic is preserved. The implementation is provided here: https://github.com/paweld2/Service-Architecture-Model I have created a test setup in this project: https://github.com/paweld2/samExample In the test project You have the definition of 3 modules: StoreServiceModule CourierServiceModule ShoppingServiceModule To create a standard injector on one JVM You may need to use this setup for guice: ShoppingServiceModule --install--> CourierServiceModule --install--> StoreServiceModule With SAM You can create each module in a remote JVM and create a remote injector. To do this : 1. build the project: mvn compile 2. start Courier service: ./runCourierServer.sh 3. start Store service: ./runStoreServer.sh 4. start Shopping service: ./runShoppingServer.sh You will note how the services will connect to each other. If someone is interested to talk about SAM, I will attend the JavaOne conference. It will be a pleasure to show it on live. Regards. Pawel Cesar Sanjuan Szklarz. http://paweld2.eu/ <http://paweld2.eu/#/> <https://github.com/paweld2/samExample> PD. Here is detailed explication about how the test project is setup. Service modules are: ShoppingServiceModule -> https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/impl/shopping/TestShoppingModule.java StoreServiceModule -> https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/impl/store/TestStoreServiceModule.java CourierServiceModule -> https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/impl/courier/TestCourierServiceModule.java As You can see, this are standard guice modules. Because SAM creates instances of each module in different machines, a "Service Architecture" definition is necessary. You can see this architecture as a definition of the information: -- I have 3 type of service https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/architecture/SeeTestArchitecture.java -- Each Service provide a predefined set of keys: Shopping service -> https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/architecture/service/ShoppingService.java Store service -> https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/architecture/service/StoreService.java Courier service -> https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/architecture/service/CourierService.java - I have 3 implementations of the service: https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/impl/TestArchitectureImplementation.java Note how we point to the original guice modules: registerImplementation(new AbstractSamServiceImplementationDefinition<StoreService>(StoreService.class, TestStoreServiceModule.class) {}); this says: "register a implementation of the service 'StoreService' that is implemented in module 'TestStoreServiceModule'" Also, because our ShoppingServiceModule injects keys from the submodules, we have to declare this in the implementation registration: registerImplementation(new AbstractSamServiceImplementationDefinition<ShoppingService>(ShoppingService.class, TestShoppingModule.class) { @Override protected void implementationDefinition() { withBindingsTo(StoreService.class); withBindingsTo(CourierService.class); } }); this says: "register a implementation of the service 'ShoppingService' that is implemented in module 'TestShoppingModule' and that use injection keys from service 'StoreService' and 'CourierService'" Note that here the implementation refers to a Service definition, and not to a concrete implementation. This means that we can change the implementation at any time. Now lets initialize the modules each in a different JVM and connect then remotely. This is done as defined in method startService in this abstract class: https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/main/AbstractServiceRunner.java the steps in startService method are as follows: -- Create the execution environment and load architecture and implementations definitions. -- Choose which implementations should run in the server -- Create a service instance of each implementation -- Create a configuration that show how to connect the services -- Expose the configuration as public services by a URL -- make the tests with the remote injected service The Store and Courier service don't have deeper dependencies, so the setup is simple - just expose the service to a URL: https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/main/CourierServer.java https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/main/StoreServer.java Now, the Shopping service needs to connect to a Store and Courier service. Look at the definition: https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/main/ShoppingServer.java In the configuration definition we define the dependencies between the modules: @Override protected List<InjectionConfigurationElement> createConfigurations(List<SamServiceInstance> samServiceInstances) { ImmutableList.Builder<InjectionConfigurationElement> builder = ImmutableList.builder(); InjectionConfigurationElement courier = InjectionConfigurationBuilder.externalServiceBind(new SamServiceKey(CourierService.class), courierURL); InjectionConfigurationElement store = InjectionConfigurationBuilder.externalServiceBind(new SamServiceKey(StoreService.class), storeURL); InjectionConfigurationElement[] externalBindings = {store, courier}; builder.add( InjectionConfigurationBuilder.complexInstanceBind( architectureManager, samServiceInstances.get(0),externalBindings)); return builder.build(); } This says: "Shopping service must connect to a StoreService available on address 'storeURL' and to a CourierService available on address 'courierURL'. Now finally lets create the remote injector and execute some code. This is done in the performTest method of ShoppingServer. We take the Shopping service instance "localServices.get(0)", create a transaction that will create the remote injector and pass a ServiceAction that define how to interact with the remote injector. The interaction just execute a method of the interface "ShoppingStoreWithCourierInteraction" : @Override protected void performTests(List<LiftedServiceConfiguration> localServices) { Key<ShoppingStoreWithCourierInteraction> serviceKey = Key.get(ShoppingStoreWithCourierInteraction.class); Future<Integer> shoppingPrice = transactionApi.executeServiceAction(localServices.get(0), new ServiceAction<Integer, ShoppingStoreWithCourierInteraction>(serviceKey) { @Override public Integer executeInteraction(ShoppingStoreWithCourierInteraction service) { return service.makeShoping(); } }); try { Integer price = Await.result(shoppingPrice, Duration.create(6, TimeUnit.SECONDS)); logger.info("Shopping price is {}", price); } catch (Exception e) { e.printStackTrace(); } System.exit(0); } Look at the implementation of "ShoppingStoreWithCourierInteraction" provided here: https://github.com/paweld2/samExample/blob/master/src/main/java/eu/paweld2/sam/example/impl/shopping/TestShoppingStoreWithCourierInteraction.java References to types provided by the remote service are injected. Also, note that on the line boolean addressSetupOk = order.receiveExternalCourierService(address); we pass a reference from a object coming from the Courier Service to the Store Service. The big difference here, is that there is no connection between Courier and Store service - They don't know about each others!. The final result of the interaction is the price for the realized order. Note that in this service interaction, the Customer using ShoppingService can select its own courier service and ask the store to provide pickup address. This means, that You don't have to provide Your address to the store, only to You favorite Courier service. -- You received this message because you are subscribed to the Google Groups "google-guice" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/google-guice. For more options, visit https://groups.google.com/groups/opt_out.
