click-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Bob Schellink <sab...@gmail.com>
Subject Re: Click Services
Date Mon, 20 May 2013 13:04:12 GMT
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 <malcolm.edgar@gmail.com>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 <malcolm.edgar@gmail.com>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 <sabob1@gmail.com> 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 <malcolm.edgar@gmail.com>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 <sabob1@gmail.com>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/>
>>>>>
>>>>
>>>>
>>>
>>
>

Mime
View raw message