Return-Path: X-Original-To: apmail-click-dev-archive@www.apache.org Delivered-To: apmail-click-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 129ABD2DB for ; Mon, 20 May 2013 12:10:16 +0000 (UTC) Received: (qmail 23595 invoked by uid 500); 20 May 2013 12:10:15 -0000 Delivered-To: apmail-click-dev-archive@click.apache.org Received: (qmail 23498 invoked by uid 500); 20 May 2013 12:10:14 -0000 Mailing-List: contact dev-help@click.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@click.apache.org Delivered-To: mailing list dev@click.apache.org Received: (qmail 23456 invoked by uid 99); 20 May 2013 12:10:13 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 20 May 2013 12:10:13 +0000 X-ASF-Spam-Status: No, hits=1.5 required=5.0 tests=HTML_MESSAGE,RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of malcolm.edgar@gmail.com designates 209.85.214.174 as permitted sender) Received: from [209.85.214.174] (HELO mail-ob0-f174.google.com) (209.85.214.174) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 20 May 2013 12:10:07 +0000 Received: by mail-ob0-f174.google.com with SMTP id un3so6965971obb.33 for ; Mon, 20 May 2013 05:09:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:x-received:in-reply-to:references:date:message-id :subject:from:to:content-type; bh=5wkk8b/TngZnf9HXfovstJ9ZWrQ6t+EUbS+hLgFj5/I=; b=IKkD1Ce5B7ClvgKF64v7aWV34g8fYyRIYQIAaVSNJR8XA+op+ywr0Au1GJ4y0sNTCv qcC7iWJrUUMD1O9vK2vBXZi08d7nQNOy3Ajfv87pSBhvv0QFEqaNvLhEzExJLSyc5bSA zISSBoGTxHD/sMgjGElPlGvndnqB8TCQLuZz6xkzsxzgqH0butG9ZcRQcDtDIuLDx4YF +GIKVOlLCoc3nKhwHzDdVDAwpCZ4BOMASkACHv97+3GxaonJhS+USn92NCt16Wyv22D4 mKSxm6vCaOH3n9rMTTI4hTlSmIo4dMqROf2ukiofz+jyt05cjAET660GS+8mRlBLvFzI tBIg== MIME-Version: 1.0 X-Received: by 10.182.32.34 with SMTP id f2mr27108925obi.86.1369051785528; Mon, 20 May 2013 05:09:45 -0700 (PDT) Received: by 10.76.73.197 with HTTP; Mon, 20 May 2013 05:09:45 -0700 (PDT) In-Reply-To: References: <517BD7C4.1050901@gmail.com> <519293E9.5010108@gmail.com> Date: Mon, 20 May 2013 22:09:45 +1000 Message-ID: Subject: Re: Click Services From: Malcolm Edgar To: dev Content-Type: multipart/alternative; boundary=089e013a07945b09e704dd25359e X-Virus-Checked: Checked by ClamAV on apache.org --089e013a07945b09e704dd25359e Content-Type: text/plain; charset=ISO-8859-1 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 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 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 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 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 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/ >>>> >>> >>> >> > --089e013a07945b09e704dd25359e Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
Another approach for generating documentation would be to = use a class properties file and look up the HTML doco based on the method n= ame, e.g.

CustomerServivce.properties
--------= -------------------------------------------------------------

CustomerServivce =3D=A0Providers Customer Account query services.

getCustomers=A0=3D=A0Return the list of customers matching the give= n keyword and active status.=A0\n\
param :=A0keyword : String :=A0Search for = customers matching the keyword (optiona)=A0\n\
=A0 =A0 =A0 =A0 param : active : boolean :=A0Include only active accounts (opti= onal)" \n\
=A0 =A0 =A0 =A0 return : customer : array of custom= ers


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 th= e 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 desc= riptor to generate doco would not be fun.=A0

Using= straight reflection wouldn't probably work because the Java reflection= API doesn't tell you what the parameter names are. =A0We would need to= add annotations to make this work. =A0However writing code with annotation= s for doco is pretty yucky, e.g.

package com.mycorp.services;

<= div>@Doc(desc=3D"Providers Customer Account query services")
public class CustomerService {

@Doc(desc=3D"R= eturn the list of customers matching the given keyword and active status&qu= ot;)
public List<= Customer> getCustomers(
@Doc(param=3D"keyw= ord", desc=3D"Search for customers matching the keyword (optional= ") String keyword,
<= /span>@Doc(param=3D"active", desc=3D"Include only active acc= ounts (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 d= ocumentation. Maybe a valid approach, especially if we can rely on a decent= library to do the marshalling. =A0Using 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/singleto= n 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/?ke= yword=3Djohn&active=3Dtrue

Would attempt to lo= ok up the class paths:

com.mycorp.services.CustomerService

Then attempt t= o resolve the method:

getCustomers(String, String)=

While this is is favoring convention over c= onfiguration, in my experience this works really well in building large sys= tems.

Would be good for the Filter to use the Click Logging s= ervice, and log the appropriate output depending upon the application mode.= =A0

It would also would be nice to have the Filte= r support formatting the JSON response to make it more human readable, with= an optional formatJson=3Dtrue request parameter.

While all these things may appear to be pretty minor be= nefits, I think they would have a cumulative productivity benefit which wou= ld 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. JS= ON over HTTP instead of REST.

Interestingly, Roy Fielding says a se= rvice isn't REST if it isn't hypertext driven:
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driv= en

Basically nobody is doing REST anyway ;-)

Wrt self documenting efforts, there is Swagger and WADL:
developers.he= lloreverb.com/swagger/

Swager Demo:
http://petstore.swagger.wordnik.c= om/

WADL:
http://en.wikipedia.org/wiki/Web_Applicat= ion_Description_Language

I'm not sure how we could self desc= ribe these services though. Perhaps a url like '/services' could ge= nerate an HTML page with links to all registered services. But Click will t= hen have to "discover" it's own services somehow via reflecti= on or annotations or at build time.

We also have to provide the input and outputs (JSON) of the services. I= f a service looked like this:

public Person getPerson(String id) {}

we could generate the JSON of a Person instance, as long as it h= as a no-args constructor. The JSON won't have any values though so it w= ould look like:

{Person: {'firstname': null, 'surname': null, 'date= OfBirth': null}}

unless we add default values for primitives:{Person: {'firstname': "example", 'surname': &qu= ot;example", 'dateOfBirth': "2013/01/01" }}

If we target JDK7 we could use the new InvokeDynamic instead of reflect= ion. InvokeDynamic should be quite a bit faster.

Another note from y= our example:
customerservice/getcustomer/?id=3D123456

how wo= uld one dynamically map customerservice to CustomerService? The URL would h= ave 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=A0mer= it=A0in this stuff for=A0RPC=A0JSON services.=A0

I would= like to see some form of API documenting feature, this is a problem with e= xisting services they are hard to program to because they are not self desc= ribing like Web Services are. This could be tricky to implement however, an= d 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 implemen= ting some service interface, e.g.

=A0 =A0com.mycor= p.service.GetCustomerService

=A0 =A0/mycorp/service/getcustomer/?id=3D123456


2) multiple RPC methods per class, using ref= lection to lookup the methods:

=A0 =A0com.myc= orp.service.CustomerService

=A0 =A0/mycorp/service/customerservice/getcustomer/?id= =3D123456

=A0 =A0/mycorp/service/custome= rservice/getcustomerlist/?keyword=3Dbob


In terms of whether we should support singleton /prototype (Spring ter= minology) services. I distrust stateful services and would prefer new servi= ce instances to be created per request. If people what to cache stuff, they= can do this themselves in the servlet context. =A0If we take this approach= I don't think we need lifecycle methods onInit(), onDestroy() etc. =A0= 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= 9;s on demand approach would be good where by we cache resolved look-ups. F= or implementation agree the Filter would be the best approach as this would= avoid impacting the ClickServlet and the XML configuration stuff. =A0It wo= uld be good do have some package automapping stuff like we do with Click pa= ges. Maybe this could be configure against the filter in the web.xml

regards


On Wed, May 15, 2013 at 5:43 AM, Bob Sc= hellink <sabob1@gmail.com> wrote:
On 2013/05/14 15:45, Malcolm Edgar wrot= e:
I think this is an interesting discussion. =A0I am seeing existing Multiple= Page Applications (MPA),
which is Clicks forte, evolve into hybrid MPA / Single Page Applications (S= PA) using frameworks like
AngularJS.

For serving JSON/RPC we have been using both hand coded Servlets with net.s= f.json.JSONSerializer and
using services built with RESTEasy (http://www.jboss.org/resteasy). =A0The REST= Easy approach is
more idiomatic Java (lots of layers of abstraction) and works well 99% of t= ime.

I am not sure what the value Click could provide for services.

Nods, we will be reinventing the wheel a bit.


=A0While I agree Velocity templates
would be useful for rendering a JSON response, the main problem in this spa= ce is marshalling JSON
request data into Java objects. Maybe Marco google library would be good fo= r this.

I'm currently using GSON[1], mostly because their docs is straightforwa= rd.




How would you see the services being registered, e.g. XML definition or aut= o-mapped some how ?

Guess annotation based but it looks like a pain to discover the annotated c= lasses. 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 disco= ver annotated classes and build an index of classes.

One could also use plain interfaces and build up a cache at runtime eg: eac= h request that matches a valid class is placed in a map and cached for fast= er retrieval in the future.

Kind regards

Bob

[1]: ht= tp://code.google.com/p/google-gson/




--089e013a07945b09e704dd25359e--