| ////////////////////// |
| * 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. |