001package org.nuxeo.ecm.webengine.samples; 002 003import javax.ws.rs.GET; 004import javax.ws.rs.Path; 005import javax.ws.rs.Produces; 006 007import org.nuxeo.ecm.webengine.model.WebObject; 008import org.nuxeo.ecm.webengine.model.impl.DefaultObject; 009 010/** 011 * WebEngine Object Model. This sample explains the basics of Nuxeo WebEngine Object Model. 012 * <p> 013 * <h3>Resource Model</h3> Resources are objects used to serve the request. WebEngine Resources are always stateless (a 014 * new instance is created on each request). There are three types of resources defined by WebEngine: 015 * <ul> 016 * <li>Module Resource - this is the Web Module entry point as we've seen in sample3. This is the root resource. The 017 * other type of resources are JAX-RS sub-resources. A WebModule entry point is a special kind of WebObject having as 018 * type name the module name. 019 * <li>Web Object - this represents an object that can be requested via HTTP methods. This resource is usually wrapping 020 * some internal object to expose it as a JAX-RS resource. 021 * <li>Web Adapter - this is a special kind of resource that can be used to adapt Web Objects to application-specific 022 * needs. 023 * <p> 024 * These adapters are useful to add new functionalities on Web Objects without breaking application modularity or adding 025 * new methods on resources. This is helping in creating extensible applications, in keeping the code cleaner and in 026 * focusing better on the REST approach of the application. For example let say you defined a DocumentObject which will 027 * expose documents as JAX-RS resources. A JAX-RS resources will be able to respond to any HTTP method like GET, POST, 028 * PUT, DELETE. So let say we use: 029 * <ul> 030 * <li> {@code GET} to get a view on the DocumentObject 031 * <li> {@code POST} to create a DocumentObject 032 * <li> {@code PUT} to update a document object 033 * <li> {@code DELETE} to delete a DocumentObject. 034 * </ul> 035 * But what if I want to put a lock on the document? Or to query the lock state? or to remove the lock? Or more, to 036 * create a document version? or to get a document version? A simple way is to add new methods on the DocumentObject 037 * resource that will handle requests top lock, unlock, version etc. Somethig like {@code @GET @Path("lock") getLock()} 038 * or {@code @POST @Path("lock") postLock()}. But this approach is not flexible because you cannot easily add new 039 * functionalities on existing resources in a dynamic way. And also, doing so, you will end up with a cluttered code, 040 * having many methods for each new aspect of the Web Object you need to handle. To solve this problem, WebEngine is 041 * defining Web Adapters, so that they can be used to add new functionality on existing objects. For example, to handle 042 * the lock actions on an Web Object we will define a new class LockAdapter which will implement the {@code GET}, 043 * {@code POST}, {@code DELETE} methods to manage the lock functionality on the target Web Object. Adapters are 044 * specified using an '@' prefix on the segment in an HTTP request path. This is needed by WebEngine to differentiate 045 * Web Objects from Web Adapters. Thus in our lock example to request the lock adapter on an object you will use a 046 * request path of like the following: {@code GET /my/document/@lock} or {@code POST /my/document/@lock} etc. 047 * <p> 048 * When defining a Web Adapter you can specify on which type of Web Object it may be used. (this is done using 049 * annotations) 050 * </ul> 051 * All WebEngine resources have a type, a super type, an optional set of facets and an optional guard (these are 052 * declared using annotations) By using types and super types you can create hierarchies or resources, so that derived 053 * resource types will inherit attributes of the super types. 054 * <p> 055 * There is a builtin adapter that is managing Web Objects views. The adapter name is {@code @views}. You will see in 056 * the view model an example on how to use it. 057 * <p> 058 * Thus, request paths will be resolved to a resource chain usually of the form: WebModule -> WebObject -> ... -> 059 * WebObject [ -> WebAdapter ]. <br> 060 * Each of these resource objects will be <i>served</i> using the <i>sub-resource</i> mechanism of JAX-RS until the last 061 * resource is reached. The last resource will usually return a view to be rendered or a redirection response. The 062 * request resource chain is exposed by the WebContext object, so that one can programatically retrieve any resource 063 * from the chain. In a given resource chain there will be always 2 special resources: a <b>root</b> and a <b>target</b> 064 * resource The root resource is exposed in templates as the {@code Root} object and the target one as the contextual 065 * object: {@code This}. <br> 066 * <b>Note</b> that the root resource is not necessarily the first one, and the target resource is not necessarily the 067 * last one! More, the root and the target resources are never WebAdapters. They can be only WebObjects or WebModule 068 * entry points (that are aspecial kind of WebObjects). 069 * <p> 070 * The root resource is by default the module entry point (i.e. the first resource in the chain) but can be 071 * programatically set to point to any other WebObject from the chain. 072 * <p> 073 * The target resource will be always the last WebObject resource from the chain (so any trailing WebAdapters are 074 * excluded). This means in the chain: {@code /my/space/doc/@lock}, the root will be by default {@code my} which is the 075 * module entry point, and the target resource will be {@code doc}. So it means that the {@code $This} object exposed to 076 * templates (and/or views) will never points to the adapter {@code @lock} - but to the last WebObject in the chain. So 077 * when an adapter view is rendered the {@code $This} variable will point to the adapted WebObject and not to the 078 * adapter itself. In that case you can retrieve the adapter using {@code $This.activeAdapter}. This is an important 079 * aspect in order to correctly understand the behavior of the {@code $This} object exposed in templates. 080 * <p> 081 * <h3>View Model</h3> The view model is an extension of the template model we discussed in the previous sample. The 082 * difference between views and templates is that views are always attached to an Web Object. Also, the view file 083 * resolution is a bit different from template files. Templates are all living in {@code skin} directory. Views may live 084 * in two places:} 085 * <ul> 086 * <li>in the skin/views/${type-name} folders where type-name is the resource type name the view is applying on. This 087 * location will be consulted first when a view file is resolved, so it can be used by derived modules to replace views 088 * on already defined objects. 089 * <li>in the same folder (e.g. java package) as the resource class. This location is useful to defining views inside 090 * JARs along with resource classes. 091 * </ul> 092 * Another specific property of views is that they are inherited from resource super types. For example if you have a 093 * resource of type {@code Base} and a resource of type {@code Derived} then all views defined on type {@code Base} 094 * apply on type {@code Derived} too. You may override these views by redefining them on type {@code Derived} <br> 095 * Another difference between templates and views is that views may vary depending on the response media-type. A view is 096 * identified by an ID. The view file name is computed as follow: 097 * 098 * <pre> 099 * view_id + [-media_type_id] + ".ftl" 100 * </pre> 101 * 102 * The {@code media_type_id} is optional and will be empty for media-types not explicitly bound to an ID in modules.xml 103 * configuration file. For example, to dynamically change the view file corresponding to a view having the ID 104 * {@code index} when the response media-type is {@code application/atom+xml} you can define a mapping of this media 105 * type to the media_type_id {@code atom} and then you can use the file name {@code index-atom.ftl} to specify a 106 * specific index view when {@code atom} output is required. 107 * 108 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 109 */ 110@WebObject(type = "Basics") 111@Produces("text/html;charset=UTF-8") 112public class BasicsObject extends DefaultObject { 113 114 /** 115 * Get the index view. The view file name is computed as follows: index[-media_type_id].ftl First the 116 * skin/views/Basics is searched for that file then the current directory. (The type of a module is the same as its 117 * name) 118 */ 119 @GET 120 public Object doGet() { 121 return getView("index"); 122 } 123 124 /** 125 * Get the WebObject (i.e. a JAX-RS sub-resource) bound to "users". Look into "users" directory for the UserManager 126 * WebObject. The location of WebObjects is not explictely specified by the programmer. The module directory will be 127 * automatically scanned for WebObject and WebAdapters. 128 */ 129 @Path("users") 130 public Object getUserManager() { 131 // create a new instance of an WebObject which type is "UserManager" and push this object on the request chain 132 return newObject("UserManager"); 133 } 134 135}