I was thinking ClickServlet should be revamped into a filter to support Services, but perhaps a separate Filter is more appropriate. Also as Naoki mentioned, Click is predominantly a Page framework, so the Service stuff could be placed into a separate jar?
Kind regards Bob On Mon, May 20, 2013 at 3:04 PM, Bob Schellink <[email protected]> wrote: > I don't personally use stateful services so we could start without > supporting them. We have also deprecated stateful Pages. > > Makes sense not to have any type of life cycle methods then too. > > The properties idea is interesting. One advantage is i18n. On the other > hand it moves the doco away from the code, which makes it more difficult > and unlikely to be updated. > > On that note, is it even possible to invoke a service method and pass in > arguments eg: > > CustomerService.getCustomers(String arg1, String arg2) > > How would we be able to know which request parameter to pass to arg1? If > the argument name ("arg1" in this case) is not available via reflection it > might not be possible to figure out which arg goes where. > > I know JAX RS uses annotations to specify args eg: > CustomerService.getCustomers(@QueryParam("arg1") String arg1, > @QueryParam("arg2") String arg2) > > If we use annotations for args then we can also use those annotations for > docs. > > So there are a couple of ways for Click to support invoking a service > method: > 1) Use no-arg methods and pull the request parameters through the Servlet > API. Won't be able to auto document this option > 2) Pass in primitive arguments (Strings, integer etc.) > 3) Pass in a DTO (for posting JSON) > > Not sure if we should support some or all of them. Should be fairly easy > though as we've solved most of these problems already with Click. > > Kind regards > > Bob > > > On Mon, May 20, 2013 at 2:09 PM, Malcolm Edgar <[email protected]>wrote: > >> Another approach for generating documentation would be to use a class >> properties file and look up the HTML doco based on the method name, e.g. >> >> CustomerServivce.properties >> --------------------------------------------------------------------- >> >> CustomerServivce = Providers Customer Account query services. >> >> getCustomers = Return the list of customers matching the given keyword >> and active status. \n\ >> param : keyword : String : Search for customers matching the keyword >> (optiona) \n\ >> param : active : boolean : Include only active accounts >> (optional)" \n\ >> return : customer : array of customers >> >> >> regards Malcolm >> >> >> On Mon, May 20, 2013 at 9:07 PM, Malcolm Edgar >> <[email protected]>wrote: >> >>> Hi Bob, >>> >>> thanks for the links to Roy's blog post. I have to admit I have used the >>> REST terminology a lot when talking about JSON RPC, so I am trying to be >>> more precise nowdays. >>> >>> The WADL looks interesting, however writing an XML descriptor to >>> generate doco would not be fun. >>> >>> Using straight reflection wouldn't probably work because the Java >>> reflection API doesn't tell you what the parameter names are. We would >>> need to add annotations to make this work. However writing code with >>> annotations for doco is pretty yucky, e.g. >>> >>> package com.mycorp.services; >>> >>> @Doc(desc="Providers Customer Account query services") >>> public class CustomerService { >>> >>> @Doc(desc="Return the list of customers matching the given keyword and >>> active status") >>> public List<Customer> getCustomers( >>> @Doc(param="keyword", desc="Search for customers matching the keyword >>> (optional") String keyword, >>> @Doc(param="active", desc="Include only active accounts (optional)") >>> boolean active) { >>> .. >>> } >>> } >>> >>> Still it would be a pretty nice feature to have APIs which are self >>> describing. >>> >>> Its interesting using the returned POJO to create the documentation. >>> Maybe a valid approach, especially if we can rely on a decent library to do >>> the marshalling. Using a reflection based approach would give us the most >>> flexibility, so you could return an ActionResult or a POJO and the Filter >>> would handle this result. >>> >>> Do you think there is merit in having stateful/singleton services ? >>> >>> In terms of mapping, I think we could develop some reasonable >>> conventions like we have done with Click pages and cache the results, e.g. >>> >>> GET >>> /mycorp/services/customer-service/get-customers/?keyword=john&active=true >>> >>> Would attempt to look up the class paths: >>> >>> com.mycorp.services.CustomerService >>> >>> Then attempt to resolve the method: >>> >>> getCustomers(String, String) >>> >>> While this is is favoring convention over configuration, in my >>> experience this works really well in building large systems. >>> >>> Would be good for the Filter to use the Click Logging service, and log >>> the appropriate output depending upon the application mode. >>> >>> It would also would be nice to have the Filter support formatting the >>> JSON response to make it more human readable, with an optional >>> formatJson=true request parameter. >>> >>> While all these things may appear to be pretty minor benefits, I think >>> they would have a cumulative productivity benefit which would be >>> significant. >>> >>> regards Malcolm >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> On Mon, May 20, 2013 at 7:14 PM, Bob Schellink <[email protected]> wrote: >>> >>>> Hi Malcolm, >>>> >>>> Multiple requests per service is what I have in mind. JSON over HTTP >>>> instead of REST. >>>> >>>> Interestingly, Roy Fielding says a service isn't REST if it isn't >>>> hypertext driven: >>>> http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven >>>> >>>> Basically nobody is doing REST anyway ;-) >>>> >>>> Wrt self documenting efforts, there is Swagger and WADL: >>>> developers.helloreverb.com/swagger/ >>>> >>>> Swager Demo: >>>> http://petstore.swagger.wordnik.com/ >>>> >>>> WADL: >>>> http://en.wikipedia.org/wiki/Web_Application_Description_Language >>>> >>>> I'm not sure how we could self describe these services though. Perhaps >>>> a url like '/services' could generate an HTML page with links to all >>>> registered services. But Click will then have to "discover" it's own >>>> services somehow via reflection or annotations or at build time. >>>> >>>> We also have to provide the input and outputs (JSON) of the services. >>>> If a service looked like this: >>>> >>>> public Person getPerson(String id) { >>>> } >>>> >>>> we could generate the JSON of a Person instance, as long as it has a >>>> no-args constructor. The JSON won't have any values though so it would look >>>> like: >>>> >>>> {Person: {'firstname': null, 'surname': null, 'dateOfBirth': null}} >>>> >>>> unless we add default values for primitives: >>>> {Person: {'firstname': "example", 'surname': "example", 'dateOfBirth': >>>> "2013/01/01" }} >>>> >>>> If we target JDK7 we could use the new InvokeDynamic instead of >>>> reflection. InvokeDynamic should be quite a bit faster. >>>> >>>> Another note from your example: >>>> customerservice/getcustomer/?id=123456 >>>> >>>> how would one dynamically map customerservice to CustomerService? The >>>> URL would have to respect the class case otherwise we won't be able to look >>>> it up automatically. Unless there is a mapping somewhere (web.xml or >>>> annotation) which maps the lower case customerservice to CustomerService. >>>> >>>> Kind regards >>>> >>>> Bob >>>> >>>> >>>> On Mon, May 20, 2013 at 5:49 AM, Malcolm Edgar <[email protected] >>>> > wrote: >>>> >>>>> I think there is some merit in this stuff for RPC JSON services. >>>>> >>>>> I would like to see some form of API documenting feature, this is a >>>>> problem with existing services they are hard to program to because they >>>>> are >>>>> not self describing like Web Services are. This could be tricky to >>>>> implement however, and you may want to disable this on production systems. >>>>> >>>>> Interesting to think what the design should be: >>>>> >>>>> 1) single RPC method per class, with the service implementing some >>>>> service interface, e.g. >>>>> >>>>> com.mycorp.service.GetCustomerService >>>>> >>>>> /mycorp/service/getcustomer/?id=123456 >>>>> >>>>> >>>>> 2) multiple RPC methods per class, using reflection to lookup the >>>>> methods: >>>>> >>>>> com.mycorp.service.CustomerService >>>>> >>>>> /mycorp/service/customerservice/getcustomer/?id=123456 >>>>> >>>>> /mycorp/service/customerservice/getcustomerlist/?keyword=bob >>>>> >>>>> >>>>> In terms of whether we should support singleton /prototype (Spring >>>>> terminology) services. I distrust stateful services and would prefer new >>>>> service instances to be created per request. If people what to cache >>>>> stuff, >>>>> they can do this themselves in the servlet context. If we take this >>>>> approach I don't think we need lifecycle methods onInit(), onDestroy() >>>>> etc. >>>>> This would also keep it simple, we dont need configuration or annoations >>>>> to describe the service lifecycle. >>>>> >>>>> In terms of mapping requests to service, I think Bob's on demand >>>>> approach would be good where by we cache resolved look-ups. For >>>>> implementation agree the Filter would be the best approach as this would >>>>> avoid impacting the ClickServlet and the XML configuration stuff. It >>>>> would >>>>> be good do have some package automapping stuff like we do with Click >>>>> pages. >>>>> Maybe this could be configure against the filter in the web.xml >>>>> >>>>> regards >>>>> >>>>> >>>>> On Wed, May 15, 2013 at 5:43 AM, Bob Schellink <[email protected]>wrote: >>>>> >>>>>> On 2013/05/14 15:45, Malcolm Edgar wrote: >>>>>> >>>>>>> I think this is an interesting discussion. I am seeing existing >>>>>>> Multiple Page Applications (MPA), >>>>>>> which is Clicks forte, evolve into hybrid MPA / Single Page >>>>>>> Applications (SPA) using frameworks like >>>>>>> AngularJS. >>>>>>> >>>>>>> For serving JSON/RPC we have been using both hand coded Servlets >>>>>>> with net.sf.json.JSONSerializer and >>>>>>> using services built with RESTEasy (http://www.jboss.org/resteasy**). >>>>>>> The RESTEasy approach is >>>>>>> more idiomatic Java (lots of layers of abstraction) and works well >>>>>>> 99% of time. >>>>>>> >>>>>>> I am not sure what the value Click could provide for services. >>>>>>> >>>>>> >>>>>> Nods, we will be reinventing the wheel a bit. >>>>>> >>>>>> >>>>>> While I agree Velocity templates >>>>>> >>>>>>> would be useful for rendering a JSON response, the main problem in >>>>>>> this space is marshalling JSON >>>>>>> request data into Java objects. Maybe Marco google library would be >>>>>>> good for this. >>>>>>> >>>>>> >>>>>> I'm currently using GSON[1], mostly because their docs is >>>>>> straightforward. >>>>>> >>>>>> >>>>>> >>>>>> >>>>>>> How would you see the services being registered, e.g. XML definition >>>>>>> or auto-mapped some how ? >>>>>>> >>>>>> >>>>>> Guess annotation based but it looks like a pain to discover the >>>>>> annotated classes. There are some libs to help with that part but EE >>>>>> environments are tricky eg. JBoss 7 has a custom file system >>>>>> implementation >>>>>> which is tricky to 'scan'. Preprocessor could also be used at compile >>>>>> time >>>>>> to discover annotated classes and build an index of classes. >>>>>> >>>>>> One could also use plain interfaces and build up a cache at runtime >>>>>> eg: each request that matches a valid class is placed in a map and cached >>>>>> for faster retrieval in the future. >>>>>> >>>>>> Kind regards >>>>>> >>>>>> Bob >>>>>> >>>>>> [1]: >>>>>> http://code.google.com/p/**google-gson/<http://code.google.com/p/google-gson/> >>>>>> >>>>> >>>>> >>>> >>> >> >
