Hey,
Continuing the AssociationRole discussion, since we would want to make
it possible to expose something in the interface which has methods for
the state directly instead of going through the AssociationRole, and
since we have also previously discussed how to get Concerns on top of
Associations (i.e. when getting or setting an Association we want to
intercept it and also do side-effects etc.), I've made a test that shows
how to do this using Composites as wrappers.
Here's the test code I want to work:
Person person;
{
EntityBuilder<Person> builder = unitOfWork.newEntityBuilder(
Person.class );
builder.stateOfComposite().name().set( "Rickard" );
person = builder.newInstance();
}
CompanyEntity companyEntity;
{
EntityBuilder<CompanyEntity> builder = unitOfWork.newEntityBuilder(
CompanyEntity.class );
companyEntity = builder.newInstance();
}
Employee employee;
{
EntityBuilder<Employee> builder =
unitOfWork.newEntityBuilder(Employee.class);
builder.stateOfComposite().position().set( "CEO" );
employee = builder.newInstance();
}
companyEntity.employees().add( role( person, employee) );
companyEntity.employees().remove( role( person, employee) );
---
In this case I want to be able to let employees() return a custom
Employees collection instead of just a
ManyAssociation<AssociationRole<Person,Employee>, and I also want to be
able to do audit logging whenever I add or remove employees. The
interfaces and mixins for this looks like so:
@Mixins( CompanyMixin.class )
interface CompanyEntity
extends EntityComposite
{
// Here there's a Domain concept instead
// of a ManyAssociation being returned
Employees employees();
}
interface Person
extends EntityComposite
{
Property<String> name();
}
interface Employee
extends EntityComposite
{
Property<String> position();
}
// Here is the Employees definition, which is a regular Composite
// that extends ManyAssociation
// Since it is a Composite I can also add Concerns to it
// The generic DecoratorMixin will simply delegate all methods
// to a CompositeBuilder.use()-supplied ManyAssociation
@Mixins( DecoratorMixin.class )
@Concerns( EmployeesAuditConcern.class )
interface Employees
extends ManyAssociation<AssociationRole<Person, Employee>>, Composite
{
}
// Here I create the Employees Composite in the constructor as a
// wrapper of the regular ManyAssociation
public static abstract class CompanyMixin
implements CompanyEntity
{
Employees employees;
public CompanyMixin( @Structure CompositeBuilderFactory cbf,
@AssociationParameter( "employees" ) ManyAssociation employees )
{
this.employees = cbf.newCompositeBuilder( Employees.class
).use( employees ).newInstance();
}
public Employees employees()
{
return employees;
}
}
// This concern prints out hirings and firings,
// which are mapped to add/remove in ManyAssociation/Collection
public static abstract class EmployeesAuditConcern
extends ConcernOf<Employees>
implements Employees
{
public boolean add( AssociationRole<Person, Employee>
personEmployeeAssociationRole )
{
System.out.println("Hired
"+personEmployeeAssociationRole.association().name()+" as
"+personEmployeeAssociationRole.role().position());
return next.add(personEmployeeAssociationRole);
}
public boolean remove( Object o )
{
AssociationRole<Person, Employee> personEmployeeAssociationRole
= (AssociationRole<Person, Employee>) o;
System.out.println("Fired
"+personEmployeeAssociationRole.association().name()+" as
"+personEmployeeAssociationRole.role().position());
return next.remove( o );
}
}
---
If you want you can add Property methods to Employees which get
delegated to the AssociationRole.role() methods, thus hiding it.
The above works with a few minor modifications to the current Qi4j codebase.
This could be improved even more by making Employees a true domain
concept, which does not expose the internal collection, but rather only
domain methods. This will be shown in the next post (to keep the size of
the posts down).
/Rickard
_______________________________________________
qi4j-dev mailing list
[email protected]
http://lists.ops4j.org/mailman/listinfo/qi4j-dev