Gang,

I am trying to find ways to make third-party "foreign" interfaces to
work nicely with Qi4j. The actual use-case is a web service that the
provider gives to us via a ServiceFactory and a Java interface;

Abc service = ServiceFactory.getService( Abc.class );

Now, many of the methods in the "Abc" interface are really query
methods, and I thought that I can map those methods into Qi4j as Named
Queries with query variables.

The most obvious way for me to introduce "named query" support is via
the Service concept, so a NamedQueryService is introduced to the API,
with a single method;

/**
 * NamedQueryService is a provider for named, native and other special
query types.
 *
 * Named queries can also be used to centralize the query management,
and avoid having
 * query code spread out in the domain model, even if the
implementation of the NamedQueryService
 * is using the Qi4j Query API.
 */
public interface NamedQueryService
{
    /**
     * Returns a Query with the given name and result type.
     *
     * @param name The name of the query. To avoid naming conflicts,
FQDNs should be used.
     * @param resultType the Query result type.
     * @param unitOfWork The UnitOfWork that the Query shall belong to.
     * @return a Query instance.
     */
    <T> Query<T> newQuery( String name, Class<T> resultType,
UnitOfWork unitOfWork );
}

But client code should not use this directly. Instead I suggest we
introduce a new method in QueryBuilderFactory (and possibly change
name of this to QueryFactory);

    <T> Query<T> newNamedQuery( String name, Class<T> resultType );

Now, I have the building blocks in Qi4j API to allow me to do the
above mentioned use-case.

The implementation looks something like this;

@Mixins( BeanServiceMixin.class )
public interface BeanServiceComposite extends NamedQueryService,
ServiceComposite
{
}

public BeanServiceMixin( @Uses Object beanService, @Uses Class mapInterface )

I am leaving out most code for brevity.

So, the BeanServiceComposite needs to be established with 2 uses().
"beanService" is the foreign provider, and the "mapInterface" is a way
to annotate the interface that I don't own. For instance;

This is the foreign interface that I have no control over;

public interface Abc
{
    Habba findHabbaFromName( String name );
}

Then I create a Mapping interface to provide some annotations;

public interface AbcMapping extends Abc
{
    @QueryMethod
    Habba findHabbaFromName( @VariableName( "name" ) String name );
}

(@QueryMethod can also take the name of the query as the value() argument)


And to set it up, one would need a ServiceInstanceFactory

public class AbcServiceFactory
    implements ServiceInstanceFactory
{
    public Object newInstance( ServiceDescriptor serviceDescriptor )
        throws ServiceInstanceProviderException
    {
        // Get the foreign instance.
        Abc service = ServiceFactory.getService( Abc.class );

        QueryBuilder<BeanServiceComposite> builder =
            cbf.newCompositeBuilder( BeanServiceComposite.class );
        builder.use( AbcMapping.class );
        builder.use( service );
        return builder.newInstance();
    }

    public void releaseInstance( Object instance )
        throws ServiceInstanceProviderException
    {
        ServiceFactory.releaseService( instance );
    }
}


And one could now use the Abc web service as if it was a named query;


@Structure QueryBuilderFactory factory;

:
Query<Habba> query = factory.newNamedQuery( "findHabbaFromName", Habba.class );
Habba habba = query.find();



Ok, that is my plan, and I am half way through it, but would like some
feedback before getting into the really gritty details. For instance,
I have ignored the relationship with an EntityStore for now, but
Rickard and I have done a 2min discussion on the whiteboard (but I
can't recall the details) without any definitive answers but some
vague intentions of creating temporary Identities for queried
instances and so forth. More on that later.


Oh, Habba in the above example, is then potentially back by the
JavabeanSupport that I have done over the last few weeks, so that no
transfer objects needs to be created, and we can stick a Qi4j facade
on the pojo itself.


Cheers
Niclas

_______________________________________________
qi4j-dev mailing list
[email protected]
http://lists.ops4j.org/mailman/listinfo/qi4j-dev

Reply via email to