blob: 41ffe9430a86729b8844f205c27db509e54b5bcd [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-create-entity,Create an Entity]]
= Create an Entity =
One of the most common tasks in Zest™ is the management of the life cycle of Entities. Since Zest™ is capable of
delivering much higher performance than traditional Object-Relational Mapping technologies, we also expect that people
use Entities more frequently in Zest™ applications, so it is a very important topic to cover.
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[]
Moreover, you'll need an EntityStore for persistence and an Indexing engine for querying. Choose among the available
implementations listed in the <<extensions>> section.
At runtime you will need the Core Runtime artifact too. See the <<howto-depend-on-zest>> tutorial for details.
== Basics First ==
All Entity operations MUST be done within a UnitOfWork. UnitOfWorks can be nested and if underlying UnitOfWorks are not
completed (method complete()), then none of the operations will be persisted permanently.
Entity composites are subtypes of the EntityComposite interface.
Domain code typically don't need to know of the EntityComposite types directly, and is instead using the domain specific
interface. The Visibility rules will be applied to associate the right EntityComposite when a domain type is requested.
Ambiguities are not accepted and will result in runtime exceptions.
Zest™ supports that each entity instance can have more than one entity type, and it is managed per instance. This feature
is beyond the scope of this HowTO and will be covered subsequently.
== Good Practice ==
We have made the observation that it is good practice to separate the internal state from the observable behavior. By
this we mean that it is not a good practice to allow client code to manipulate or even view the internal states of
objects, which is such a common (bad) practice in the so called POJO world.
Instead, we recommend that the programmer defines the client requirement of what each participant within the client
context needs to conform to, and then create composites accordingly and hide all the state internal to the composite in
private mixins. By doing so, the same entity can participate in multiple contexts with different behavioral requirements
but using the same internal state.
We recommend limited use of primitive types for Properties and instead subtype the Property.
And try to use ValueComposites instead of Entities.
== The Entity ==
We need an entity to illustrate how we recommend to separate internal state from public behavior and observable state.
We will for the sake of simplicity use a trivial example. Please refer to other (possibly future) HowTos on patterns on
Entity management.
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/Car.java
tag=entity
-----------
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/Manufacturer.java
tag=entity
-----------
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/Accident.java
tag=entity
-----------
Above we define a Car domain object, which is of a particular Manufacturer (also an Entity), a model and a record of
Accidents.
// We are using explicit types for properties, so that instead of saying Property<String> model(), we make it explicit that
// the Property is a ModelProperty, which is useful when passing the Model property instance around for processing and
// similar. It very effectively communicates intent in a typesafe manner.
We will also need to define the composites for the above domain structure;
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/CarEntity.java
tag=composite
-----------
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/ManufacturerEntity.java
tag=composite
-----------
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/AccidentValue.java
tag=composite
-----------
For this case, we define both the Car and the Manufacturer as Entities, whereas the Accident is a Value, since it is an
immutable event that can not be modified.
== Assembly ==
All of the above must also be declared in the assembly. We MUST associate the EntityComposites with a relevant Module.
We must also assemble an EntityStore for the entire application, but that is outside the scope of this HowTo.
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/MyAssembler.java
tag=assembler1
-----------
We have no other Composites involved yet, so we can proceed to look at the usage code.
We recommend that the life cycle management of entities is placed inside domain factories, one for each type and made
available as services.
== The Entity Factory ==
The entity factory is something you need to write yourself, but as with most things in Zest™ it will end up being a
fairly small implementation. So how is that done?
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/CarEntityFactory.java
tag=carFactory
-----------
That is just the domain interface. We now need to make the service interface, which Zest™ needs to identify services and
make it possible for the service injection later.
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/CarEntityFactoryService.java
tag=carFactoryService
-----------
Then we need an implementation of the mixin.
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/CarEntityFactoryMixin.java
tag=carFactoryMixin1
-----------
And doing that, first of all we need to request Zest™ runtime to give us the Module
that our code belongs to, and the UnitOfWork current context the execution is happening in.
Injections that are related to the Visibility rules are handled by the @Structure annotation. And the easiest way for us
to obtain a Module is simply to;
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/CarEntityFactoryMixin.java
tag=carFactoryMixin2
-----------
Here Zest™ will inject the member module with the correct Module. In case we only need the Module
during the construction, we can also request it in the same manner as constructor argument.
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/CarEntityFactoryMixin.java
tag=carFactoryMixin3
-----------
This is important to know, since the injected member will not be available until AFTER the constructor has been
completed.
We then need to provide the implementation for the create() method.
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/CarEntityFactoryMixin.java
tag=create
-----------
So far so good. But how about the Manufacturer input into the create() method?
DDD promotes the use of Repositories. They are the type-safe domain interfaces into locating entities without getting
bogged down with querying infrastructure details. And one Repository per Entity type, so we keep it nice, tidy and
re-usable. So let's create one for the Manufacturer type.
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/ManufacturerRepository.java
tag=repo
-----------
And then we repeat the process for creating a Service...
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/ManufacturerRepositoryService.java
tag=manufacturerRepositoryService
-----------
and a Mixin that implements it...
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/ManufacturerRepositoryMixin.java
tag=repo
-----------
But now we have introduced 2 services that also are required to be declared in the assembly. In this case, we want the
Services to be available to the application layer above, and not restricted to within this domain model.
[snippet,java]
-----------
source=manual/src/main/java/org/qi4j/manual/recipes/createEntity/MyAssembler.java
tag=assembler2
-----------
== The UnitOfWork ==
If you notice, there is a couple of calls to Module.currentUnitOfWork(), but what is current UnitOfWork, and
who is setting that up?
Well, the domain layer should not worry about UoW, it is probably the responsibility of the application/service layer
sitting on top. That could be a web application creating and completing a UoW per request, or some other co-ordinator
doing long-running UnitOfWorks.
There are of course a lot more details to get all this completed, but that is beyond the scope of this HowTo.
See <<core-api-unitofwork>> in Core API.