Hi, Fabio,
Thanks a lot for detailed reply.
I agree with you that the approach of defining a MessageBodyWriter to
produce html is more modularized and easier to maintain the code
compared with adding another method of producing html for all of the
xwiki resource classes.
In the previous email, I proposed something similar to JAXBProvder and
JSONProvider in restlet:
@Provider
@Produces("text/html")
class HTMLProvider extends AbstractProvider
In restlet api, AbstractProvider implements MessageBodyWriter and
MessageBodyReader. Regarding the implementation, I thought of using XML
transformation at the beginning as I did not know there is a mothod of
document.getRenderedContent(), which can produce HTML content.
When I look more into the source code, I think one possible way to
re-factor the REST API would be to enhance XWikiResource class and its
inherited classess instead of adding more code to the auto generated
JAXB classes. In the current PageResource implementation, more methods
in getRenderedContent() may be provided so that different media type can
be supported.
@GET
public PageResource getPage() {
return the getRenderedContent()
}
implement getRenderedContent() with the following methods
getRenderedContent(MediaType)
|-- getRenderContentXML
|-- getRenderContentHTML
|-- getRenderContentPDF
Bridge pattern or adapter pattern may be applied in this case, which can
separate the implementation of ContentProvider and actual XWikiResource
itself.
Thomas also pointed out the Android client project also needs to use
REST API. I prefer re-factoring it as soon as possible, if REST API
needs further re-factoring in the future anyway.
Best regards
Jun Han
On Thu, May 19, 2011 at 6:22 AM, Fabio Mancinelli
<fabio.mancinelli(a)xwiki.com> wrote:
On Thu, May 19, 2011 at 7:53 AM, Jun
Han<jun.han37(a)gmail.com> wrote:
Hi Fabio,
Thanks a lot for your clarification.
Following RootResource class, I created a class called PageHTMLResource,
which extends XWikiResource. This class defines a new endpoint
(/wikis/{wikiName}/spaces/{spaceName}/pagesHTML/{pageName}) and produces
"text/html" content.
This link shows the class implementation as well as curl request and
server response.
https://docs.google.com/document/d/18xfQBSBxXT31a_QY5uBQ7c5MTbt9UEvk6zXO9F3…
I hope I understand the requirement this time.
I was also trying to use the same end point as PageResource class.
However, it does not work as the restlet complains "WARNING: There is
already a root resource class with path
/wikis/{wikiName}/spaces/{spaceName}/pages/{pageName}".
Therefore, adding a new end point seems like the way to go.
If this is case, how many resources are needed to provide HTML content?
page, space, links, etc.?
Another question would be how to design the new end points?
For now, "HTML" is appended after "pages" for PageHTMLResource,
which
gives /wikis/{wikiName}/spaces/{spaceName}/pagesHTML/{pageName}.
This is just a quick and dirty design.
Do you have better ideas?
Well, I think this solution is not good because if we want to add more
media types (e.g., PDF, etc.) we should introduce a lot of URIs.
Instead we can leverage the current ones and use HTTP metadata to
produce the right output.
To do this we have 2 ways:
1) Either we define a MessageBodyWriter
(
http://jsr311.java.net/nonav/javadoc/javax/ws/rs/ext/MessageBodyWriter.html)
that @Produces("text/html") for an org.xwiki.rest.model.jaxb.Page
object that is returned by PageResource.getPage() (i.e., the method
that is called when GET is called on the
/wikis/{wikiName}/spaces/{spaceName}/pages/{pageName} URI)
2) Or we enhance the PageResource class by providing a new method,
e.g., getPageHTML that @Produces("text/html") and returns a String
which is the actual rendered content.
@Produces is the annotation that enables content negotiation. If a
client requests a specific media type, the @Produces is used by the
framework to locate the entity that should provide the response.
The first option is better wrt modularity but it has a problem. The
org.xwiki.rest.model.jaxb.Page doesn't have any link to the original
XWiki Document from where it has been built, so we cannot directly
call getRenderedContent. A quick solution would be to re-get the
associated XWiki Document based on the information present in the
org.xwiki.rest.model.jaxb.Page object and call getRenderedContent(). A
bit ugly because this makes the work done in the getPage() method
useless.
The second option is straightforward, works fine and doesn't have the
drawbacks of the first but introduces a second way for adding media
format support. I mean this is perfectly legal in JAX-RS, it's just
that from an architectural point of view, it is nice to have media
type support using body writers because they are XWiki components and
they can be injected in the system without touching existing code
(giving more flexibility and better extensibility)
So how do we proceed?
To do 1) I think we should refactor a the whole system in order to
make original XWiki entities to be accessible from JAXB objects. Since
we are using a JAXB compiler to automatically generate these classes
from an XSD schema, I am not sure that we can tell the compiler to
"add an Object entity field to the generated classes" (have to check
if). If this is possible then we're done, otherwise we might need to
stop using the compiler and write explicitly the classes using JAXB
annotations for serializing only the relevant fields.
2) as I said is straightforward.
Since my idea was to give you some insights about how the REST API
works, I think you can implement 2) because 1) is too much (though, if
you feel comfortable you might try :)). This mail and your
implementation should provide you enough background to understand how
things work under the hood in case we'll need to patch some things
server side while working on XEclipse.
So try to go for 2). You can also have a look at the JAX-RS
specification that details all the concepts I've mentioned before and
that we use in the RESTful API backend.
Thanks,
Fabio
Best regards
Jun Han
On 05/18/2011 08:23 AM, Fabio Mancinelli wrote:
> Hi Jun
>
> On Wed, May 18, 2011 at 5:49 AM, Jun Han<jun.han37(a)gmail.com> wrote:
>> Hi Fabio and Thomas,
>>
>> Thanks a lot.
>>
>> I took some time to look at how to produce XML output in Xwiki REST API.
>>
>> The job of marshaling Java object to XML is done by
>> restlet.ext.JAXBProvider via Restlet 1.1.10.
>> |@Provider
>> @Consumes("application/xml")
>> @Produces("application/xml")
>> class JAXBProvider extends AbstractProvider|
>>
>> Similarly, our HTMLProvider can also be devised if we want to provide a
>> HTML output.
>> |@Provider
>> @Produces("text/html")
>> class HTMLProvider extends AbstractProvider|
>>
>> As discussed earlier, another issue is about html page's format and content.
>> An easy way would be to transform XML to html page via XSLT.
>> I also checked the current version of Restlet (2.0.7 stable). They added
>> Representation class in v2.0 and plan to add Representation
>> transformation (i.e., XML -> HTML) in version v2.2 via XSLT. see
>>
http://wiki.restlet.org/developers/175-restlet.html
>> Therefore, I think XSLT approach might work for plain html.
>>
>> Take a simple page as an example,
>>
>> |<?xml version="1.0" encoding="UTF-8"
standalone="yes"?>
>> <page xmlns="http://www.xwiki.org">
>> <title>New title</title>
>> <content>New content</content>
>> </page>|
>>
>> What would be the output of html page?
>>
>> |<html>
>> <H1>Page<H1>
>> <p>namespace:
http://www.xwiki.org</p>
>> <p>title: New title</p>
>> <p>content: New content</p>
>> </html>
>> |
>> Best regards
>> Jun Han
>>
> I think you misunderstood what is the purpose of this functionality...
> We don't want to render in HTML the XML produced by the standard REST
> response. We simply want to return the HTML that comes from the
> rendering of the page content.
>
> Basically, in its simplest form, this boils down to write a resource
> that returns what is generated by Document.getRenderedContent()
>
> As a side note keep in mind that we are using JAX-RS in top of
> Restlet, so when defining a resource you need to create a @Component
> Class that extends XWikiResource and also list it in the
> META-INF/components.txt
>
> You can have a look at
>
https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwi…
> and
https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwi…
> to see what I am talking about.
>
> Thanks,
> Fabio
>
>
>
>> On 5/17/2011 5:29 AM, Fabio Mancinelli wrote:
>>> Hi Jun
>>>
>>> On Tue, May 17, 2011 at 9:16 AM, Jun Han<jun.han37(a)gmail.com>
wrote:
>>>> Dear all,
>>>>
>>>> Regarding REST API for XWiki,
>>>> Source codes are in
>>>> xwiki-trunk/xwiki-platform/xwiki-platform-core/xwiki-platform-rest.
>>>> Test codes are in
>>>>
xwiki-trunk/xwiki-enterprise/xwiki-enterprise-test/xwiki-enterprise-test-rest.
>>>> I hope I am looking at the correct places.
>>>>
>>> Correct.
>>>
>>>> XWiki-5820 is related to adding an endpoint for providing a rendered
>>>> version of the page.
>>>> Does REST API need to invoke xwiki-rendering library in order to render
>>>> the html content?
>>>>
>>> There are several getRenderedContent() methods in the Document
>>> class... It should be enough to call them.
>>>
>>>> The current implementation will return various resources, (e.g., pages,
>>>> tags, attachments), and produce XML responses in most cases.
>>>> In XWiki-5820, only page resources will be rendered, right?
>>>>
>>>> A straight-forward way may be to add additional end point (getPage and
>>>> getPageInHTML), and they will be invoked according to different Accept
>>>> http headers.
>>>>
>>>> It would be great that an example can be given to show the expected
>>>> input and output.
>>>>
>>> Actually this is a good question...
>>>
>>> The original purpose of this resource was to provide a rendered
>>> version of a page (typically in HTML).
>>> Now, provided that we render in HTML, how this HTML should be returned?
>>>
>>> If we render with the complete skin we would end up with the same
>>> content already available from http://.../xwiki/bin/view/Space/Page
>>> So the idea was to return the "bare HTML" that could be emdedded
in
>>> other contexts.
>>>
>>> For the input we can consider Accept headers and media parameters
>>> (already handled by the backend)
>>>
>>> Thanks,
>>> Fabio
>>>
>>>> Best regards
>>>> Jun Han
>>>> _______________________________________________
>>>> devs mailing list
>>>> devs(a)xwiki.org
>>>>
http://lists.xwiki.org/mailman/listinfo/devs
>>>>
>>> _______________________________________________
>>> devs mailing list
>>> devs(a)xwiki.org
>>>
http://lists.xwiki.org/mailman/listinfo/devs
>> _______________________________________________
>> devs mailing list
>> devs(a)xwiki.org
>>
http://lists.xwiki.org/mailman/listinfo/devs
>>
> _______________________________________________
> devs mailing list
> devs(a)xwiki.org
>
http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________
devs mailing list
devs(a)xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________
devs mailing list
devs(a)xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________
devs mailing list
devs(a)xwiki.org