You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Sonny Gill <so...@gmail.com> on 2011/10/05 19:07:24 UTC

Re: Injecting domain object into all pages

Hi guys,

I tried this a few days ago, ran into a few problems, and then tried again
today.

Unfortunately I could not get this to work.

On changing the method name to contributeSiteInjectionProvider, it was
detected by Tapestry, and the provider and FieldValueConduit is created, but
the ReadOnlyFieldValueConduit.get() was never called.

Then I upgraded to Tapestry 5.3-beta-16, and it looks
like ReadOnlyFieldValueConduit has been removed.


Finally, I tried to follow
http://wiki.apache.org/tapestry/JEE-Annotationand added the following
:-

public class SiteAnnotationWorker implements ComponentClassTransformWorker2
{

    @Override
    public void transform(PlasticClass plasticClass, TransformationSupport
transformationSupport, MutableComponentModel mutableComponentModel) {
        for (PlasticField field :
plasticClass.getFieldsWithAnnotation(Inject.class)) {
            if (Site.class.getName().equals(field.getTypeName())) {
                field.inject(new Site());
                field.claim(Inject.class);
            }
        }
    }

}

and in AppModule,

    @Contribute(ComponentClassTransformWorker2.class)
    @Primary
    public static void
provideClassTransformWorkers(OrderedConfiguration<ComponentClassTransformWorker2>
configuration) {
        configuration.addInstance("site", SiteAnnotationWorker.class,
"before:Property");
    }

With this, the field is injected correctly (great!).

The problem now is that Tapestry continues to keep the injected object
around and injects the same object for every request.
This is probably correct for the use case
for ComponentClassTransformWorker(s), but I need to inject a different
object on each HTTP request.

How can I achieve that?

Again.. I am very thankful for the help received so far. I would have been
completely lost without it.


Best regards,
Sonny




On Wed, Sep 28, 2011 at 2:59 PM, Cezary Biernacki <ce...@gmail.com>wrote:

> Hi,
> I built a website with similar requirements, and it is not hard to do that
> with Tapestry. A simple approach is to built a service that returns correct
> 'Site' instance, and use it everywhere where you need to 'site'.
>
> So instead having
>  private Site site;
>
> you would have, e.g.
>   @Inject
>   private SiteLookup lookup;
>
>
> and instead using 'site', you would use 'lookup.getSite()'. SiteLookup can
> depend on 'Request' service, so there is no need to pass it as argument to
> getSite() method.
>
> But, if you are not afraid of some more advanced machinery, you can
> contribute your own InjectionProvider, and inject 'Site' directly,
> something
> like:
>
>
> public class SiteInjectionProvider implements InjectionProvider {
>    private final Request request;
>
>    public  SiteInjectionProvider (Request request) {
>        this.request = request;
>    }
>
>    @Override
>    public boolean provideInjection(String fieldName,
> @SuppressWarnings("rawtypes") Class fieldType,
>            ObjectLocator locator, ClassTransformation transformation,
> MutableComponentModel componentModel) {
>
>        if (!Site.class.equals(fieldType)) {
>            return false;
>        }
>
>        TransformField field = transformation.getField(fieldName);
>
>        ComponentValueProvider<FieldValueConduit> provider =
> createProvider(fieldName);
>
>        field.replaceAccess(provider);
>
>        return true;
>    }
>
>    private ComponentValueProvider<FieldValueConduit> createProvider(final
> String fieldName) {
>
>        return new ComponentValueProvider<FieldValueConduit>() {
>
>            public FieldValueConduit get(final ComponentResources resources)
> {
>
>                return new ReadOnlyFieldValueConduit(resources, fieldName) {
>                    public Object get() {
>                        return ....; // <--- here implement selecting
> correct Site based on Request
>                    }
>                };
>            }
>
>        };
>    }
>
> }
>
>
> Remember to contribute your injection provider in your AppModule
>
>    @Contribute(InjectionProvider.class)
>    public static void
> setupInjectingSite(OrderedConfiguration<InjectionProvider> configuration) {
>        configuration.addInstance("site", SiteInjectionProvider .class,
> "after:Default");
>
>    }
>
>
> After that, you would be able to use
>   @Inject
>    private Site site;
>
> on your pages and components.
>
> Best regards,
> Cezary
>
>
>
>
>
>
>
> On Wed, Sep 28, 2011 at 2:39 PM, Sonny Gill <so...@gmail.com>
> wrote:
>
> > Thanks Barry.
> >
> > Site is a domain layer object and knows nothing about Request/Response
> etc.
> > There will be a limited number of Site objects, one for each site
> > supported,
> > created and configured at the application start up.
> >
> > I could set it up as a Service for Tapestry application.
> > But can I then provide a Service lookup method that can look at the
> current
> > request, get the correct Site using some criteria, and hand it over to
> > Tapestry to inject into the page for current request?
> >
> > So, something like :-
> >
> > public Service lookupSiteService(Request request) {
> >   String id = ...get site id from the request in some way...;
> >
> >   SiteRepository repository = ...; // Can I inject an implementation of
> > SiteRepository (also a domain layer object) here?
> >
> >   return repository.getSite(id);
> > }
> >
> >
>



-- 
http://sonnygill.net/
http://twitter.com/sonny_gill
http://www.linkedin.com/in/sonnygill

Re: Injecting domain object into all pages

Posted by Cezary Biernacki <ce...@gmail.com>.
Hi,
I am still using Tapestry 5.2.6, so I am not sure what changed in Tapestry
5.3. However I believe, that "field.inject(new Site());" line is wrong. It
inserts a constant value to the field. I believe (if online documentation is
still relevant) that you should use field.setConduit() instead, and provide
FieldConduit<Site> instance that selects in get() method a correct Site
based on a request.

See

http://tapestry.apache.org/5.3/apidocs/org/apache/tapestry5/plastic/PlasticField.html#setConduit(org.apache.tapestry5.plastic.FieldConduit)

http://tapestry.apache.org/5.3/apidocs/org/apache/tapestry5/plastic/FieldConduit.html

However, I would recommend avoiding using such advanced techniques with a
beta version of Tapestry. More mundane approach with normal injection of a
service, that has a single method returning Site would work on all versions
of Tapestry 5 without any headaches.

Best regards,
Cezary


On Wed, Oct 5, 2011 at 7:07 PM, Sonny Gill <so...@gmail.com> wrote:

> Hi guys,
>
> I tried this a few days ago, ran into a few problems, and then tried again
> today.
>
> Unfortunately I could not get this to work.
>
> On changing the method name to contributeSiteInjectionProvider, it was
> detected by Tapestry, and the provider and FieldValueConduit is created,
> but
> the ReadOnlyFieldValueConduit.get() was never called.
>
> Then I upgraded to Tapestry 5.3-beta-16, and it looks
> like ReadOnlyFieldValueConduit has been removed.
>
>
> Finally, I tried to follow
> http://wiki.apache.org/tapestry/JEE-Annotationand added the following
> :-
>
> public class SiteAnnotationWorker implements ComponentClassTransformWorker2
> {
>
>    @Override
>    public void transform(PlasticClass plasticClass, TransformationSupport
> transformationSupport, MutableComponentModel mutableComponentModel) {
>        for (PlasticField field :
> plasticClass.getFieldsWithAnnotation(Inject.class)) {
>            if (Site.class.getName().equals(field.getTypeName())) {
>                field.inject(new Site());
>                field.claim(Inject.class);
>            }
>        }
>    }
>
> }
>
> and in AppModule,
>
>    @Contribute(ComponentClassTransformWorker2.class)
>    @Primary
>    public static void
>
> provideClassTransformWorkers(OrderedConfiguration<ComponentClassTransformWorker2>
> configuration) {
>        configuration.addInstance("site", SiteAnnotationWorker.class,
> "before:Property");
>    }
>
> With this, the field is injected correctly (great!).
>
> The problem now is that Tapestry continues to keep the injected object
> around and injects the same object for every request.
> This is probably correct for the use case
> for ComponentClassTransformWorker(s), but I need to inject a different
> object on each HTTP request.
>
> How can I achieve that?
>
> Again.. I am very thankful for the help received so far. I would have been
> completely lost without it.
>
>
> Best regards,
> Sonny
>
>
>
>
> On Wed, Sep 28, 2011 at 2:59 PM, Cezary Biernacki <cezary.bi@gmail.com
> >wrote:
>
> > Hi,
> > I built a website with similar requirements, and it is not hard to do
> that
> > with Tapestry. A simple approach is to built a service that returns
> correct
> > 'Site' instance, and use it everywhere where you need to 'site'.
> >
> > So instead having
> >  private Site site;
> >
> > you would have, e.g.
> >   @Inject
> >   private SiteLookup lookup;
> >
> >
> > and instead using 'site', you would use 'lookup.getSite()'. SiteLookup
> can
> > depend on 'Request' service, so there is no need to pass it as argument
> to
> > getSite() method.
> >
> > But, if you are not afraid of some more advanced machinery, you can
> > contribute your own InjectionProvider, and inject 'Site' directly,
> > something
> > like:
> >
> >
> > public class SiteInjectionProvider implements InjectionProvider {
> >    private final Request request;
> >
> >    public  SiteInjectionProvider (Request request) {
> >        this.request = request;
> >    }
> >
> >    @Override
> >    public boolean provideInjection(String fieldName,
> > @SuppressWarnings("rawtypes") Class fieldType,
> >            ObjectLocator locator, ClassTransformation transformation,
> > MutableComponentModel componentModel) {
> >
> >        if (!Site.class.equals(fieldType)) {
> >            return false;
> >        }
> >
> >        TransformField field = transformation.getField(fieldName);
> >
> >        ComponentValueProvider<FieldValueConduit> provider =
> > createProvider(fieldName);
> >
> >        field.replaceAccess(provider);
> >
> >        return true;
> >    }
> >
> >    private ComponentValueProvider<FieldValueConduit> createProvider(final
> > String fieldName) {
> >
> >        return new ComponentValueProvider<FieldValueConduit>() {
> >
> >            public FieldValueConduit get(final ComponentResources
> resources)
> > {
> >
> >                return new ReadOnlyFieldValueConduit(resources, fieldName)
> {
> >                    public Object get() {
> >                        return ....; // <--- here implement selecting
> > correct Site based on Request
> >                    }
> >                };
> >            }
> >
> >        };
> >    }
> >
> > }
> >
> >
> > Remember to contribute your injection provider in your AppModule
> >
> >    @Contribute(InjectionProvider.class)
> >    public static void
> > setupInjectingSite(OrderedConfiguration<InjectionProvider> configuration)
> {
> >        configuration.addInstance("site", SiteInjectionProvider .class,
> > "after:Default");
> >
> >    }
> >
> >
> > After that, you would be able to use
> >   @Inject
> >    private Site site;
> >
> > on your pages and components.
> >
> > Best regards,
> > Cezary
> >
> >
> >
> >
> >
> >
> >
> > On Wed, Sep 28, 2011 at 2:39 PM, Sonny Gill <so...@gmail.com>
> > wrote:
> >
> > > Thanks Barry.
> > >
> > > Site is a domain layer object and knows nothing about Request/Response
> > etc.
> > > There will be a limited number of Site objects, one for each site
> > > supported,
> > > created and configured at the application start up.
> > >
> > > I could set it up as a Service for Tapestry application.
> > > But can I then provide a Service lookup method that can look at the
> > current
> > > request, get the correct Site using some criteria, and hand it over to
> > > Tapestry to inject into the page for current request?
> > >
> > > So, something like :-
> > >
> > > public Service lookupSiteService(Request request) {
> > >   String id = ...get site id from the request in some way...;
> > >
> > >   SiteRepository repository = ...; // Can I inject an implementation of
> > > SiteRepository (also a domain layer object) here?
> > >
> > >   return repository.getSite(id);
> > > }
> > >
> > >
> >
>
>
>
> --
> http://sonnygill.net/
> http://twitter.com/sonny_gill
> http://www.linkedin.com/in/sonnygill
>