Re: Evaluating sling
On 02.01.11 21:51, Markus Joschko markus.josc...@gmail.com wrote: 1) It is more a finding then a question: I miss the C in MVC. I read that a controller is not required when using SLING as the selection of scripts happens content driven. The nice thing about Sling is that you don't have to write the controller (or at least most of it), especially no URL-wiring. However I have seen code on top of some jsps that is typical for a controller:E.g. checking whether a user is logged in (or has the appropriate role) and redirecting if that's not the case. Authentication is so generic and required by most web apps that it is generally handled in Sling. Also, with the JCR repository the general concept is to have authentication and authorization as part of the repository infrastructure, so when Sling provides a JCR session for each request, it must log in with a given user. The details of how certain auth mechanisms works (such as http basic, form login, OpenID, etc.) can be plugged in as authentication handlers. For more see http://sling.apache.org/site/authentication.html I would like to see that code in a controller, long before my HTML view template is about to render and not mixed into my view. Is there any concept in SLING to provide a better separation? Speaking about separation: I have seen a lot of code on top of the esp and jsps files. That's fine for samples but for the last years I always tried to avoid that kind of mixture in my projects. Is there a way to provide all that code in java services which can make use of DI and just provide calculated values to the HTML view? Something I'd do normally in the controller? (I am aware of JSPs taglibs but, hm, I don't like the programming model. Any alternatives?) I think this all is an aspect of maximizing code-reuse and code readability in the rendition (view) layer. The access to the model comes with the JCR API (using Node as your flexible domain object) and/or Resource API in Sling (just a simpler API abstraction on top). This can already lead to short JSPs (e.g. just printing the properties of a node). For extracting more complex code, I would use helper classes, wrapper objects (wrapping the JCR or Resource API) or yes, even write a custom tag lib (JSP specific, though, and probably only for very common things). I think it is wrong that those things are placed inside the (web application) controller - they are either part of the model (here: mainly JCR) or simply helpers in the rendering logic. But this might also be a philosophical question ;-) I know that in the Spring MVC world people write a lot of domain objects and restrict people to use only what these provide in the JSPs. With Sling and JCR however, the underlying data model is much more flexible because it is unstructured and thus allows for faster development cycles and less layers of code to maintain. Also there is this rule no JSP snippets, which IMHO is totally arbitrary and comes from the (wrong) notion, that only web designers work on the JSPs and they should not be messing with the code... In many cases you have a very rendering-specific logic and why not use all what the JSP technology provides in the first place? 2) How is input validation done? The postservlet allows the client to post nearly everything in every structure to the repository. I am sure there are ways to restrict that ability. I guess part of this is to define ACLs on the repository and to not use nt:unstructured as nodetype but a more precise one (see next question). But how would I do more low level validation like checking that a number is in a certain range, a string matches a given regex or a given e-mailadress is not already existent in the repository? Sling Post processors are a way to combine that with the post servlet. They are run after the Sling POST operation has been executed on the current JCR session, but before it has been saved: http://sling.apache.org/apidocs/sling5/org/apache/sling/servlets/post/Sling PostProcessor.html Or use a custom filter that runs before the Sling POST servlet. Otherwise, in most cases the validation can (or must also) already happen on the UI side. This in combination with unstructured gives you the best flexibility, while providing a good experience for users. Don't be afraid of using nt:unstructured, for most cases you don't want hard constrains in the repository! If you start using strongly constrained node types = fixed schema, you loose a lot on the niceness of JCR. In this regard, also have a look at David's model: http://wiki.apache.org/jackrabbit/DavidsModel 3) How do I interact with the underlying jackrabbit repository? In the slingbucks sample I have seen some json files to setup a basic structure. Can I use that mechanism to also setup custom node types and define ACLs? Or how would I do that? http://wiki.apache.org/jackrabbit/JcrLinks#Open_Source_Tools_and_Libraries And/or use the JCR API for application-specific
Re: Evaluating sling
However I have seen code on top of some jsps that is typical for a controller: E.g. checking whether a user is logged in (or has the appropriate role) and redirecting if that's not the case. Authentication is so generic and required by most web apps that it is generally handled in Sling. Also, with the JCR repository the general concept is to have authentication and authorization as part of the repository infrastructure, so when Sling provides a JCR session for each request, it must log in with a given user. The details of how certain auth mechanisms works (such as http basic, form login, OpenID, etc.) can be plugged in as authentication handlers. For more see http://sling.apache.org/site/authentication.html Yet I found that code in the sample crx bookstore application http://code.google.com/p/crxzon/source/browse/trunk/apps/bookstore/components/checkout/checkout.jsp?r=11 And authentication is not the only reason for controling the view. I guess everything that's not a static resource lookup but a dynamic/runtime decision benefits from having a controller. E.g. in an onlineshop where a user enters his address the software might check the address and redirect the user to different payment flows depending on the location. Can this be cleanly expressed in sling? I would like to see that code in a controller, long before my HTML view template is about to render and not mixed into my view. Is there any concept in SLING to provide a better separation? Speaking about separation: I have seen a lot of code on top of the esp and jsps files. That's fine for samples but for the last years I always tried to avoid that kind of mixture in my projects. Is there a way to provide all that code in java services which can make use of DI and just provide calculated values to the HTML view? Something I'd do normally in the controller? (I am aware of JSPs taglibs but, hm, I don't like the programming model. Any alternatives?) I think this all is an aspect of maximizing code-reuse and code readability in the rendition (view) layer. The access to the model comes with the JCR API (using Node as your flexible domain object) and/or Resource API in Sling (just a simpler API abstraction on top). This can already lead to short JSPs (e.g. just printing the properties of a node). For extracting more complex code, I would use helper classes, wrapper objects (wrapping the JCR or Resource API) or yes, even write a custom tag lib (JSP specific, though, and probably only for very common things). I think it is wrong that those things are placed inside the (web application) controller - they are either part of the model (here: mainly JCR) or simply helpers in the rendering logic. But this might also be a philosophical question ;-) There are no such things like simple helpers ;-) E.g. in the Slingbucks example the price is calculated in an esp. Fine for that example but in a real world app you would probably have to ask other systems for sales conditions, make a db lookup to check blacklists etc and soon the calculation is no longer simple. You want to have access to your ecosystem, probably services and dependency injection to ease the wiring. That's nothing a simple static helper or a tag library has to offer. It's much easier to do all that in a java based controller. I know that in the Spring MVC world people write a lot of domain objects and restrict people to use only what these provide in the JSPs. With Sling and JCR however, the underlying data model is much more flexible because it is unstructured and thus allows for faster development cycles and less layers of code to maintain. Also there is this rule no JSP snippets, which IMHO is totally arbitrary and comes from the (wrong) notion, that only web designers work on the JSPs and they should not be messing with the code... In many cases you have a very rendering-specific logic and why not use all what the JSP technology provides in the first place? Mhm, because it's too easy to produce a hard to test maintenance nightmare? Unfortunately I had to develop in a rather large site where JSPs heavily mixed markup with code and had multi level snippet includes. While the system originally was developed in a very short time frame, the maintenance was extremely painful and expensive. 2) How is input validation done? The postservlet allows the client to post nearly everything in every structure to the repository. I am sure there are ways to restrict that ability. I guess part of this is to define ACLs on the repository and to not use nt:unstructured as nodetype but a more precise one (see next question). But how would I do more low level validation like checking that a number is in a certain range, a string matches a given regex or a given e-mailadress is not already existent in the repository? Sling Post processors are a way to combine that with the post servlet. They are run after the Sling POST operation has been
Re: Evaluating sling
On 03.01.11 16:25, Markus Joschko markus.josc...@gmail.com wrote: Yet I found that code in the sample crx bookstore application http://code.google.com/p/crxzon/source/browse/trunk/apps/bookstore/compone nts/checkout/checkout.jsp?r=11 That should be possible otherwise, using the plain sling auth mechanisms. However, I didn't write this sample, so I don't know the reasoning behind this and that. And authentication is not the only reason for controling the view. I guess everything that's not a static resource lookup but a dynamic/runtime decision benefits from having a controller. E.g. in an onlineshop where a user enters his address the software might check the address and redirect the user to different payment flows depending on the location. Can this be cleanly expressed in sling? A clean Sling approach would model the onlineshop using (JCR) resources in a restful way. For the redirect, you could have a plain Java servlet (or jsp) for that POST-address-resource calling into some service providing the information for the given address and then doing an internal (sling include/forward) or external (http) redirect to the proper payment form. There are no such things like simple helpers ;-) E.g. in the Slingbucks example the price is calculated in an esp. Fine for that example but in a real world app you would probably have to ask other systems for sales conditions, make a db lookup to check blacklists etc and soon the calculation is no longer simple. But you should still strive for a simple architecture for a simple calculation ;-) These other systems would probably be best implemented as (osgi scr) services. You want to have access to your ecosystem, probably services and dependency injection to ease the wiring. That's nothing a simple static helper or a tag library has to offer. It's much easier to do all that in a java based controller. Yes, I think for most plain logic-only scripts you'd use a plain java servlet, calling into those services. If they need to return some html as well, a JSP is fine for that as well (just some service calls and then the rendering part). Using the simple sling include mechanism, it is also easy to build a component system, where you might have a top-level java servlet handling the resource type (controller-like) and then including sub-paths or using different resource types which do jsp based rendering. Mhm, because it's too easy to produce a hard to test maintenance nightmare? Unfortunately I had to develop in a rather large site where JSPs heavily mixed markup with code and had multi level snippet includes. While the system originally was developed in a very short time frame, the maintenance was extremely painful and expensive. Ok, granted. Developers should not try to write complex jsps and leave back a mess. But preventing any use of jsp snippets is also a huge self-constraint. Mhm, yes validation happens on the UI side. But also on the serverside. Otherwise it would be far to easy to circumvent the validation by modifying the HTTP requests. Combined with a nt:unstructured node the repository doors are then open for attackers to put malicious content into. You would use ACL of course that prevent people from writing into locations they are not allowed to. The execution of scripts (setting a resource type and uploading a script) is restricted/able to certain folders. So input validation is a must. Yes, but not for everything (personal opinion). Most cases fall into the category of it is possible for someone to tweak the HTTP request to write his zip code as a string instead of a number. And JCRs implicit value type conversion helps here more or less automatically. If you have the need, you can write your own POST handler or a Sling post processor, as mentioned. And that's where I would hope to get some help from my model. If the model already knows that a property is not a string but a number it can help me to check the input. And maybe it's possible to add validation rules to the nodetype so input validation is done declaratively? That's not possible with an unstructured nodetype. With node types, you can restrict what properties are allowed, what type they are and for string properties you can also have value constraints (regexps). Mhm, and I am not sure if I really see the advantages of nt:unstructured. The model exists either in code (duck typing) or in the repository. If it is in code you need to validate the data and that requires code like that one from the slingbucks options.esp // If field has a jcr:title property, we can use it. 31 if(f[jcr:title]) { ... If I could rely on the fact that the currentNode has a mandatory title attribute, I could spare this check. What if it doesn't have this title? For one, it is impossible to guarantee that from the storage layer (not even with RDBMS, things break) and also what if a future version doesn't require a title? The application knows what to do when a title is there or not. It is
freemarker
.Hi I am evaluating CQ5/Sling and have a 2 questions of freemarker support. If any of these questions should be addressed to other mailing list please don't hesitate to point it. In a sling there is a freemarker scripting engine that binds some objects (like current node) to freemarker model map and then executes ftl template feeding it with the model. That's fine but since freemarker support is based on scripting engine - all freemarker request are routed through single class i.e. FreemarkerScriptEngine, I find this approach a little bit limited. I am much more into old school freemarker usage: create sling servlet that handles specific request URL (like http://foo.bar/app/productList), let that servlet build model, load freemarker template and send freemarker template processing result to outputstream. In code it looks like this: [code] class MyProductSlingServlet extends SlingSafeMethodsServlet{ public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response){ Map model = buildSpecificModel(request); Template freemarkerTemplate = getTemplate(request); freemarkerTemplate.process(model, response.getWriter()); } } [/code] To make it work i had to deploy osgified freemarker into Felix. Employing this approach i can write servlet that can build specific model for the specific request. So building model and choosing appropriate ftl file is nicely encapsulated in a servlet created to handle given request. It is a major difference to that how it works in sling freemarker scripting since the latter only binds current node to freemarker map (asfaik this behavior can be extended by using mechanism to allow bundles to contribute script binding values) but indeed I can see no dedicated building model per request mechanism. Any comments from more experienced CQ5/Sling users ? The other thing i bumped into is the fact that freemarker scripting support in sling is an OSGI bundle (org.apache.sling.scripting.freemarker) with freemarker embedded. Why is it done like that ? Isn't it more natural and correct to have that bundle contains only it's own classes and then specify that it imports freemarker.template package.It would require installing of 2 bundles: osgified freemarker and freemarker scripting support bundle but the final solution would be more OSGI friendly. As a matter of face today i did some sample coding and wanted to extend the code presented above by putting current node object into model map. Looking at http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/freemarker/src/main/java/org/apache/sling/scripting/freemarker/FreemarkerScriptEngine.java?view=markupit seemed quite simple: [code] Resource resource = request.getResource(); Node n = resource.adaptTo(Node.class); model.put(currentNode, new NodeModel(n)); [/code] Everything seemed to work fine and i was able to reach currentNode variable and its properties from my ftl file. The problem was that instead of getting string values of properties i did get strings like: org.apache.sling.scripting.freemarker.wrapper.propertymo...@1fsa2 . For 100 % it wasn't value of the property i referenced to and it looked to me like the result of toString() call on org.apache.sling.scripting.freemarker.wrapper.PropertyModel instance. After a short investigation i found out that the problem was caused by 2 version of freemarker in the system: the one i installed myself - to use freemarker in my sling servlet, and the second one from freemarker scripting support. Since freemarker processing is triggered by my sling servlet all template building and processing is done in the context of (my own installed) osgified version of freemarker. If NodeModel (or any of its child) is to be rendered it returns instances that reference/implement freemarker classes. Unfortunately these classes were loaded from freemarker scripting support bundle, hence by a different classloader from the one that processes ftl template so the property values couldn't be correctly rendered. The solution was straightforward: just remove embedded freemarker from freemarker scripting support bundle and let the bundle import (osgified) freemarker. I believe it is a bug that freemarker is embedded into freemarker scripting support bundle and it should be removed asap. regards miluch