I'm assuming that your users aren't uploading the components or the
services, just the pages?

If you use a common interface for your services you can use that class
to access the registry.

I built a quick binding factory and wrote a couple services for it to
use here is the implementation:

public class ServiceBindingFactory implements BindingFactory {
   private BindingSource _source;

   private ObjectLocator _locator;

   ServiceBindingFactory(final BindingSource source, ObjectLocator locator) {
       _source = source;
       _locator = locator;
   }

   public Binding newBinding(String description, ComponentResources
container, ComponentResources component,
                             String expression, Location location) {

       Object service = null;
       try {
// All services that use this binding must implement the PublicService Interface
// this also allows you to keep your private services private.
           service = _locator.getService(expression, PublicService.class);
       } catch (RuntimeException e ) {
           // just ignore it we'll handle null later.
       }

       return new ServiceBinding(service, expression, location);
   }

   public class ServiceBinding extends AbstractBinding {
       private Location _location;
       private Object _service;
       private String _expression;

       ServiceBinding(Object service, String expression, Location location) {
           _service = service;
           _expression = expression;
           _location = location;
       }

       public Object get() {
           if (_service == null) {
               throw new TapestryException("Unable to locate service:
" + _expression
                       , _location, null);
           }
           return _service;
       }
   }
}


The binder and services are added to the AppModule like this:

public class AppModule {
   public static void bind(ServiceBinder binder) {
       // Bind the PublicService classes available to unsafe templates
via the "service" binding.
       binder.bind(ColorService.class,
RedColorService.class).withId("redcolorservice");
       binder.bind(ColorService.class,
BlueColorService.class).withId("bluecolorservice");

       binder.bind(FontService.class,
ArialFontService.class).withId("arialfontservice");
       binder.bind(FontService.class,
MonospaceFontService.class).withId("monospacefontservice");
   }

   public static void contributeBindingSource(
           MappedConfiguration<String, BindingFactory> configuration,
           BindingSource bindingSource,
           ObjectLocator objectLocator
   ) {
       configuration.add("service", new
ServiceBindingFactory(bindingSource,objectLocator));
   }
}

Your component might look like this:

public class StyleAdder {

  �...@parameter
   private ColorService _color;
  �...@parameter
   private FontService _font;

   void beforeRenderTemplate(MarkupWriter writer) {
       writer.element("div");
       StringBuilder style = new StringBuilder();
       if (_color != null)
           style.append("color:").append(_color.getColor()).append(';');

       if (_font != null) {
           style.append("font-family:").append(_font.getFont()).append(';');
       }
       if ( style.length() > 0 )
           writer.attributes("style", style);
   }

   void afterRenderTemplate(MarkupWriter writer) {
       writer.end();
   }
}

And the page would include the component like this:

<t:StyleAdder t:font="service:monospacefontservice"
t:color="service:bluecolorservice">Blue Text</t:StyleAdder>
<t:StyleAdder t:color="service:redcolorservice">Red Text</t:StyleAdder>
<t:StyleAdder t:font="service:arialfontservice"
t:color="service:redcolorservice">Red Arial Text</t:StyleAdder>


Josh

On Mon, Sep 21, 2009 at 6:28 AM, david.boyce
<david.bo...@thisisnumero.com> wrote:
>
>
> What does the text "dooferController" represent in this context? Is it
>> a string that represents the name of the service interface that you
>> want to load? or is it a property in your page that holds a reference
>> to the service implementation?
>>
>
> Sorry, my question probably wasn't very clear. Basically, the components we
> are creating are intended to be reusable, and their behaviour is largely
> defined by services they delegate to, as per your graphing example with the
> BarChartService, PieChartService and ScatterPlotService.
>
> In our product most of the tml is actually supplied by the user, and there
> is no backing code for any of this tml in the conventional sense. When a
> component is used, it's quite convenient to specify the implementation of
> its backing service as a parameter, however, the only way I can see of doing
> this is to introduce a new binding type, which in my example I've called
> "service". The implementation of the sevice binding would ideally pull the
> service out of the Registry.
>
> The problem is when you get into the BindingFactory implementation:
>
> @Inject Registry registry;
>
> @Override
> public Binding newBinding(
>                        final String description,
>                        final ComponentResources container,
>                        final ComponentResources component,
>                        String expression,
>                        final Location location) {
>
>   // oops, how do i get the type?
>   registry.getService(expression, meh?);
> }
>
> So I appreciate that you could probably pass the service id and the service
> type in the expression somehow, but that seems weak to me and wouldn't go
> down well with our users.
>
> As it happens, we had been passing the services into the components in a
> different way previously, as we couldn't see a good way of achieving it via
> parameters (for the previously stated reasons), but came back to it
> recently. After posting the previous message on this forum, I had the idea
> of doing the following, using a bespoke binding type I had already created
> called factory.
>
> The gist of this approach is to have 2 parameters, an internal parameter for
> the actual service, where you specifiy both the service id and the parameter
> type, and a public parameter for the service id (which gets fed into the
> first parameter).
>
> // the user specifies this...
> @Property @Parameter(required=true, defaultPrefix="literal")
> private String controller;
>
> // this is a bespoke binding type, the user doesn't modify this parameter
> @Parameter(defaultPrefix="factory", value="tapestry(" +
>        "id -> prop:controller," +
>        "serviceType -> prop:controllerType )")
> private DataFormRendererController controllerService;
>
> Which basically achieves what we want, but still doesn't seem very good - we
> have to repeat this pattern for every component we have and require 2
> parameters per service.
>
> It just seems to me that being able to inject services out of the tapestry
> registry into the components via parameters without having to perform any
> special incantations would be a nice feature... but meh, what do I know
> (apparently nothing).
>
> Cheers,
>
> Dave
>
>
>
>
>
>
> --
> View this message in context: 
> http://www.nabble.com/passing-a-service-into-a-component-as-a-parameter-tp25505462p25530329.html
> Sent from the Tapestry - User mailing list archive at Nabble.com.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
> For additional commands, e-mail: users-h...@tapestry.apache.org
>
>



--
--
TheDailyTube.com. Sign up and get the best new videos on the internet
delivered fresh to your inbox.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org

Reply via email to