Thanks that's really useful and does exactly what we want, it's not a problem for us to make all our controller interfaces extend a marker type.
Cheers Dave joshcanfield wrote: > > 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 > > > -- View this message in context: http://www.nabble.com/passing-a-service-into-a-component-as-a-parameter-tp25505462p25566444.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