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.
Qi4j 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.
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.
@Immutable
ModelProperty model();
AccidentHistory accidents();
}
public interface ModelProperty extends Property<String>
{}
public interface Manufacturer
{
NameProperty name();
CountryProperty country();
@UseDefaults
QuantityProperty carsProduced();
}
public interface QuantityProperty extends Property<Long>
{}
public interface NameProperty extends Property<String>
{}
public interface CountryProperty extends Property<String>
{}
public interface AccidentHistory extends ManyAssociation<Accident>
{}
public interface Accident extends Value
{
DescriptionProperty description();
PointInTimeProperty occured();
PointInTimeProperty repaired();
}
public interface DescriptionProperty extends Property<String>
{}
public interface PointInTimeProperty extends Property<Date>
{}
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;
public interface ManufacturerEntity extends Manufacturer, EntityComposite
{}
public interface AccidentValue extends Accident, ValueComposite
{}
module.addValues( AccidentEntity.class );
}
}
We recommend that the life cycle management of entities is placed inside domain factories, one for each type and made available as services.
Injections that are related to the Visibility rules are handled by the @Structure annotation. And the easiest way for us to obtain a UnitOfWorkFactory is simply to;
}
We then need to provide the implementation for the create() method.
Car prototype = builder.instance();
prototype.manufacturer().set( manufacturer );
prototype.model().set( model );
return builder.newInstance();
}
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.
Manufacturer findByName( String name );
}
public class ManufacturerRepositoryMixin
implements ManufacturerRepository
{
@Structure private UnitOfWorkFactory uowf;
public Manufacturer findByIdentity( String identity )
{
UnitOfWork uow = uowf.currentUnitOfWork();
return uow.find( identity, Manufacturer.class );
}
public Manufacturer findByName( String name )
{
UnitOfWork uow = uowf.currentUnitOfWork();
QueryBuilderFactory qbf = uow.queryBuilderFactory();
QueryBuilder<Manufacturer> builder =
qbf.newQueryBuilder( Manufacturer.class );
Manufacturer template = templateFor( Manufacturer.class );
builder.where( eq( template.name(), name ) );
Query<Manufacturer> query = builder.newQuery();
Iterator<Manufacturer> iterator = query.iterator();
if( iterator.hasNext() )
{
return query.iterator().next();
}
return null;
}
}
module.addValues( AccidentEntity.class );
module.addServices(
ManufacturerRepositoryService.class,
CarEntityFactoryService.class
).visibleIn( Visibility.application );
}
}
Well, the domain layer should not worry about UoW, it is probably the responsibility of the application 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.