Here comes a preliminary result of some research:
Feel free to fork it and add ideas/thoughts => https://gist.github.com/8d074110af839a1190b7
Follows inline for discussion
-- cut here --
## Desirable features to have on a mvc framework
When we talk about a mvc framework, we're talking about getting out of the way of the web developer. Sometimes getting out of the way means offering the least resistance path, and that's what I'm talking about here.
### Having the routes on a central place
(instead of near the controllers)
When java finally got Annotations, they rushed to have the configuration closer to the code. Even if we _old_ java devs find it nice, I've heard lots of complaints when I was giving struts 2 classes that the struts 1 approach - a central xml gluing actions and url endpoints - seemed way easier, **even if it were making you switch contexts**.
This never clicked to me until I've started to work full time with Ruby on Rails.
Rails has a `config/routes.rb` and has a concise shorthand for specifying routes
# this is plain ruby code
resources :photos
Play has a `conf/routes` and it's a little more verbose
GET /tasks controllers.Application.tasks()
POST /tasks controllers.Application.newTask()
POST /tasks/:id/delete controllers.Application.deleteTask(id: Long)
Proposal: We could have something code centric (no metadata, plain java code)
Routes routes = Routes.build(
from("/tasks/:id").on(GET).to(TaskController.class).find(":id"),
from("/tasks").on(POST).to(TaskController.class).newTask()
);
The idea is that we could have something that extracts a `Routes` instance from JAX-RS annotations too, but keep in mind that this is a bit slower than just running code straight.
Having programmatic routes mean this is refactor-friendly and can use IDE help.
### Having ActiveRecord-like Entity interaction
Rails brought again the ActiveRecord idea. Like it or not, it **can** yield nice readable code. Play uses Hibernate unde the hood for it, so it's mostly plain JPA:
// All entities inherit from Model
@Entity
public class Car extends Model {
…
}
And the usage
List<Car> allTheCars = Car.all();
Car car = Car.find(1L);
car.delete();
new Car("corvette").save();
How cool is for a newcomer to just not have to learn about DAO/Repository stuff? Like it or not, it's one less object to deal with.
### Having a CLI REPL
Needless to say, one of the most amazing things for exploring an rails application codebase is the Console
$ rails console
> Car.where(:age > 10) # oversimplifying
=> [Car, Car, Car, Car]
Having support for something like this (glorified beanshell?) would be very useful.
**Does forge fits the bill?**
### Schema evolution
WIP - working on an internal DSL for it
### Development mode & Deployment
#### Environments
This is another feature that shines on rails - you have a consistent environment setup from the ground up.
$ rails console -e test
I still remember my days developing apps with spring and having `-Dcom.mycompany.application.env=PROD` and two sets of XML for the different environments.
#### Fast turnaround
Play's approach relies on having lots of static code, without a container + taking advantage of [sbt](https://github.com/harrah/xsbt/wiki) auto reloading support.
We want Object Oriented programming, and CDI is an important part of our model. The problem is that we need very aggressive times for container bootstrap/startup to even compete with the **static-code-party**.
With regard to code reloading, we can use some techniques for fast class reloading, or just make the entire container reboot in less than one second.
### Packaging
Play's approach on having a zip package (91MB) with everything baked in is interesting, and we can achieve a self-contained development package similar to it, without needing the AS7 100MB+. We could use weld-embedded during development as a default, and have it deploy to AS7 for production use.
Rails' approach comprises of rubygems, which needs a ruby environment installed.
## Rails' Critique
1. Dynamic language
1. Drama factor (ask any rubyst)
1. Full stack
1. Slow (but normally this is not your bottleneck)
### Play's Critique
1. Everything is static
1. ZOMG Everything is static
1. Functional Programming appeal != everything static FFS
1. Load-Time Bytecode Weaving (hooray for the exception thrown at line 330 of a 15-line class).
1. Servlet API is so amazing that Ruby devs wanted to implement it to have async streaming - so no reason to skip it.
1. Schema evolution with raw SQL
-- qmx
Sent from my iPhone
Proposal: We could have something code centric (no metadata, plain java code)
Routes routes = Routes.build(
from("/tasks/:id").on(GET).to(TaskController.class).find(":id"),
from("/tasks").on(POST).to(TaskController.class).newTask()
);
The idea is that we could have something that extracts a `Routes` instance from JAX-RS annotations too, but keep in mind that this is a bit slower than just running code straight.
> * centralized routes when talking to Rails/Grails/Play folks that is one of their favorite features.
> - Would the Java-based descriptor still be hot deployable? Hot deployment is critical IMO.
of course it is
> - But the proposed Java-based descriptor is a fair bit harder to read vs Play/Rails
yeah, but it's a tradeoff between ctrl+space friendliness :P
> - Plus, I would like to see how this concept can be blended with annotated JAX-RS which are our endpoints for HTML5 clients (POH5) today.
> - and...what if we could provide a centralized view (shell command) of all the routes scattered around as annotations on the various classes? This might give you the easier maintenance point of annotations but the single view point of a routes.rb?
yeah, having something like `rake routes` on rails would help, but my general feeling is that in a huge project things tend to get lost (200+ controllers)
> Good stuff, especially about centralized dispatch, which is one of my pet peeves. I'll add some more comments over the weekend, as there are some other things that I think we need - eg pluggable views and such.
The controllers can just dispatch to the views, in the traditional mvc fashion - we can provide and aggregate any view handler we want (haml support == jar w/ servlet 3.0 fragment or annotations)
Do you have other idea for pluggable views? please clarify if you think I didn't understood ;)
Sent from my iPad
> No, I just think that the choice of a view technology is critical, even the ability of combining multiple different view types in the same application.
>
IMO we should let Servlet api do it's best and just make a plain dispatch :P
>
>
> On Mar 30, 9:34 pm, Douglas Campos <q...@qmx.me> wrote:
>> On Mar 30, 2012, at 10:30 PM, Marius Bogoevici wrote:
>>
>>> No, I just think that the choice of a view technology is critical, even the ability of combining multiple different view types in the same application.
>>
>> IMO we should let Servlet api do it's best and just make a plain dispatch :P
>
> That would work for JSP, would be a bit iffy for JSF,
Although I like to idea of being completely view layer agnostic I do think we'll have to draw some limits even if just initially. I.e we can't jump through hoops for jsf - jsf has jsf for that :-)
> but what about
> 'pure' templating frameworks? Or you're suggesting to defer to a
> servlet in each and every case?
Once you start talking about templating you go from a view-dispatcher controller to very client impl specific.
We want to take advantage of client side templating and explore that first.
This is an example of getting out of the way of the client developer. It also makes hybrid mobile app support MUCH easier as whole parts of the client are self contained and needing little from the server.
>
> On Mar 31, 2012, at 12:26 AM, Marius Bogoevici <marius.b...@gmail.com> wrote:
>
>>
>>
>> On Mar 30, 9:34 pm, Douglas Campos <q...@qmx.me> wrote:
>>> On Mar 30, 2012, at 10:30 PM, Marius Bogoevici wrote:
>>>
>>>> No, I just think that the choice of a view technology is critical, even the ability of combining multiple different view types in the same application.
>>>
>>> IMO we should let Servlet api do it's best and just make a plain dispatch :P
>>
>> That would work for JSP, would be a bit iffy for JSF,
I'm thinking with my action-based hat - so no expectancy of having
>
> Although I like to idea of being completely view layer agnostic I do think we'll have to draw some limits even if just initially. I.e we can't jump through hoops for jsf - jsf has jsf for that :-)
>
>> but what about
>> 'pure' templating frameworks? Or you're suggesting to defer to a
>> servlet in each and every case?
>
> Once you start talking about templating you go from a view-dispatcher controller to very client impl specific.
>
> We want to take advantage of client side templating and explore that first.
The best part of client side templates is that we just return JSON from rest endpoints - I really don't want any server side support beyond rendering the landing page for the RIA
>
> This is an example of getting out of the way of the client developer. It also makes hybrid mobile app support MUCH easier as whole parts of the client are self contained and needing little from the server.
>
>>
>> Not sure what you mean by 'servlet api doing its best' here. My
>> understanding is that you're suggesting to use different url schemes
>> to differentiate between the different types of views, but it seems to
>> me that this introduces some tight coupling between the controller and
>> the view layer.
We can have view resolvers (via CDI)
Sent from my iPad
On 2012-03-31, at 8:32, Douglas Campos <q...@qmx.me> wrote:
>
> On Mar 31, 2012, at 8:42 AM, Jay Balunas wrote:
>
>>
>> On Mar 31, 2012, at 12:26 AM, Marius Bogoevici <marius.b...@gmail.com> wrote:
>>
>>>
>>>
>>> On Mar 30, 9:34 pm, Douglas Campos <q...@qmx.me> wrote:
>>>> On Mar 30, 2012, at 10:30 PM, Marius Bogoevici wrote:
>>>>
>>>>> No, I just think that the choice of a view technology is critical, even the ability of combining multiple different view types in the same application.
>>>>
>>>> IMO we should let Servlet api do it's best and just make a plain dispatch :P
>>>
>>> That would work for JSP, would be a bit iffy for JSF,
> I'm thinking with my action-based hat - so no expectancy of having
>
>>
>> Although I like to idea of being completely view layer agnostic I do think we'll have to draw some limits even if just initially. I.e we can't jump through hoops for jsf - jsf has jsf for that :-)
I agree, but I tend to put down the cards early, since I am not fond of surprises :)
View agnosticism would come by returning logical handles which resolve to view implementations. My point was that dispatching as implementation works well for JSP, and no, I dont think we want to go the spring faces route either.
>>
>>> but what about
>>> 'pure' templating frameworks? Or you're suggesting to defer to a
>>> servlet in each and every case?
>>
>> Once you start talking about templating you go from a view-dispatcher controller to very client impl specific.
>>
>> We want to take advantage of client side templating and explore that first.
Yes, this is to be expected from single-page apps I guess.
> The best part of client side templates is that we just return JSON from rest endpoints - I really don't want any server side support beyond rendering the landing page for the RIA
>
So as a reminder, mobile development is not the only driver for this. The other cases, which involve server side MVC need more consideration for server side templating.
Anyway, the discussion started by proposing a servlet based mechanism for view rendering, I don't think it fits well beyond JSP and JSF.
>>
>> This is an example of getting out of the way of the client developer. It also makes hybrid mobile app support MUCH easier as whole parts of the client are self contained and needing little from the server.
+1
>>
>>>
>>> Not sure what you mean by 'servlet api doing its best' here. My
>>> understanding is that you're suggesting to use different url schemes
>>> to differentiate between the different types of views, but it seems to
>>> me that this introduces some tight coupling between the controller and
>>> the view layer.
> We can have view resolvers (via CDI)
Yes, they ought to be first class citizens.
Although I like to idea of being completely view layer agnostic I do think we'll have to draw some limits even if just initially. I.e we can't jump through hoops for jsf - jsf has jsf for that :-)
>
> Although I like to idea of being completely view layer agnostic I do think we'll have to draw some limits even if just initially. I.e we can't jump through hoops for jsf - jsf has jsf for that :-)
>
> I don't think we need to jump through any hoops for this, JSF is extremely simple to use as a View layer, particularly if you are using CDI, which I believe we are :)
>
> PS. Where is the demo MVC that someone wrote previously? Is it douglasses, here? https://github.com/aerogear/aerogear-controller
>
> I don't see any real code in the demo? Should I instead be looking at the impl somewhere?
Nah, it's a very thin layer over resteasy to dispatch rendering to servlet container (return a View instance)
it exposes the "model" object to the view as request attributes, with a smart naming policy (taken from VRaptor 3) Message => ${message} List<Message> => ${messageList}
This discussion needs, IMO to be split in 3 parts:
a) controller mapping
b) persistence
c) CLI support
A couple of thoughts on the latter two items:
b) deals with ActiveRecord and such - while I agree that it can be a
valuable component to a MVC solution (especially when RAD comes into
play), I think it needs to be discussed separately from MVC proper -
while ActiveRecord it is a staple for Rails, it is still a controversial
pattern in the Java EE world, and it's orthogonal to the topic: a proper
MVC solution should work equally well with DAOs and direct JPA. I
believe that the a separate discussion should focus on this.
c) I believe that the right place to provide CLI support for this is Forge.
Regarding a), which is the most MVC-centric aspect of the discussion, I
believe that we need to support both centralized and decentralized
routing - the latter is fairly easy to implement as a JAX-RS extension
(as Douglas' prototype is proving), the former is nice to have but needs
a distinct mapping mechanism AFAICT (e.g. something based on Lincoln's
rewrite). Using JAX-RS as an underlying mechanism has the advantage of
automatic data binding, etc - what Douglas has can be made JAX-RS
implementation agnostic through the use of Solder.
Missing ideas (goals):
a) Views should be logical handles - a separate view resolution layer
should delegate to the appropriate implementation - thus we can have
multiple types of views in the same application - we discussed this
somewhere else in the thread, but I am adding this for closure;
b) We should support automatic view delegation - i.e. target views
should be inferrable from the URL - .e.g. the logical view of GET
/members can be automatically 'members' and so on).
c) We should specify an error handling mechanism - e.g. what
views/actions can the framework delegate - again, this is something that
can be built on top of JAX-RS' exception handling I believe.
> �
> }
>
> And the usage
>
> List<Car> allTheCars = Car.all();
>
> Car car = Car.find(1L);
> car.delete();
>
> new Car("corvette").save();
>
>
> How cool is for a newcomer to just not have to learn about DAO/Repository stuff? Like it or not, it's one less object to deal with.
>
> ### Having a CLI REPL
>
> Needless to say, one of the most amazing things for exploring an rails application codebase is the Console
>
> $ rails console
> > Car.where(:age> 10) # oversimplifying
> => [Car, Car, Car, Car]
>
> Having support for something like this (glorified beanshell?) would be very useful.
>
> **Does forge fits the bill?**
>
> ### Schema evolution
>
> WIP - working on an internal DSL for it
>
> ### Development mode& Deployment
> b) deals with ActiveRecord and such - while I agree that it can be a valuable component to a MVC solution (especially when RAD comes into play), I think it needs to be discussed separately from MVC proper - while ActiveRecord it is a staple for Rails, it is still a controversial pattern in the Java EE world, and it's orthogonal to the topic: a proper MVC solution should work equally well with DAOs and direct JPA. I believe that the a separate discussion should focus on this.
We did some foray into that with Seam Entity framework but AFAIK it never really got popular. Am I right?
With EntityHome? IIRC that was not exactly the same as adding
EntityManager methods on the model classes directly. It feels just
right being able to call .create(), .save() and .delete() on entities.
The extra ModelClass.find() and other methods are equally nice.
--
Stéphane Épardaud
On 2 avr. 2012, at 14:21, burrs...@gmail.com wrote:
> While I agree with Marius that the "data layer" is orthogonal to the MVC focus of this thread, I would like to explore how we would achieve more "Rails-like" behaviors on top of typical JPA-based entities, not just CRUD but also dynamic finders.
It's not too hard
1. Make all your entities extend a Entity class which contains the following methods persist(), update(), delete(), findBy(String pseudoQueryByMethodName)
2. Abandon every hope of using your Entities objects remotely
3. Abandon every hope of detached objects
4. pray that no getter calls the Entity methods, that would be fun otherwise :)
About 2. and 3., it works nice for applications where you reload the whole dataset from the database at each interaction.
Sent from my iPad
On 2012-03-31, at 8:32, Douglas Campos <q...@qmx.me> wrote:
>
> On Mar 31, 2012, at 8:42 AM, Jay Balunas wrote:
>
>>
>> On Mar 31, 2012, at 12:26 AM, Marius Bogoevici <marius.b...@gmail.com> wrote:
>>
>>>
>>>
>>> On Mar 30, 9:34 pm, Douglas Campos <q...@qmx.me> wrote:
>>>> On Mar 30, 2012, at 10:30 PM, Marius Bogoevici wrote:
>>>>
>>>>> No, I just think that the choice of a view technology is critical, even the ability of combining multiple different view types in the same application.
>>>>
>>>> IMO we should let Servlet api do it's best and just make a plain dispatch :P
>>>
>>> That would work for JSP, would be a bit iffy for JSF,
> I'm thinking with my action-based hat - so no expectancy of having
>
>>
>> Although I like to idea of being completely view layer agnostic I do think we'll have to draw some limits even if just initially. I.e we can't jump through hoops for jsf - jsf has jsf for that :-)I agree, but I tend to put down the cards early, since I am not fond of surprises :)
View agnosticism would come by returning logical handles which resolve to view implementations. My point was that dispatching as implementation works well for JSP, and no, I dont think we want to go the spring faces route either.
>>
>>> but what about
>>> 'pure' templating frameworks? Or you're suggesting to defer to a
>>> servlet in each and every case?
>>
>> Once you start talking about templating you go from a view-dispatcher controller to very client impl specific.>>
>> We want to take advantage of client side templating and explore that first.Yes, this is to be expected from single-page apps I guess.
> The best part of client side templates is that we just return JSON from rest endpoints - I really don't want any server side support beyond rendering the landing page for the RIA
>So as a reminder, mobile development is not the only driver for this. The other cases, which involve server side MVC need more consideration for server side templating.
Anyway, the discussion started by proposing a servlet based mechanism for view rendering, I don't think it fits well beyond JSP and JSF.
Although I like to idea of being completely view layer agnostic I do think we'll have to draw some limits even if just initially. I.e we can't jump through hoops for jsf - jsf has jsf for that :-)
I don't think we need to jump through any hoops for this, JSF is extremely simple to use as a View layer, particularly if you are using CDI, which I believe we are :)
PS. Where is the demo MVC that someone wrote previously? Is it douglasses, here? https://github.com/aerogear/aerogear-controller
I don't see any real code in the demo? Should I instead be looking at the impl somewhere?
@Controller public class HelloWorldController { @RequestMapping("/helloWorld") public String helloWorld(Model model) { model.addAttribute("message", "Hello World!"); return "helloWorld"; // but you could also return a View here, or a navigation case. } }
@Routes // can have as many or as few of these as you like
public interface MyAppRoutes {
@AdminRequired
@Path("/user/create")
@If("#{userAgent == mobile}")
@Controller(MyController.class)
void createUser(@QueryParam("type") Type type);
}
Conversion:
It usually helps to be able to marshal or convert data into the proper type - this is a reason to use JAX-RS (due to extendable marshalling system,) but we may need to provide some utilities to make registering custom converters (for non automatic types.) It's also super easy to do with a routing API like Rewrite:
This example demonstrates actually a number of the principles we are looking for here:
.when(Method.isGet().and(Path.matches("/store/product/{pid}").where("pid").constrainedBy(new IntegerConstraint()).bindsTo(El.property("controller.product").convertedBy(ProductConverter.class).validatedBy(ProductValidator.class))))
.perform(Invoke.typesafe(Controller.class).buyItem());
You might say that this is verbose, but I would also argue that this is explicit and provides a great deal of control. It's a tradeoff between this, annotations, and doing everything by hand in the controller IMO.
However, when it comes to navigation, there are reasons to, again, use a custom routing framework instead of pure JAX-RS. Routes should know how to "reverse"-navigate, generate redirects, and can enforce type-safe navigation parameters. This framework can be transparent (using existing metadata to generate routes, perhaps through a Mockito style API:
return Navigate.to(MyController.class).viewUser("blah");
return "/user/create?type=blah";
throw Navigation.redirect(MyController.class).viewUser("blah");
throw Navigation.redirect("/user/create?type=blah"); // implements Throwable
<faces-config> ........ RUN!
So, my hands are tired, and this is already a lot to swallow. I'll wrap it up with a summary of how I think Rewrite plays in here.
Conclusion:
First, unless we can solve the type-safe method invocation configuration problem, or decide to use an Interface on controllers, we are going to have difficulty using either a text-based configuration for routes, or a Java API-based configuration like Rewrite.
However, we need to think about the practical cases here. We want this framework to be very productive from the start, for developing new apps, but we also absolutely NEED it to play well with existing applications, and be able to fit into existing ecosystems. This is where we are going to want a Routing API (as opposed to @Annotations) the most. It's much more difficult to perform non-invasive integrations into an application when you need to change application code in order to do it. This is the strongest case I can make for Rewrite and the Routing API at this time, but I think it is a very strong argument. But in a pure sense.
It comes down to prototyping a bunch of these different styles and seeing which ones work best together. I think we really need to do some technical research and rigor here in order to get due diligence for any solution. So on that note, please converse. I'm going to start writing some code now.
~Lincoln
…
This being said, TypeSafe method invocation is only a hangup if we want it. Otherwise, half of what I stated as problems can be removed. Fluent API can simply be a way of removing coupling of the URL, and that's a benefit I don't think I sold enough. Controllers can still be responsible for pulling out and validating their own parameters, in which case, again, typesafe config doesn't really matter.
~Lincoln
On Mon, Apr 2, 2012 at 12:54 PM, Lincoln Baxter, III <lincol...@gmail.com> wrote:
So I'm going to focus solely on the MVC for right now, since that's the part we need to address first (though I agree we need to think about tooling and data productivity along the way.) Also, I think we may want to start moving this content to a wiki - email is a bad format for this. What do you guys think?
There are 6 primary concerns that I can think of in any MVC or web-framework. Each is enough for its own discussion, but obviously many are related.:
First, I'm going to say that I think most of our work is already done - we just need to put some nice design patterns and JBoss-style APIs on top, and if you want to hear about that -- then skip to the end.
- Routing
- Rendering
- Validation
- Conversion
- Security
- Navigation
The MVC Prototype
We should probably consider the type of programming model that we want for the MVC. Right now the prototype a mix of two models that I can tell.
I should mention that one of the most powerful abstractions that I've seen in MVCs is separating the Controller from the URL, possibly because I am obsessed with that concept in general. So while we can use JAX-RS for this purpose, it would make de-coupled routing much more difficult. You might argue that it's not important for simplicity's sake, and you might be right.
- We have an annotation-based config for JAX-RS that's serving as the controller and the Routing - this is somewhat convenient. In order to get this to work, we have to do some fun customization of the Application class in order to register different View Renderers. This could probably be hidden away in the MVC web-fragment.xml, but it would bean losing some flexibility in the user's app (choice of MVC root URL, for instance, also the ability to swap controllers at runtime based on request attributes (mobile/etc))
Conversely, we solve at least the first part of that, using an abstract (not easy to conflict or discover) Servlet mapping to the MVC root-controller, then route requests to that using our Routing framework. Or we can just make it the responsibility of the developer to add this entry to their web.xml, then they have control.
Comment: You can specify multiple JAX-RS Applications, so this would not conflict with user's existing endpoints.
- We have tightly coupled the Controller to the URL endpoint. This is a problem with using JAX-RS directly to map the controller class, instead of delegating through another abstraction (which could certainly be done.)
Routing:
�
Spring MVC for instance, has done something similar to what Douglas prototyped:
@Controller public class HelloWorldController { @RequestMapping("/helloWorld") public String helloWorld(Model model) { model.addAttribute("message", "Hello World!"); return "helloWorld"; // but you could also return a View here, or a navigation case. } }
Notice that they are not using JAX-RS here, and there is just one big reason I can figure on that - because JAX-RS does not yet support validation (It will in 2.0: http://java.net/projects/jax-rs-spec/pages/Validation). JAX-RS 2.0 was even thinking about including an MVC feature, which I think got squashed because of scope creep (a good thing IMO.) However, Validation is something that we can address and add via a few techniques (see Validation section.)
Otherwise, I believe that JAX-RS is a very good fit for us, and we need not re-invent the wheel completely. I think that folks will actually appreciate the familiar programming model.
However, this makes it more difficult to apply a centralized routing strategy for those people that like to see everything in one place. Centralized routing means that we need to do more work. Not much more, and I think that we may still want to support this out of box because there ARE a lot of people who prefer this. It should be easy to do both, however.
Again, we need some supporting classes, but we have several approaches, douglas listed several more in his document ( https://gist.github.com/8d074110af839a1190b7 ), but there are a few more I'd like to consider.
- Annotation based - This ties in well with Navigation # 1, because you can simply use Reflection on the interface in your API, and the framework will know what to do (you can even pass some parameters.)
- Downside: Controller probably needs to implement an interface in order to work, otherwise you don't know which method to call
- Downside: Complicated to extend to handle additional conditions, difficult to add conditional routing
@Routes // can have as many or as few of these as you like
public interface MyAppRoutes {
� @AdminRequired
� @Path("/user/create")
� @If("#{userAgent == mobile}")
� @Controller(MyController.class)
� void createUser(@QueryParam("type") Type type);
}
�
- API based (Rewrite)
When you want to start routing based on certain conditions without worrying about cluttering your Routing framework API, while still leaving yourself open to extension to other view frameworks, then this is a good match. Rewrite or a fluent Java API can handle both this scenario, and also scenario #1 - creating a new route, but in terms of creating a typesafe navigation API, option #1 is going to make things easier.
.defineRoute("/user/create")
.if("#{userAgent == mobile}")
.securedBy(ADMIN)
.to(MyController.class)
- � .withParam("type", MyConverter.class, MyValidator.class)
� .withParam("p2", MyConverter2.class, MyValidator2.class);�
// Concern: How do we specify method parameter, if at all? Ordered method arguments? Seems ugly, can this be improved? If Java can do it, Rewrite can do it. We are actually discussing this at 2pm today in our development meeting.
or...
.to("/existing/route") // ahh, much better
I'm having a hard time seeing how this would replace actually putting metadata / annotations on the class without a very verbose API, or requiring ordering of method arguments. But it's certainly something that needs to be available so that folks can integrate the MVC with their existing applications. It's my opinion that this fact alone is reason enough to include a Routing API.
Rendering:
This is really pretty simple. We have a ViewMapper interface that can be registered to handle different types of view results, or we can bypass this entirely using the Routing framework (if the view tech already has its own URL or invocation strategy.) But that's up to the developer.
- Templates and non-routed APIs - typically things like Velocity, Freemarker, or Seam Render. They have no bindings to a URL, so it's easy to provide a ViewMapper to take a Model result, and map it into a template.
- Existing frameworks with Routes - more difficult to integrate because you may be dealing with stateful situations, for instance - JSF - You could argue about the benefit of putting a front-controller in front of JSF because the view "drives the entire lifecycle," but it's also possible to use a controller to populate your beans, then use the EL bindings in the view to do simple rendering and composite templating - this is typically the pattern I use in JSF that works the best.
Validation:
There are a couple approaches we can use here:
- CDI Interceptor: I believe that the CDI programming model (interceptors) will actually be extremely useful here, and we can even use the same design that we just put into the DeltaSpike Security Module. Easy.
- Rewrite annotation handlers: Using Rewrite, we can actually detect when users have added additional annotations to their classes, and build a URL-based rule to perform validations directly. Not difficult either.
Conversion:
It usually helps to be able to marshal or convert data into the proper type - this is a reason to use JAX-RS (due to extendable marshalling system,) but we may need to provide some utilities to make registering custom converters (for non automatic types.) It's also super easy to do with a routing API like Rewrite:
This example demonstrates actually a number of the principles we are looking for here:����
���������������.when(Method.isGet()������������������������.and(Path.matches("/store/product/{pid}")���������������������������������.where("pid").constrainedBy(new IntegerConstraint())���������������������������������.bindsTo(El.property("controller.product").convertedBy(ProductConverter.class)������������������������������������������.validatedBy(ProductValidator.class))))
�������������� .perform(Invoke.typesafe(Controller.class).buyItem());
Feel free to fork it and add ideas/thoughts => �https://gist.github.com/8d074110af839a1190b7
Follows inline for discussion
-- cut here --
## Desirable features to have on a mvc framework
When we talk about a mvc framework, we're talking about getting out of the way of the web developer. Sometimes getting out of the way means offering the least resistance path, and that's what I'm talking about here.
### Having the routes on a central place
(instead of near the controllers)
When java finally got Annotations, they rushed to have the configuration closer to the code. Even if we _old_ java devs find it nice, I've heard lots of complaints when I was giving struts 2 classes that the struts 1 approach - a central xml gluing actions and url endpoints - seemed way easier, **even if it were making you switch contexts**.
This never clicked to me until I've started to work full time with Ruby on Rails.
Rails has a `config/routes.rb` and has a concise shorthand for specifying routes
� � # this is plain ruby code
� � resources :photos
Play has a `conf/routes` and it's a little more verbose
� � GET � � /tasks � � � � � � � � �controllers.Application.tasks()
� � POST � �/tasks � � � � � � � � �controllers.Application.newTask()
� � POST � �/tasks/:id/delete � � � controllers.Application.deleteTask(id: Long)
Proposal: We could have something code centric (no metadata, plain java code)
� � Routes routes = Routes.build(
� � � � from("/tasks/:id").on(GET).to(TaskController.class).find(":id"),
� � � � from("/tasks").on(POST).to(TaskController.class).newTask()
� � );
The idea is that we could have something that extracts a `Routes` instance from JAX-RS annotations too, but keep in mind that this is a bit slower than just running code straight.
Having programmatic routes mean this is refactor-friendly and can use IDE help.
### Having ActiveRecord-like Entity interaction
Rails brought again the ActiveRecord idea. Like it or not, it **can** yield nice readable code. Play uses Hibernate unde the hood for it, so it's mostly plain JPA:
� � // All entities inherit from Model
� � @Entity
� � public class Car extends Model {
� � �
� � }
And the usage
� � List<Car> �allTheCars = Car.all();
� � Car car = Car.find(1L);
� � car.delete();
� � new Car("corvette").save();
How cool is for a newcomer to just not have to learn about DAO/Repository stuff? Like it or not, it's one less object to deal with.
### Having a CLI REPL
Needless to say, one of the most amazing things for exploring an rails application codebase is the Console
� � $ rails console
� � > �Car.where(:age> �10) # oversimplifying
� � => �[Car, Car, Car, Car]
Having support for something like this (glorified beanshell?) would be very useful.
**Does forge fits the bill?**
### Schema evolution
WIP - working on an internal DSL for it
### Development mode& �Deployment
#### Environments
This is another feature that shines on rails - you have a consistent environment setup from the ground up.
� � $ rails console -e test
I still remember my days developing apps with spring and having `-Dcom.mycompany.application.env=PROD` and two sets of XML for the different environments.
#### Fast turnaround
Play's approach relies on having lots of static code, without a container + taking advantage of [sbt](https://github.com/harrah/xsbt/wiki) auto reloading support.
We want Object Oriented programming, and CDI is an important part of our model. �The problem is that we need very aggressive times for container bootstrap/startup to even compete with the **static-code-party**.
> So I'm going to focus solely on the MVC for right now, since that's the part we need to address first (though I agree we need to think about tooling and data productivity along the way.) Also, I think we may want to start moving this content to a wiki - email is a bad format for this. What do you guys think?
Wiki - Where Information Kills Itself (sorry, couldn't resist)
Yeah, I've made the PoC with "what's the dumbest and simplest way to get this working" in mind
>
> Notice that they are not using JAX-RS here, and there is just one big reason I can figure on that - because JAX-RS does not yet support validation (It will in 2.0: http://java.net/projects/jax-rs-spec/pages/Validation). JAX-RS 2.0 was even thinking about including an MVC feature, which I think got squashed because of scope creep (a good thing IMO.) However, Validation is something that we can address and add via a few techniques (see Validation section.)
Maybe we need to push this (MVC+Validation) for a JAX-RS 3.0?
>
> Otherwise, I believe that JAX-RS is a very good fit for us, and we need not re-invent the wheel completely. I think that folks will actually appreciate the familiar programming model.
>
> However, this makes it more difficult to apply a centralized routing strategy for those people that like to see everything in one place. Centralized routing means that we need to do more work. Not much more, and I think that we may still want to support this out of box because there ARE a lot of people who prefer this. It should be easy to do both, however.
>
> Again, we need some supporting classes, but we have several approaches, douglas listed several more in his document ( https://gist.github.com/8d074110af839a1190b7 ), but there are a few more I'd like to consider.
>
> • Annotation based - This ties in well with Navigation # 1, because you can simply use Reflection on the interface in your API, and the framework will know what to do (you can even pass some parameters.)
>
> • Downside: Controller probably needs to implement an interface in order to work, otherwise you don't know which method to call
> • Downside: Complicated to extend to handle additional conditions, difficult to add conditional routing
>
> @Routes // can have as many or as few of these as you like
> public interface MyAppRoutes {
>
> @AdminRequired
> @Path("/user/create")
> @If("#{userAgent == mobile}")
> @Controller(MyController.class)
> void createUser(@QueryParam("type") Type type);
>
> }
>
> • API based (Rewrite)
>
> When you want to start routing based on certain conditions without worrying about cluttering your Routing framework API, while still leaving yourself open to extension to other view frameworks, then this is a good match. Rewrite or a fluent Java API can handle both this scenario, and also scenario #1 - creating a new route, but in terms of creating a typesafe navigation API, option #1 is going to make things easier.
>
> .defineRoute("/user/create")
> .if("#{userAgent == mobile}")
- 1 // IMO this overcomplicate routes (and prevents me from shelling out a clean DFA for it)
> .securedBy(ADMIN)
+ 1 // this is amazing, although we could "namespace" a bunch of routes (by putting auth constraints)
> .to(MyController.class)
> .withParam("type", MyConverter.class, MyValidator.class)
> .withParam("p2", MyConverter2.class, MyValidator2.class);
>
> // Concern: How do we specify method parameter, if at all? Ordered method arguments? Seems ugly, can this be improved? If Java can do it, Rewrite can do it. We are actually discussing this at 2pm today in our development meeting.
>
> or...
>
> .to("/existing/route") // ahh, much better
>
> I'm having a hard time seeing how this would replace actually putting metadata / annotations on the class without a very verbose API, or requiring ordering of method arguments. But it's certainly something that needs to be available so that folks can integrate the MVC with their existing applications. It's my opinion that this fact alone is reason enough to include a Routing API.
Yeah, argument ordering is the way to go + precedence to disambiguate routes
It's worth noting that having a Java Fluent API (or internal DSL), we really need to keep it simple (aka less verbose), or it's better to fallback to an external DSL (I think we lose on this)
>
> Rendering:
> This is really pretty simple. We have a ViewMapper interface that can be registered to handle different types of view results, or we can bypass this entirely using the Routing framework (if the view tech already has its own URL or invocation strategy.) But that's up to the developer.
>
> • Templates and non-routed APIs - typically things like Velocity, Freemarker, or Seam Render. They have no bindings to a URL, so it's easy to provide a ViewMapper to take a Model result, and map it into a template.
I think a CDI viewMapper should fit the bill
>
> • Existing frameworks with Routes - more difficult to integrate because you may be dealing with stateful situations, for instance - JSF - You could argue about the benefit of putting a front-controller in front of JSF because the view "drives the entire lifecycle," but it's also possible to use a controller to populate your beans, then use the EL bindings in the view to do simple rendering and composite templating - this is typically the pattern I use in JSF that works the best.
Let's try to keep JSF out of the cycle - focusing on action based all the way
We already have a mockito-like api on VRaptor (we can steal it :)), so capturing the methods won't be a problem. (and it was advertised as "refactor-friendly")
>
>
> Or return a standard URL:
>
> return "/user/create?type=blah";
>
> • Navigate.to(MyController.class).viewUser("blah") // Needs to be able to abort further lifecycle processing, possibly by encapsulating strategy #3.
>
> • Not the prettiest API.
> throw Navigation.redirect(MyController.class).viewUser("blah");
>
> throw Navigation.redirect("/user/create?type=blah"); // implements Throwable
>
> • And then someone took drugs...
> <faces-config> ........ RUN!
> So, my hands are tired, and this is already a lot to swallow. I'll wrap it up with a summary of how I think Rewrite plays in here.
>
> Conclusion:
>
> First, unless we can solve the type-safe method invocation configuration problem, or decide to use an Interface on controllers, we are going to have difficulty using either a text-based configuration for routes, or a Java API-based configuration like Rewrite.
>
> However, we need to think about the practical cases here. We want this framework to be very productive from the start, for developing new apps, but we also absolutely NEED it to play well with existing applications, and be able to fit into existing ecosystems. This is where we are going to want a Routing API (as opposed to @Annotations) the most. It's much more difficult to perform non-invasive integrations into an application when you need to change application code in order to do it. This is the strongest case I can make for Rewrite and the Routing API at this time, but I think it is a very strong argument. But in a pure sense.
> It comes down to prototyping a bunch of these different styles and seeing which ones work best together. I think we really need to do some technical research and rigor here in order to get due diligence for any solution. So on that note, please converse. I'm going to start writing some code now.
I think we can and should support both annotation-based routing and programmatic config.
* centralized routes when talking to Rails/Grails/Play folks that is one of their favorite features.- Would the Java-based descriptor still be hot deployable? Hot deployment is critical IMO.
- But the proposed Java-based descriptor is a fair bit harder to read vs Play/Rails
- Plus, I would like to see how this concept can be blended with annotated JAX-RS which are our endpoints for HTML5 clients (POH5) today.
- and...what if we could provide a centralized view (shell command) of all the routes scattered around as annotations on the various classes? This might give you the easier maintenance point of annotations but the single view point of a routes.rb?
### Development mode & Deployment
> This may be a little too deep into the integration, but I would think having an abstraction object over a route and/or route container would be a good idea. Then you could extend it to configuration via xml, yaml, annotations, java api, etc. If we're hoping to get a wide range of developers to adopt this we'll probably be talking about more than one way of doing things.
exactly, for me the Java internal DSL generates a Routes object - We can have several ways to build it (xml, yaml, ruby, zomgwtfbbq)
This might have already been the plan and I have just missed it but it
seems it would be desirable to support both client-side and
server-side template rendering to bridge two worlds: the client
focused JS or GWT world and the traditional MVC world (JSF et al.).
Cheers,
Christian
I do want to comment on one thing, and that is scope. When I hear validation, conversion, etc... I get very nervous. Imo this is exactly where JSF shot itself in the foot. All of a sudden JSF needed lifecycle phases, more rules, more config, more...more!
I believe a minimal MVC with a limited initial scope, that can be added to easily is much more valuable. We need to keep some things like validation in mind as we design, but I don't want us to design the next JSF. I hope I'm not being too harsh, but we need something functional that can be built on.
Imo we need a few things, especially since we are basing it off of JAX-RS core.
- Central Routing - not sure which is best atm.
- Some sort of rewrite support
- Pluggable view dispatcher
- Lets default to container based for initial impl
- Security integration
- Well underway with DS and AeroGear efforts
In some respects, even advanced navigation can be phase 2, 3, 4 type things imo.
As far as prototyping, go for it, but lets be mindful that some prototyping gets thrown away - its a prototype. We should be careful how far down the road we go before we bring idea's and approaches back for discussions.
On Mon, Apr 2, 2012 at 5:42 PM, Jay Balunas <tec...@gmail.com> wrote:I do want to comment on one thing, and that is scope. When I hear validation, conversion, etc... I get very nervous. Imo this is exactly where JSF shot itself in the foot. All of a sudden JSF needed lifecycle phases, more rules, more config, more...more!
I'll just put it out there that I disagree that this is scope creep; we can't ignore these things or the framework will not be viable technically in real situations. That's part of the benefit of combining JAX-RS with a light validation framework like we did with Security.
I believe a minimal MVC with a limited initial scope, that can be added to easily is much more valuable. We need to keep some things like validation in mind as we design, but I don't want us to design the next JSF. I hope I'm not being too harsh, but we need something functional that can be built on.
I never said anything about phases ;) JSF has many problems, but validation and conversion are not really part of them (aside from obvious lack of CDI support.)
Imo we need a few things, especially since we are basing it off of JAX-RS core.
- Central Routing - not sure which is best atm.
- Some sort of rewrite support
Show me an app and I'll show you how rewrite integrates. This can be added no matter what we do.
- Pluggable view dispatcher
- Lets default to container based for initial impl
Container based? Could you explain what you mean?
- Security integration
- Well underway with DS and AeroGear efforts
Agreed, I don't think we need much discussion here on Security.
In some respects, even advanced navigation can be phase 2, 3, 4 type things imo.
I'd say this is something we need to at least consider up front or our initial routing designs could potentially make this very difficult.
As far as prototyping, go for it, but lets be mindful that some prototyping gets thrown away - its a prototype. We should be careful how far down the road we go before we bring idea's and approaches back for discussions.
I'd just like to say that this is true, but by all means, go freakin' wild prototyping. Just let us see and comment :)
> JAX-RS 2.0 was even thinking about including an MVC feature, which I think got squashed because of scope creep (a good thing IMO.)
I think it was mainly because it was because Paul, who was championing it, and was spec lead, left ;-)
Although you could argue that JSP and JSF compete in the same UI space.
Sent from my iPhone
> And yes, this was a good thing. If we want to standardise an MVC framework, it should be as a new JSR, not as part of JAX-RS. It's a different topic with different experts and focus.
+1
ouch! was it that bad? :)
I dont think I went that route. in fact I think I implied that we use bean validation, which is definitely the direction I think we should head in! I was merely suggesting that we try to advance the jaxrs 2.0 features if possible. (they use bean validarion)
---
Lincoln Baxter's Droid
http://ocpsoft.org
"Simpler is better."