blob: 86751b57f7fb70df08b75e9c35f4ddbc21b734e4 [file] [log] [blame]
//////////////////////
* 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.