users@jax-rs-spec.java.net

[jax-rs-spec users] Re: [jsr344-experts mirror] JAX-RS MVC

From: Leonardo Uribe <lu4242_at_gmail.com>
Date: Fri, 30 May 2014 07:15:43 +0200

Hi

2014-05-30 2:10 GMT+02:00 Adrian Gonzalez <adr_gonzalez_at_yahoo.fr>:
> Hello,
> First thing, I'm sorry for this long post.
>
> Sections of this post :
> * MVC Objectives ?
> * MVC idea supporting option 4
> * My working notes
> === MVC Objectives ? ===
> I would like to know what are the objectives of the MVC functionality.
> To quote Leonardo Uribe :
> 1. Some people want to see JAX-RS on top and JSF as a template engine.
> 2. Some people want to see JSF on top with built-in action oriented features,
> but keeping its own component-oriented approach.
> 3. Some people want to see JSF with built-in REST features, replicating
> the same features as in JAX-RS, because after all that code doesn't have
> anything to do with JSF.
> Personally I would have expected to have an MVC action framework based on JAX-RS annotations with it's own template engine. Let's call it option 4 :
> 4. MVC action framework based on JAX-RS annotations with it's own template engine.
> I can see people (I've done all this) :
> * developing JSF applications
> * developing a mixed JSF / REST (JSON) application
> * developing REST (JSON) application with some js on the client side (i.e. angularjs...).
> * developing MVC / REST (JSON)

This is no different from the approach 1.

The really big problem is not how to write the controller, it is how to
plug the template engine with the controller.

If you take a look at the examples, in all of them you need to write
an url or something by hand to point the request to the controller
defined in JAX-RS. In JSF, the framework do that for you, you don't
want to get your hands dirty with that, it is just a waste of time. But
for users aiming to solve the problem using approach 1, this is
everything.

Let's start from the beginning. In a template engine for an action
framework you need.

1. Do some processing in the controller to invoke the template engine.
2. Inside the pages that are processed by the template engine, you need
a syntax that allow you to define URLs. (for forms, links, whatever)

JSF is a "page centric" framework. In other words, each page is a
controller. It is no strange that to define an action, in JSF you use
a component that is bound to the page (f:viewAction). In other words
JSF defines a well known algorithm and the uses just use the known
strategy.

In an action based framework, the user has to write the controller by
hand. The point is what do you need in JSF as a template engine, is
to do the binding with the controller, usually through an url.

And here is when things get interesting, because there is something out
there that do something similar to what we want and is Portlets. A
JSF portlet brigde provides a custom environment to execute the JSF
lifecycle, and using JSF pluggability it can override the urls generated
by JSF to include the portlet specific information, like some state keys
and so on.

To my eyes, you are doing just the same thing here. You define a front
controller no matter how, and then in some point you invoke JSF to
generate the HTML, and JSF does what it always does when a view is
built by first time, which is create the view, and render the view. The
state management code is only executed when there is a h:form inside
the page, so by practical effects, the JSF lifecycle just fits like a glove.
Does it have sense to take the template engine out of JSF? absolutely
no, it is a nonsense, because one way or another, the same steps
that JSF already does (create the view and render the view) should be
done for any template engine.

The trick is how to make JAX-RS to pass the necessary information
to JSF, so JSF can build the necessary URLs taking into account the
logic defined by JAX-RS.

> But I don't really see the need for MVC + JSF.

Unfortunately it is not that simple. Different users, different
perspectives, different solutions. That's why I started from that, and
this is something to keep in mind. For a JSF user perspective, an
MVC approach is one, no two or more steps back, because once
you go in there, you need to write a lot of code that JSF just does
easily, without pain. We are not here to discuss which one is best,
but to find how to create a sinergy between both frameworks that
coexists inside JEE.

regards,

Leonardo

> === MVC idea supporting option 4 ===
> After looking 2 hours at the following action frameworks : Playframework / Spring MVC with GSP / ASP.NET MVC 5, all of their latest template engines support templating (layout and reusable blocks) and provide for a shorter syntax (no xml based).
> Trying to imagine what JAX-RS MVC could be in order to support option 4 (please note : it's only some sketching with a lot of errors (don't know if this could even work in java) and areas for improvement - cannot do more with so little time ;( - I don't develop in java anymore for now) :
> Java Controller :
> @Path("/client")
> public class ClientController {
> @Inject
> ClientManager clientManager;
> // JAX-RS should be able to bind form data to complex data objects
> // must give us a BindResult to handle binding failure and redirect user to the input page if need be
> @POST
> @Path("/{id}")
> @Produces("application/json")
> public ActionResult edit(Client client, BindResult bindResult) {
> if (bindResult.isValid()) {
> return ok(list.redirect(clientManager.update(client));
> } else {
> return badRequest(show.render(client));
> }
> }
>
> @GET
> @Produces("application/json")
> @Path("{id}")
> public Client show(@PathParam("id") Long id) {
> public Client show(@PathVariable Long id) {
> return clientManager.findById(id);
> }
> ...
> }
> some notes on the controller :
> * list.redirect : list source code is automatically created when we create list page. This functionnality is from Playframework and enables on to have compile time checking.
> * BindResult : from SpringFramework. In this solution, JAX-RS is responsible for the conversion before calling the method.
> Another option would be for JAX-RS to send a Form object (i.e. Form<Client>) and for us to call explicitely the conversion inside the action (i.e. form.bind) - just like in playframework
> * JAX-RS must be able to convert HTTP POST parameters (multipart or not) to a java object
> edit view :
> @import static Helper.*;
> @views.template.Main.render(clientForm: Form<Client>) {
> @Helper.form(action -> routes.Clients.edit()) {
>
> @inputText(
> clientForm("lastName"),
> '_label -> "First name"
> )
>
> @inputText(
> clientForm("lastName"),
> '_label -> "Last name"
> )
>
> </fieldset>
> <div class="actions">
> <input type="submit" class="btn primary" value="Create">
> <a href="@routes.Application.index" class="btn">Cancel</a>
> </div>
> }
> }
> list view :
> @main(clients: List<Client>)
> <ul class="clients" id="clients">
> @for(client <- clients) {
> <li><a href="@routes.ClientController.show(client.id)">@client.lastName @client.firstName</a></li>
> }
> </ul>
> Notes about the view :
> * template inclusion mechanism (main references a page names 'main' - just like in Play).
> * reusable blocks (i.e. @inputText)
> * @ instead of XML to include dynamic code (less verbosity) - just like in GSP, ASP .NET MVC 5 (Razor) and Playframework
> * real HTML must be output like real HTML (no automatic translation div (class:'pull-right') to <div class="pull-right"> like in groovy - it appeared to me to be too much magic)
> * in edit view : the view parameter is Form<Client> and not Client. Form has all the necessary info for previous invalid values. Perhaps JAX-RS could automatically use Form<Client> instead of Client when we need it ?
> === My working notes ===
> If it can help someone...
> Really rough.
> Some notes on how I would implement a similar use case in Play, Spring MVC, dot Net.
> This won't compile (I've used a text editor to aggregate some samples around the web), there will be a lot of errors.
> === Spring MVC with GS ==
> @Controller
> @RequestMapping(value = "/exemple/clients")
> public class ClientController {
>
> @Inject
> private ClientManager clientManager;
>
> @RequestMapping(value = "/{id}", method = RequestMethod.GET)
> public String show(@PathVariable Long id, Model uiModel) {
> Client lClient = clientManager.findById(id);
> uiModel.addAttribute(lClient);
> uiModel.addAttribute("itemId", id);
> return "exemple/client/show";
> }
> @RequestMapping(method = RequestMethod.POST)
> public String create(@Valid Client client, BindingResult
> bindingResult,
> Model uiModel) {
> String inputView = "exemple/client/edit";
> if (bindingResult.hasErrors()) {
> return inputView;
> }
> client.setDateContact(new Date());
> try {
> clientManager.create(client);
> } catch (SomeBusinessException e) {
> bindingResult.reject("error.global", e.getMessage());
> return inputView;
> }
> uiModel.asMap().clear();
> return "redirect:/exemple/clients/" + client.getId();
> }
> @RequestMapping(params = "form", method = RequestMethod.GET)
> public String createForm(Model uiModel, SitePreference
> sitePreference) {
> uiModel.addAttribute(newClient());
> return "exemple/client/edit";
> }
>
> @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
> public String delete(@PathVariable Long id, Model uiModel,
> SitePreference sitePreference) {
> Client client = clientManager.findById(id);
> clientManager.delete(client);
> uiModel.asMap().clear();
> return "redirect:/exemple/clients" +
> (sitePreference.isMobile() ? "-mobile" : "");
> }
>
> @RequestMapping(method = RequestMethod.PUT)
> public String update( @Valid Client client, BindingResult
> bindingResult,Model uiModel) {
> String inputView = "exemple/client/edit";
> if (bindingResult.hasErrors()) {
> return inputView;
> }
> try {
> clientManager.update(client);
> } catch (MatriculeExistantException e) {
> bindingResult.reject("error.global", e.getMessage());
> return inputView;
> }
> uiModel.asMap().clear();
> return "redirect:/exemple/clients/" + client.getId();
> }
> @RequestMapping(value = "/{id}", params = "form", method =
> RequestMethod.GET)
> public String updateForm(@PathVariable Long id, Model uiModel) {
> show(id, uiModel);
> return "exemple/client/edit";
> }
> @RequestMapping(method = RequestMethod.GET)
> public String list(@Valid ClientCriteriaForm clientCriteriaForm,
> BindingResult aBindingResult,
> Model uiModel) {
> if (aBindingResult.hasErrors()) {
> return "exemple/client/list";
> }
> ...call clientManager...
> uiModel.addAttribute("clients", clients);
> return "exemple/client/list";
> }
> @RequestMapping(params = "list", method = RequestMethod.GET)
> public String listForm(ClientCriteriaForm clientCriteriaForm, Model
> uiModel) {
> List<Client> clients = new ArrayList<Client>();
> uiModel.addAttribute("clients", clients);
> return "exemple/client/list";
> }
>
> @RequestMapping(params="cancel")
> public String cancel() {
> return "redirect:/exemple/clients";
> }
> }
> [2] A REST backend controller with Spring MVC
> @Controller
> @RequestMapping(value = "/exemple/rest/clients")
> public class RestClientController {
> @Inject
> private ClientManager clientManager;
> @RequestMapping(method = RequestMethod.GET)
> @ResponseBody
> public Map<String, Object> list(@Valid ClientCriteriaForm
> clientCriteriaForm) {
> List<Client> clients = clientManager.findByName(
> clientCriteriaForm.getNom(),
> clientCriteriaForm.getPage()
> *
> clientCriteriaForm.getSize(),
> clientCriteriaForm.getSize() + 1);
> Map<String, Object> lResults = new HashMap<String, Object>();
> if (clients.size() > clientCriteriaForm.getSize()) {
> lResults.put("hasNextPage", true);
>
> lResults.put("page", clientCriteriaForm.getPage());
>
> clients.Remove(clientCriteriaForm.getSize().intValue());
> }
> lResults.put("clients", clients);
> return lResults;
> }
> @RequestMapping(value = "/{id}", method = RequestMethod.GET,
> produces="application/json")
> @ResponseBody
> public Client show(@PathVariable Long id) {
> return clientManager.findById(id);
> }
>
> @RequestMapping( method = RequestMethod.POST,
> produces="application/json")
> @ResponseBody
> public Client create(@RequestBody @Valid Client client) throws
> SomeBusinessException {
> return clientManager.create(client);
> }
>
> @RequestMapping(value = "/{id}", method = RequestMethod.DELETE,
> produces="application/json")
> @ResponseStatus(HttpStatus.NO_CONTENT)
> public void delete(@PathVariable Long id) {
> Client client = clientManager.findById(id);
> clientManager.delete(client);
> }
> @RequestMapping(method = RequestMethod.PUT,
> produces="application/json")
> @ResponseBody
> public Client update(@RequestBody @Valid Client client) throws
> SomeBusinessException {
> return clientManager.update(client);
> }
>
>
> @ExceptionHandler(RequestBodyNotValidException.class)
> @ResponseBody
> public Map<String,Object>
> handleException(RequestBodyNotValidException exception, HttpServletResponse
> response) throws IOException {
> return RestUtils.convertAndSetStatus(exception, response);
> }
>
> @ExceptionHandler(Exception.class)
> @ResponseBody
> public Map<String,Object> handleException(Exception exception,
> HttpServletResponse response) throws IOException {
> return RestUtils.convertAndSetStatus(aException, aResponse);
> }
> }
> Groovy template
> see http://spring.io/blog/2014/05/28/using-the-innovative-groovy-template-engine-in-spring-boot
> Groovy template features : layout + lambda + concise (no xml) + fragments
> layout 'layouts/main.tpl',
> pageTitle: 'Spring Boot - Groovy templates example with layout',
> mainBody: contents {
> ul {
> clients.each { client ->
> li {
> a(href:"/client/$client.id", "$client.lastName $client.firstName")
> }
> }
> }
> div {
> a(href:'/client/add', 'Add new client')
> }
> }
> }
> }
> see https://github.com/spring-projects/spring-boot/blob/master/spring-boot-samples/spring-boot-sample-web-groovy-templates/src/main/resources/templates/messages/form.tpl
> layout 'layout.tpl', title: 'Messages : Create',
> content: contents {
> div (class:'container') {
> form (id:'messageForm', action:'/', method:'post') {
> if (formErrors) {
> div(class:'alert alert-error') {
> formErrors.each { error ->
> p error.defaultMessage
> }
> }
> }
> div (class:'pull-right') {
> a (href:'/', 'Messages')
> }
> label (for:'lastName', 'Last Name')
> input (name:'lastName', type:'text', value:client.lastName?:'',
> class:fieldErrors?.lastName ? 'field-error' : 'none')
> label (for:'firstName', 'First Name')
> input (name:'firstName', type:'text', value:client.firstName?:'',
> class:fieldErrors?.firstName ? 'field-error' : 'none')
> div (class:'form-actions') {
> input (type:'submit', value:'Create')
> }
> }
> }
> }
> == Playframework ==
> === routes ===
> # Client
> GET /exemple/clients controllers.Clients.list()
> PUT /exemple/clients/:client controllers.Clients.update(client: Long)
> DELETE /exemple/clients/:client controllers.Clients.delete(client: Long)
> === Controller ===
> public class Clients extends Controller {
> public static Result list() {
> return ok(
> list.render(
> Client.findAll()
> )
> );
> }
>
> /**
> * Update a client
> */
> public static Result update(Long client) {
> ClientForm clientForm = form().bindFromRequest();
> if(clientForm.hasErrors()) {
> return badRequest(clientForm.render(clientForm));
> } else {
> Client.markAsDone(
> client,
> Boolean.valueOf(
> clientForm.get()
> )
> );
> return ok();
> }
>
> /**
> * Delete a client
> */
> public static Result delete(Long client) {
> Client.find.ref(client).delete();
> return ok();
> }
> }
> list.scala.html
> @main(clients: List[Client])
> <ul class="clients" id="clients">
> @for(client <- clients) {
> <li><a href="@routes.ClientController.show(client.id)">@client.lastName @client.firstName</a></li>
> }
> </ul>
> create page
> @main(clientForm: Form[Client])
> @import helper._
> @import helper.twitterBootstrap._
> @title = {
> Add a new client <small><a href="@routes.Clients.edit">Or edit an existing client</a></small>
> }
> @main(title, nav = "Client") {
>
> @if(clientForm.hasErrors) {
> <div class="alert-message error">
> <p><strong>Oops</strong> Please fix all errors</p>
> </div>
> }
>
> @helper.form(action = routes.Clients.submit, 'id -> "form") {
>
> <fieldset>
> <legend>General information</legend>
>
> @inputText(
> clientForm("lastName"),
> '_label -> "First name"
> )
>
> @inputText(
> clientForm("lastName"),
> '_label -> "Last name"
> )
>
> </fieldset>
> <div class="actions">
> <input type="submit" class="btn primary" value="Create">
> <a href="@routes.Application.index" class="btn">Cancel</a>
> </div>
> }
> }
> public class Clients extends Controller {
>
> /**
> * Defines a form wrapping the Client class.
> */
> final static Form<Client> contactForm = form(Client.class);
>
> /**
> * Display a blank form.
> */
> public static Result blank() {
> return ok(form.render(contactForm));
> }
>
> public static Result edit() {
> Client existingClient = new Client(
> "Fake", "Client", "Fake company",
> new Client.Information(
> "Personal", "fakecontact_at_gmail.com", "01.23.45.67.89", "98.76.54.32.10"
> ),
> new Client.Information(
> "Professional", "fakecontact_at_company.com", "01.23.45.67.89"
> ),
> new Client.Information(
> "Previous", "fakecontact_at_oldcompany.com"
> )
> );
> return ok(form.render(contactForm.fill(existingClient)));
> }
>
> /**
> * Handle the form submission.
> */
> public static Result submit() {
> Form<Client> filledForm = contactForm.bindFromRequest();
>
> if(filledForm.hasErrors()) {
> return badRequest(form.render(filledForm));
> } else {
> Client created = filledForm.get();
> return ok(summary.render(created));
> }
> }
> }
> == dot Net MVC 5 with Razor template engine ==
> from http://www.asp.net/mvc/tutorials/mvc-5/introduction/getting-started
> using System.Web;
> using System.Web.Mvc;
>
> namespace MvcMovie.Controllers
> {
> public class ClientsController : Controller
> {
> // GET: /Clients/
> public ActionResult Index()
> {
> return View(clientManager.findAll());
> }
> // POST: /Clients/Edit/5
> [HttpPost]
> [ValidateAntiForgeryToken]
> public ActionResult Edit([Bind(Include="ID,FirstName,LastName")] Client client)
> {
> if (ModelState.IsValid)
> {
> clientManager.update(client);
> return RedirectToAction("Index");
> }
> return View(client);
> }
> }
> }
> App_Start/RouteConfig.cs :
> public static void RegisterRoutes(RouteCollection routes)
> {
> routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
> routes.MapRoute(
> name: "Default",
> url: "{controller}/{action}/{id}",
> defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
> );
> routes.MapRoute(
> name: "Hello",
> url: "{controller}/{action}/{name}/{id}"
> );
> }
> === list.cshtml ===
> default layout is defined in Views\_ViewStart.cshtml.
> @model IEnumerable<Exemple.Models.Client>
> @{
> ViewBag.Title = "Client List";
> }
> <h2>Client List</h2>
> @foreach (var client in Model) {
> {
> <li>@Html.ActionLink(client.firstName + " " + client.lastName, "Edit", new { id=item.ID }) |</li>
> }
> <p>Hello from our View Template!</p>
> <ul class="clients" id="clients">
> @for(client <- clients) {
> <li><a href="@routes.ClientController.show(client.id)">@client.lastName @client.firstName</a></li>
> }
> </ul>
> }
> === edit.cshtml ===
> @model Exemple.Models.Client
> @{
> ViewBag.Title = "Edit";
> }
> <h2>Edit</h2>
> @using (Html.BeginForm())
> {
> @Html.AntiForgeryToken()
> <div class="form-horizontal">
> <h4>Client</h4>
> <hr />
> @Html.ValidationSummary(true)
> @Html.HiddenFor(model => model.ID)
> <div class="form-group">
> @Html.LabelFor(model => model.FirstName, new { @class = "control-label col-md-2" })
> <div class="col-md-10">
> @Html.EditorFor(model => model.FirstName)
> @Html.ValidationMessageFor(model => model.FirstName)
> </div>
> </div>
> <div class="form-group">
> @Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" })
> <div class="col-md-10">
> @Html.EditorFor(model => model.LastName)
> @Html.ValidationMessageFor(model => model.LastName)
> </div>
> </div>
> <div class="form-group">
> <div class="col-md-offset-2 col-md-10">
> <input type="submit" value="Save" class="btn btn-default" />
> </div>
> </div>
> }
> @section Scripts {
> @Scripts.Render("~/bundles/jqueryval")
> }
>
>
>
> ----- Mail original -----
> De : Frank Caputo <frank_at_frankcaputo.de>
> À : users_at_jax-rs-spec.java.net
> Cc :
> Envoyé le : Mardi 27 mai 2014 19h52
> Objet : [jax-rs-spec users] Re: [jsr344-experts mirror] JAX-RS MVC
>
> Hi,
>
> I’m Frank Caputo and happy to continue the discussion here.
>
> Ciao Frank
>
>
>
>
> Am 23.05.2014 um 17:27 schrieb Edward Burns <edward.burns_at_oracle.com>:
>
>>>>>>> On Fri, 23 May 2014 10:10:21 -0400, Santiago Pericas-Geertsen <Santiago.PericasGeertsen_at_oracle.com> said:
>>
>> SPG> I'm the spec lead for JAX-RS and Ed asked me to pop in here and
>> SPG> invite you over to the mailto:users_at_jax-rs-spec.java.net where we
>> SPG> are planning to have our discussions. I'd like to preserve the
>> SPG> momentum from the thread that was started by Arjan back in February
>> SPG> [2] and had discussions through until April [3]. Our plans for
>> SPG> JAX-RS MVC include using Facelets and JSP as well as support for
>> SPG> Flows, ViewScope and FlashScope. Ed will have more to say about the
>> SPG> JSF side of these things.
>>
>> Hi Santiago,
>>
>> Thanks for the invitation.
>>
>> This email is a call to action to those of us how contributed to the
>> discussion of MVC on users_at_javaserverfaces-spec-public list.
>> Specifically, I'm counting on Arjan Tijms, Adrian Gonzalez, Andy Bosch,
>> Kito Mann, Leonardo Uribe, Manfred Riem, Neil Griffin, and
>> Frank Caputo to strongly consider joining users_at_jax-rs-spec.java.net and
>> continuing the discussion there.
>>
>> Here is a brief summary the discussion that happened on
>> users_at_javaserverfaces-spec-public thus far, staring with Arjan's message
>> on Fri, 28 Feb 2014 23:14:52 +0100 [1] and completing with Leonardo's
>> last message on the thread at Tue, 8 Apr 2014 18:22:44 +0200 [2].
>>
>> Arjan pointed out the work Manfred did to build the action oriented
>> framework on top of the JSF lifecycle mechanism.
>>
>> Adrian Gonzalez wrote:
>>
>> AG> Both JAX-RS and JSF miss some features for a MVC framework. JSF
>> AG> misses (at least) the following stuff to support reasonably well the
>> AG> MVC scenario :
>>
>> AG> 1. it doesn't support for now HTTP REST usage : HTTP PUT, POST
>> AG> (without postback), DELETE, etc... This is a blocker.
>>
>> AG> 2. templating : plugging in a 3rd party templating engine easily
>> AG> should be supported in MVC.
>>
>> AG> This is not the case for a component and an action based
>> AG> framework. As I recall, Spring MVC has been built after
>> AG> JAX-RS. Spring MVC authors didn't used JAX-RS because it was too
>> AG> limiting for them . Perhaps someone should ask them why JAX-RS was
>> AG> too limiting in order to lift those limitations ?
>>
>> AG> As for PlayFramework, I didn't used it, but here are some goodies :
>>
>> AG> * code reloading - a must have !
>>
>> AG> * view are compiled so you can use them in the controllers (to
>> AG> populate the view and to navigate to them).
>>
>> AG> * view templates (and form helpers) are more succinct/understandable
>> AG> than the same in JSP / facelets.
>>
>> Andy Bosch wrote:
>>
>> AB> Of course I am in favour of enhancing JSF according to user
>> AB> feedback. But I am not sure whether it is a good idea to integrate
>> AB> too much into it.
>>
>> Ed Burns wrote:
>>
>> EB> I'd like to see us extract Facelets from JSF, make it a first class
>> EB> citizen of a JAX-RS MVC, *and* provide an Action Oriented
>> EB> lifecycle as an alternative to the standard JSF lifecycle.
>>
>> Andy Bosch replied:
>>
>> AB> In my personal opinion it sounds good. But I often hear complaints
>> AB> of people about the JSF lifecycle (mostly those people do not like
>> AB> JSF at all ;-) ). Some people just don't like a complex
>> AB> lifecycle. They prefer having a simple controller that is called
>> AB> during an action invocation.
>>
>> AB> So to sum up I would say we have to carefully think about how
>> AB> complex or easy such an lifecycle would become.
>>
>> Kito Mann asked:
>>
>> KM> Ed, what's your motivation for doing the JAX-RS route _and_ the JSF
>> KM> route? Support action-based scenarios within JSF apps, but provide
>> KM> JAX-RS for those who don't use JSF?
>>
>> Ed Burns replied:
>>
>> EB> Right, it's about making Facelets available outside of JSF because
>> EB> templating is useful on its own, even without the JSF lifecycle.
>>
>> Leonardo Uribe responded by asserting that the combination of Spring MVC
>> *and* JSF can be powerful, citing a blog entry and examples.
>>
>> LU> In other words, what the user want is in this case is:
>>
>> LU> - Take advantage of JSF 2 template system (facelets) and component
>> LU> model.
>>
>> LU> - Don't use the JSF lifecycle and use something else that fits.
>>
>> Leonardo further asserts it is nonsense to take Facelets out of JSF:
>>
>> LU> If you take facelets out of JSF, what you are really doing is get
>> LU> rid of JSF lifecycle, but besides that, you are not doing anything
>> LU> else.
>>
>> Frank agreed with Leonardo's assertion.
>>
>> Though I agree with all of Leonardo's other points in his response, I
>> disagree with this one. You are getting all the page templating from
>> the <ui:> tag library which doesn't exist in any other server side java
>> solution aside from Struts Tiles.
>>
>> Leonardo goes on to sketch a solution to allow JSF to plug more cleanly
>> into Spring MVC, providing specific details about how the JSF lifecycle
>> can be improved in the process.
>>
>> Taking another perspective on the matter, Leonardo outlines the
>> data-only JSF lifecycle idea we've been kicking around for years and
>> discussed at Javaland. The basic idea is to have a way for a JSF ajax
>> request to have access to all JSF features except those relating
>> directly to a view. This would include FacesContext, Flash, Flow, etc
>> but would *NOT* include anything to do with a specific view. This is
>> captured in JAVASERVERFACES_SPEC_PUBLIC-1261 and I want to pursue this
>> in JSF 2.3.
>>
>> The discussion continued after Javaland. Frank sketched out how you
>> could forward from JAX-RS to the FacesServlet today, even without Jersey
>> MVC. Leonardo replied,
>>
>> LU> The only flaw I can see is using ExternalContext there is no way to
>> LU> know when the request is a GET, a POST and so on, which is important
>> LU> at the time to define the endpoint.
>>
>> LU> Now, it could be useful to have a "action source framework"
>> LU> component. That means, an special component that work in a way that
>> LU> everything inside it works just like any action source framework,
>> LU> but everything outside the box still work under JSF rules.
>>
>> LU> So, other people has already thought the same as we are trying to do
>> LU> and have been doing (JSF 2.2 viewAction and JSF 2.0 viewParam),
>> LU> there are some cases where an action oriented approach with a
>> LU> component oriented framework can coexist. In that sense, the ability
>> LU> to define REST services inside CDI managed beans through Faces
>> LU> Servlet seems to be important. For what? It is not hard to find
>> LU> cases. For example, to expose information to some other app or
>> LU> component or service that consume it as a REST service. If you have
>> LU> a JSF webapp nothing can be simpler as define the method right on
>> LU> the managed bean.
>>
>> Leonardo followed up on this with some very detailed suggestions.
>> Leonardo, please join the discussion over on
>> users_at_jax-rs-spec.java.net. He ends by summarizing:
>>
>> LU> For some users who currently uses JSF at a daily basis, this problem
>> LU> is not something important, because there is a workaround and this
>> LU> usually suppose a small part of the whole application, so you don't
>> LU> really spent a lot of time solving it. It is not really hard to
>> LU> write a couple of servlets that can do the job in these cases.
>>
>> LU> But for some other users that are not into JSF, this is
>> LU> important. The reason is JSF Template engine (Facelets) solves a lot
>> LU> of problems for them. These guys usually are making applications
>> LU> with another architectural paradigm, different to the one proposed
>> LU> initially by JSF.
>>
>> Let's get moving!
>>
>> Ed
>>
>> [1] https://java.net/projects/javaserverfaces-spec-public/lists/users/archive/2014-02/message/7
>>
>> [2] https://java.net/projects/javaserverfaces-spec-public/lists/users/archive/2014-04/message/6
>>
>>
>