| ////////////////////// |
| * Copyright (c) 2007-2012, Niclas Hedhman. All Rights Reserved. |
| * |
| * 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. |
| ////////////////////// |
| |
| [[howto-configure-service,Configure a Service]] |
| = Configure a Service = |
| Zest™ supports a Configuration system for services. The configuration instance itself is an Entity and is therefor |
| readable, writeable and queryable, just like other Entities. This should make Configuration management much simpler, |
| since you can easily build GUI tools to allow editing of these in runtime. However, to simplify the initial values of |
| the Configuration instance, Zest™ also does the initial bootstrapping of the Configuration entity for you. This HowTo is |
| going to show how. |
| |
| If you want to reproduce what's explained in this tutorial, remember to depend on the Core Bootstrap artifact: |
| |
| include::../../../../core/bootstrap/build/docs/buildinfo/artifact.txt[] |
| |
| At runtime you will need the Core Runtime artifact too. See the <<howto-depend-on-zest>> tutorial for details. |
| |
| == We need a Service == |
| |
| To illustrate these features we create an TravelPlan service, which allows clients to find and make Reservations to |
| Destinations. For the sake of simplicity, we are leaving out the domain details... |
| |
| [snippet,java] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/TravelPlan.java |
| tag=service |
| ----------- |
| |
| So, then there is the ServiceComposite... |
| |
| [snippet,java] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/TravelPlanService.java |
| tag=serviceComposite |
| ----------- |
| |
| And then in the Mixin we actually need to connect to a foreign system to obtain the various details that the service |
| can provide to the clients. For instance, it needs a host name and port and a protocol to use. We put these into a |
| configuration interface. |
| |
| [snippet,java] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/TravelPlanConfiguration.java |
| tag=configuration |
| ----------- |
| |
| We used the recommended type-safe Property subtype pattern, and for each PortNumber and Protocol we have defined a |
| Constraint required. |
| |
| Now we can access this configuration in the TravelPlanMixin like this; |
| |
| [snippet,java] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/TravelPlanMixin.java |
| tag=mixin |
| ----------- |
| |
| |
| And from the Service point of view, it doesn't need to worry about where the configuration really comes from. But it may |
| want to control when the Configuration should be refreshed, to ensure that atomic changes are happening. This is done |
| with the refresh() method in the Configuration interface; |
| |
| [snippet,java] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/TravelPlanMixin.java |
| tag=refresh |
| ----------- |
| |
| This ensures that any updates to the Configuration that has occurred will be retrieved and available to the Service. |
| Since Configuration instance is an Entity, the UnitOfWork system will ensure that the Configuration is consistent and |
| not in the middle of value changes. |
| |
| === Initial Values === |
| |
| The initial Configuration instance will be created automatically behind the scenes, by reading a properties file and |
| create an Entity with the same identity as the identity of the service. That was a handful. Services are, as we know, |
| singletons and have an identity specified at assembly. Even if it is not provided, one will automatically be assigned. |
| The service's "identifiedBy" will be used as the identifier for the Configuration entity and stored in the visible |
| EntityStore. This identity is also used to locate a properties file in the same package as the ServiceComposite belongs |
| to. |
| |
| So, we create a properties file, where the keys are the names of the properties in TravelPlanConfiguration. |
| |
| [snippet,bash] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/TravelPlanService.properties |
| tag=params |
| ----------- |
| File: org/hedhman/niclas/travel/TravelPlanService.properties |
| |
| Note that the file resides in the directory equivalent to the package name of the TravelPlanService. |
| |
| And this would work with the standard assembly. |
| |
| [snippet,java] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/Main.java |
| tag=simple |
| ----------- |
| |
| == Non-default Identity == |
| If you need to use multiple instances of the same service, or that the service has a non-default Identity, then you need |
| to name the properties file according to the Identity of the service declaration, but the file will still need to be in |
| the same package as the ServiceComposite sub type, the TravelPlanService in the above example. For instance; |
| |
| [snippet,java] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/Main.java |
| tag=assemble |
| ----------- |
| |
| And the two files for configuration, |
| |
| [snippet,bash] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/ExpediaService.properties |
| tag=params |
| ----------- |
| File: org/qi4j/manual/travel/ExpediaService.properties |
| |
| |
| [snippet,bash] |
| ----------- |
| source=manual/src/main/java/org/qi4j/manual/travel/OrbitzService.properties |
| tag=params |
| ----------- |
| File: org/qi4j/manual/travel/OrbitzService.properties |
| |
| == Changing Configuration in runtime == |
| Unlike most frameworks, the Configuration in Zest™ is an active Entity, and once the properties file has been read once |
| at the first(!) startup, it no longer serves any purpose. The Configuration will always be retrieved from the |
| EntityStore. Changes to the properties file are not taken into consideration if the Configuration entity is found in the |
| entity store. |
| |
| But that also means that applications should not cache the configuration values, and instead read them from the |
| Configuration instance every time needed, and do a refresh() method call when it is safe to update the Configuration |
| Entity with new values. |