<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7203181491808683266</id><updated>2012-01-26T03:58:56.700-08:00</updated><category term='sencha'/><category term='mobile'/><category term='working with workflows'/><category term='Servicemix'/><category term='extending share'/><category term='ECM SOA'/><category term='REST'/><category term='ECB'/><category term='learning surf'/><category term='ESB'/><category term='jBPM'/><category term='Surf'/><category term='Share 3.2 preview'/><category term='Alfresco'/><category term='BPM'/><category term='Spring'/><category term='Enterprise 2.0'/><category term='CMIS'/><category term='Forms Engine'/><category term='Web 2.0'/><category term='HTML5'/><title type='text'>Enterprise 2.0 Application Technologies</title><subtitle type='html'>Discussions of building enterprise applications leveraging Web 2.0+ concepts with technologies related to Java including: HTML5, Ajax, Spring Roo, GWT and other JavaScript and rich client libraries, while leveraging SOA, REST, ORM Persistence and the Semantic Net.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-934430772670608998</id><published>2012-01-17T11:17:00.000-08:00</published><updated>2012-01-26T03:58:56.704-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='sencha'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML5'/><title type='text'>Sencha Touch</title><content type='html'>This blog is outlining my experiences developing a mobile web based application developed with Sencha Touch and packaged with PhoneGap.&lt;br /&gt;&lt;br /&gt;I have been developing a quick app for my iphone using &lt;a href="http://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CEYQFjAA&amp;amp;url=http%3A%2F%2Fwww.sencha.com%2Fproducts%2Ftouch&amp;amp;ei=a8kVT-yJNOuCsgKkzqCIBA&amp;amp;usg=AFQjCNFIc52OJr69O-7WkHimgmsFDgM1Aw&amp;amp;sig2=i0_l5I6xuSZjvzu835v3OA"&gt;Sencha Touch API&lt;/a&gt; (currenty 1.1). I have found it quite intuitive and the outcome is that I get a web based app that can be run nicely on Android as well as &lt;a href="http://www.apple.com/ios/"&gt;iOS&lt;/a&gt; devices. And I get to develop on my Win based machine in Java. Easy to test without emulator using normal browser too.&lt;br /&gt;&lt;br /&gt;The idea is to write code via HTML5 that can be useful on touch based devices such as iPhone, iPad and Android based phones and tabs. Rather than learning languages and frameworks specific to these technologies it is possible to stick to common HTML5 skills that still support touch device like gestures and form factors.&lt;br /&gt;&lt;br /&gt;In addition to deploying as a device capable web site, I intend to wrap it up with &lt;a href="http://phonegap.com/"&gt;PhoneGap&lt;/a&gt;&amp;nbsp;to deploy it as native binaries onto multiple devices (Android, iOS, BB)&amp;nbsp;with access to native APIs.&lt;br /&gt;&lt;br /&gt;The technology I am starting with&lt;br /&gt;&lt;br /&gt;I'm not cool enough to develop on a Mac Book, so I'm building on Win 7 Laptop. For my editor, I've been trying out &lt;a href="http://www.sublimetext.com/"&gt;Sublime Text 2&lt;/a&gt;. Nice that it opens a folder tree and has smart syntax highlighting for JavaScript, and knows about all the HTML5 stuff (CSS, JSON, HTML, JavaScript) but a full fledged IDE would have things like code complete and syntax checking right in the IDE, so I am also old schooling it and using Eclipse IDE. &lt;br /&gt;&lt;br /&gt;I have setup&lt;a href="http://eclipse.org/downloads/packages/eclipse-classic-371/indigosr1"&gt; Eclipse IDE (Classic edition)&lt;/a&gt; augmented with &lt;a href="http://developer.android.com/sdk/index.html"&gt;Android SDK&lt;/a&gt; and the emulators, with the &lt;a href="http://developer.android.com/sdk/eclipse-adt.html"&gt;ADT Android Developer Tools eclipse plugin&lt;/a&gt;. However, for just Sencha touch the android stuff is not needed. But soon i will be looking at &lt;a href="http://phonegap.com/"&gt;PhoneGap&lt;/a&gt; to create binaries ready to deploy to devices. And I'm also developing with Android SDK specifically.&lt;br /&gt;&lt;br /&gt;I am also building the server side. I have been looking at &lt;a href="http://node.js/"&gt;node.js&lt;/a&gt; as a possibility. But I am also looking at Java based solutions as well (I'm showing my age I guess). For the Java based solutions, I am looking at deploying a J2EE (war) app and using &lt;a href="http://www.springsource.org/"&gt;Spring MVC &lt;/a&gt;as a core framework on the server side. &lt;br /&gt;&lt;br /&gt;To deploy as a server based web app (and I also intend to have server side components as well), I have constructed a maven driven web app from a maven archetype (see &lt;a href="http://www.mkyong.com/maven/how-to-create-a-web-application-project-with-maven/"&gt;this great blog article&lt;/a&gt;), and assuring it has the web app nature for using eclipse with help and great gratitude from &lt;a href="http://www.mkyong.com/maven/how-do-use-maven-to-create-a-dynamic-web-project-in-eclipse/"&gt;this blog&lt;/a&gt;. This process of getting Eclipse to work with Maven for a web app based project was more complex and error prone than I'd like. My desire was to use the IDE to code and build, and see the results immediately synchronized on the integrated web server. But Eclipse doesn't build natively with Maven goals like NetBeans does, and the integrated web server plugins aren't as smart as they should on when to sync, deploy and run. I may rethink this choice as I go along.&lt;br /&gt;&lt;br /&gt;To help provide the server stuff I need (remember Im on a Windows platform) I downloaded &lt;a href="http://www.apachefriends.org/en/xampp.html"&gt;XAMPP &lt;/a&gt;and am running&amp;nbsp;separate&amp;nbsp;a Tomcat instance as an independent deployment target different from the&amp;nbsp;Eclipse integrated tomcat server where I can test changes during development.    &lt;br /&gt;&lt;br /&gt;For the hosted solution and since I'm deploying to a java based app server (tomcat), I am deploying to &lt;a href="http://jelastic.com/"&gt;jelastic&lt;/a&gt;&amp;nbsp;I can test &amp;nbsp;it on my real devices. I also have Android emulators integrated into Eclipse and also &lt;a href="http://ipadian.net/"&gt;iPadian &lt;/a&gt;emulating an ipad but I haven't tried that avenue yet.&lt;br /&gt;&lt;br /&gt;The real devices I have to test on incude:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;galaxy 10.1 tab&lt;/li&gt;&lt;li&gt;iphone 3GS (old I know)&lt;/li&gt;&lt;/ul&gt;For basic application architecture I have two MVC frameworks!&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;One MVC on the client (Sencha Touch with MVC pattern) and&amp;nbsp;&lt;/li&gt;&lt;li&gt;One MVC on the server (Spring MVC).&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;Overkill? we shall see.&amp;nbsp;We will get into the MVC model client and server side in another blog.&lt;br /&gt;&lt;br /&gt;For Sencha Touch I am following the MVC pattern as described by the &lt;a href="http://www.sencha.com/learn/working-with-forms/"&gt;sencha forms tutorial&lt;/a&gt;. &amp;nbsp;Also, I have followed a great talk and tutorial from this German developer &lt;a href="http://www.nils-dehl.de/"&gt;Nils Dehl&lt;/a&gt; where he creates a shopping list app.&lt;br /&gt;&lt;br /&gt;For persistence, I have two choices: old school main stream relational (MySQL) or&lt;a href="http://en.wikipedia.org/wiki/NoSQL"&gt; NoSQL&lt;/a&gt;&amp;nbsp;approach with &lt;a href="http://www.mongodb.org/"&gt;MondoDB&lt;/a&gt;. I will start out with mondo db and see what happens. The idea is that the data model is going to be json based and object oriented. Structured, hierarchic data can be managed using objects and indexes. For the app I want to build, it may work well. But it seems heretical (not necessarily a bad thing)..&lt;br /&gt;&lt;br /&gt;Next article I will get into the app design...&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-934430772670608998?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/934430772670608998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=934430772670608998' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/934430772670608998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/934430772670608998'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2012/01/sencha-touch.html' title='Sencha Touch'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-5935331876271808413</id><published>2011-07-29T17:31:00.000-07:00</published><updated>2011-07-31T10:55:59.904-07:00</updated><title type='text'>Getting started with Spring Roo, GWT and STS</title><content type='html'>&lt;div&gt;Time to get started. I'm going to run through the introductory materials on building a &lt;a href="http://www.springsource.org/roo"&gt;Spring Roo&lt;/a&gt; application with the &lt;a href="http://code.google.com/webtoolkit/"&gt;Google Web Toolkit&lt;/a&gt; front end. I will be using the Spring Tools Suite as the IDE (based on Eclipse).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I will start by following some initial advice:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;on the Google side: here is a &lt;a href="http://code.google.com/webtoolkit/doc/latest/tutorial/roo-sts.html4"&gt;google code blog&lt;/a&gt;&lt;/li&gt;&lt;li&gt;on the Spring side: here is the&lt;a href="http://www.springsource.org/roo/start"&gt; springroo start&lt;/a&gt; and the&lt;a href="http://static.springsource.org/spring-roo/reference/html/beginning.html"&gt; Beginning with Roo: The tutorial from Spring Framework&lt;/a&gt; reference documentation&lt;/li&gt;&lt;li&gt;another blog (&lt;a href="http://gwtsts.blogspot.com/"&gt;gwtsts.blogspot.com&lt;/a&gt;) by &lt;span class="Apple-style-span" style="color: rgb(34, 34, 34); font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 12px; font-weight: bold; line-height: 16px; "&gt;&lt;a class="profile-name-link" href="http://www.blogger.com/profile/10471886955497473463" rel="author" style="text-decoration: none; color: rgb(34, 136, 187); "&gt;Cengiz Öner&lt;/a&gt; &lt;/span&gt;describing this effort has&lt;a href="http://gwtsts.blogspot.com/2011/03/part-i-installation-and-setup-of-sts.html"&gt; multi-part instructions&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Installation&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What I have&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Java 6 SDK r26 from &lt;a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk-6u26-download-400750.html"&gt;here&lt;/a&gt;&lt;/li&gt;&lt;li&gt;SpringSource Tool Suite: Version: 2.7.1.RELEASE: Build Id: 201107091000&lt;/li&gt;&lt;li&gt;Using Google Suite Plugin Version 2.3.3.r36v201107211953&lt;/li&gt;&lt;li&gt;Spring Roo (latest production release) 1.1.4 RELEASE&lt;/li&gt;&lt;/ul&gt;I got Spring Tool Suite bundled with Google Integration from &lt;a href="http://www.springsource.com/developer/sts"&gt;here&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After running STS, go to the dashboard and select the 'extensions' tab (bottom). Find and Check Google Plugin for Eclipse and press 'Install' (bottom left)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Restart STS and thats it (for now)&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Overview of Spring Pizza Shop Demo&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Lets use the &lt;a href="http://static.springsource.org/spring-roo/reference/html/beginning.html"&gt;Spring Framework Roo tutorial&lt;/a&gt; to get started.This tutorial walks us through creating a Roo project including entities controllers and the UI/scaffold. I will try to emphasise use of the STS tool as well as focusinging on using GWT as the front end. To begin with, we will follow the tutorial fairly closely.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Here is the project UML from the spring tutorial that we will create&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is the Roo Pizza Shop demo&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://static.springsource.org/spring-roo/reference/html/images/pizza.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 450px; height: 123px;" src="http://static.springsource.org/spring-roo/reference/html/images/pizza.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;First Step Basic Roo Configuration&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Spring Roo builds upon Spring framework 3.0 with JPA 2.0. It uses a command line tool to create basic elements of a project, from persistence setup, to creating entities, to creating Spring MVC controllers, to generating Scaffold ui (in our case using GWT).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;We can use spring STS to create a new spring Roo project project&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-LGT52MfXiI4/TjWI-8sf3yI/AAAAAAAAAFc/-DVZ_A_PANk/s1600/sts-createrooproject.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 218px; height: 320px;" src="http://2.bp.blogspot.com/-LGT52MfXiI4/TjWI-8sf3yI/AAAAAAAAAFc/-DVZ_A_PANk/s320/sts-createrooproject.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5635561123750076194" /&gt;&lt;/a&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;From the Dashboard, select Create a Spring Roo Project&lt;/li&gt;&lt;li&gt;Fill out dialog: Project Name: pizza, top level package: com.springsource.roo.pizzashop&lt;/li&gt;&lt;li&gt;Accept all other defaults and press Next (and then Finish). This will create the Roo project and open the roo shell. Actually, STS is executing the roo shell to create the project directory and the roo command: &lt;blockquote&gt;roo&amp;gt; project --topLevelPackage com.springsource.roo.pizzashop&lt;/blockquote&gt;&lt;/li&gt;&lt;/ol&gt;We see the ROO command shell at the bottom with a command promt inviting us to execute roo commands. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://2.bp.blogspot.com/-yVj8ScfOu7g/TjVU5XzFB1I/AAAAAAAAAFE/yqjrgCFGEGM/s1600/sts-roo-shell-typehere.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 112px;" src="http://2.bp.blogspot.com/-yVj8ScfOu7g/TjVU5XzFB1I/AAAAAAAAAFE/yqjrgCFGEGM/s320/sts-roo-shell-typehere.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5635503853341574994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The window has a top part showing a console with roo commands as well as a prompt, but don't be fooled. The roo prompt we use in StS is below (a single line edit).&lt;br /&gt;The spring ROO project leverages Maven2 and its unique project structure. &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;One cool roo command you will use right away is hint. This will give you possible options to do from the point in your project. In this case, &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;type HINT and press enter, Roo Shell will respond with a suggestion to do 'persistence setup'&lt;/li&gt;&lt;li&gt;type' persitence setup' and press ctrl+space. In StS, this will use code assist to allow you to select possible next options for the command (the command line, you press the TAB key). In this case we will select --provider HIBERNATE and --database HYPERSONIC_IN_MEMORY&lt;/li&gt;&lt;li&gt;The complete roo command is: &lt;blockquote&gt;persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Roo will generate the JPA configuration files and initial spring context&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Next: Create an Entity&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Now we are ready to create some entities and fields&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Press Hint again, and Roo will advise you to type ent and press TAB to get the next option (from STS, ctrl+space). This will allow us to create an entity with a specific class name: Topping&lt;/li&gt;&lt;li&gt;Type entity then press (ctrl+space) . This will produce --class&lt;/li&gt;&lt;li&gt;Type ~.domain.Topping for the class name (the tilda will indicate the project's package root (remember we specified com.springsource.roo.pizzashop)&lt;/li&gt;&lt;li&gt;Now ctrl+space doesn't give us more hints since all required options are satisfied, but type double dash (--) and then ctrl+space will give us a bunch more options.&lt;/li&gt;&lt;li&gt;type or select --testAutomatically to generate test classes for the new entity and press enter (the ccomplete roo command: entity --class ~.domain.Topping --testAutomatically)&lt;/li&gt;&lt;/ol&gt;Roo creates a whole bunch of files and aspects. Notice the actual entity "SRC_MAIN_JAVA\com\springsource\roo\pizzashop\domain\Topping.java" is created. You can see it in the packag tree. However, STS starts with an inital filter in the package tree to 'Focus on Active Task'. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-NtOmLp1j11A/TjVV4L1hZZI/AAAAAAAAAFM/ejMwwVrR5as/s1600/sts-project-removefilter.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 117px; height: 320px;" src="http://1.bp.blogspot.com/-NtOmLp1j11A/TjVV4L1hZZI/AAAAAAAAAFM/ejMwwVrR5as/s320/sts-project-removefilter.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5635504932462355858" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Click the filter icon in the top toolbar of the Package view to reveal the entire project. Now navigate to src/main/java. See the com.springsource.roo.pizzashop.domain package and the created Topping.java class just created.&lt;/div&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Next: Create Fields for Our Entity&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Now lets add a field. Use the roo command to type field string --fieldName name --notnull --sizeMin 2&lt;br /&gt;THis will add a field, and update/add to the generated aspects based on the annotaitions.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Opening this class, all you see is&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[  &lt;br /&gt;package com.springsource.roo.pizzashop.domain;  &lt;br /&gt;import org.springframework.roo.addon.entity.RooEntity; &lt;br /&gt;import org.springframework.roo.addon.javabean.RooJavaBean; &lt;br /&gt;import org.springframework.roo.addon.tostring.RooToString; &lt;br /&gt;import javax.validation.constraints.NotNull; &lt;br /&gt;import javax.validation.constraints.Size;  &lt;br /&gt;@RooJavaBean &lt;br /&gt;@RooToString &lt;br /&gt;@RooEntity &lt;br /&gt;public class Topping { &lt;br /&gt;     @NotNull&lt;br /&gt;     @Size(min = 2)&lt;br /&gt;     private String name; &lt;br /&gt;} &lt;br /&gt;]]&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;Notice the classs annotations that roo adds @RooJavaBean, @RooToString and @RooEntity. These annotations generate aspects with extensions .aj for inter type definitions. Spring also adds JSR 303 bean validation annotations on the field based on the options we specified: @NotNull and @Size(min = 2).&lt;br /&gt;&lt;br /&gt;The principle that Roo introduces here is the heavy leveraging of AspectJ's Inter-Type Declaration (ITD). The ITD code generates as a separately complied file, but is encorporated into the class byte code of the advised class. Generally we don't need to bother about what is generated here. But lets look anyway. For instance, the @RooJavaBean annotaion creates the class Topping_Roo_JavaBean.aj. Peeking at it, we see:&lt;br /&gt;&lt;div&gt;File: Topping_Roo_Entity.aj&lt;br/&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[ &lt;br /&gt;// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. &lt;br /&gt;// You may push code into the target .java compilation unit if you wish to edit any member(s).  &lt;br /&gt;package com.springsource.roo.pizzashop.domain; &lt;br /&gt;&lt;br /&gt;import java.lang.String; &lt;br /&gt;&lt;br /&gt;privileged aspect Topping_Roo_JavaBean { &lt;br /&gt;    public String Topping.getName() { &lt;br /&gt;        return this.name; &lt;br /&gt;    }     &lt;br /&gt;&lt;br /&gt;    public void Topping.setName(String name) { &lt;br /&gt;        this.name = name; &lt;br /&gt;    }      &lt;br /&gt;}  &lt;br /&gt;&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;We see that the name field produced a getter and a setter for the field. As we add new fields, this aspect will be updated. Using aspects this way allows the domain class to remain particularly pure.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;As another example, lets look at what was generated for the @RooToString annotation:&lt;/div&gt;&lt;br /&gt;&lt;div&gt;File: Topping_Roo_ToString.aj&lt;br/&gt;&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[  &lt;br /&gt;package com.springsource.roo.pizzashop.domain;  &lt;br /&gt;import java.lang.String;  &lt;br /&gt;privileged aspect Topping_Roo_ToString {      &lt;br /&gt;    public String Topping.toString() { &lt;br /&gt;        StringBuilder sb = new StringBuilder(); &lt;br /&gt;        sb.append("Id: ").append(getId()).append(", "); &lt;br /&gt;        sb.append("Name: ").append(getName()).append(", "); &lt;br /&gt;        sb.append("Version: ").append(getVersion()); &lt;br /&gt;        return sb.toString(); &lt;br /&gt;    } &lt;br /&gt;} ]]&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Pretty nifty, huh! this is the Secret Sauce of Roo as described in &lt;a href="http://blog.springsource.com/2009/06/18/roo-part-3/"&gt;Ben Alex' Blog on Roo's Architecture&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Finally, lets' look at what Roo does with the @RooEntity declairation&lt;br /&gt;&lt;div&gt;File: Topping_Roo_Entity.aj&lt;br/&gt;&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[  &lt;br /&gt;// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO.&lt;br /&gt;// You may push code into the target .java compilation unit if you wish to edit any member(s).&lt;br /&gt;&lt;br /&gt;package com.springsource.roo.pizzashop.domain;&lt;br /&gt;&lt;br /&gt;import com.springsource.roo.pizzashop.domain.Topping;&lt;br /&gt;import java.lang.Integer;&lt;br /&gt;import java.lang.Long;&lt;br /&gt;import java.util.List;&lt;br /&gt;import javax.persistence.Column;&lt;br /&gt;import javax.persistence.Entity;&lt;br /&gt;import javax.persistence.EntityManager;&lt;br /&gt;import javax.persistence.GeneratedValue;&lt;br /&gt;import javax.persistence.GenerationType;&lt;br /&gt;import javax.persistence.Id;&lt;br /&gt;import javax.persistence.PersistenceContext;&lt;br /&gt;import javax.persistence.Version;&lt;br /&gt;import org.springframework.transaction.annotation.Transactional;&lt;br /&gt;&lt;br /&gt;privileged aspect Topping_Roo_Entity {&lt;br /&gt;    &lt;br /&gt;    declare @type: Topping: @Entity;&lt;br /&gt;    &lt;br /&gt;    @PersistenceContext&lt;br /&gt;    transient EntityManager Topping.entityManager;&lt;br /&gt;    &lt;br /&gt;    @Id&lt;br /&gt;    @GeneratedValue(strategy = GenerationType.AUTO)&lt;br /&gt;    @Column(name = "id")&lt;br /&gt;    private Long Topping.id;&lt;br /&gt;    &lt;br /&gt;    @Version&lt;br /&gt;    @Column(name = "version")&lt;br /&gt;    private Integer Topping.version;&lt;br /&gt;    &lt;br /&gt;    public Long Topping.getId() {&lt;br /&gt;        return this.id;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void Topping.setId(Long id) {&lt;br /&gt;        this.id = id;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public Integer Topping.getVersion() {&lt;br /&gt;        return this.version;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void Topping.setVersion(Integer version) {&lt;br /&gt;        this.version = version;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Transactional&lt;br /&gt;    public void Topping.persist() {&lt;br /&gt;        if (this.entityManager == null) this.entityManager = entityManager();&lt;br /&gt;        this.entityManager.persist(this);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Transactional&lt;br /&gt;    public void Topping.remove() {&lt;br /&gt;        if (this.entityManager == null) this.entityManager = entityManager();&lt;br /&gt;        if (this.entityManager.contains(this)) {&lt;br /&gt;            this.entityManager.remove(this);&lt;br /&gt;        } else {&lt;br /&gt;            Topping attached = Topping.findTopping(this.id);&lt;br /&gt;            this.entityManager.remove(attached);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Transactional&lt;br /&gt;    public void Topping.flush() {&lt;br /&gt;        if (this.entityManager == null) this.entityManager = entityManager();&lt;br /&gt;        this.entityManager.flush();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Transactional&lt;br /&gt;    public void Topping.clear() {&lt;br /&gt;        if (this.entityManager == null) this.entityManager = entityManager();&lt;br /&gt;        this.entityManager.clear();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Transactional&lt;br /&gt;    public Topping Topping.merge() {&lt;br /&gt;        if (this.entityManager == null) this.entityManager = entityManager();&lt;br /&gt;        Topping merged = this.entityManager.merge(this);&lt;br /&gt;        this.entityManager.flush();&lt;br /&gt;        return merged;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static final EntityManager Topping.entityManager() {&lt;br /&gt;        EntityManager em = new Topping().entityManager;&lt;br /&gt;        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");&lt;br /&gt;        return em;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static long Topping.countToppings() {&lt;br /&gt;        return entityManager().createQuery("SELECT COUNT(o) FROM Topping o", Long.class).getSingleResult();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static List&lt;Topping&gt; Topping.findAllToppings() {&lt;br /&gt;        return entityManager().createQuery("SELECT o FROM Topping o", Topping.class).getResultList();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static Topping Topping.findTopping(Long id) {&lt;br /&gt;        if (id == null) return null;&lt;br /&gt;        return entityManager().find(Topping.class, id);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static List&lt;Topping&gt; Topping.findToppingEntries(int firstResult, int maxResults) {&lt;br /&gt;        return entityManager().createQuery("SELECT o FROM Topping o", Topping.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;} ]]&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Rather than creating a data access object (DAO) or service, Roo assumes that each entity created has its own implementation of persistence. The @RooEntity annotation generates a ITD (Inter-type Declairation) for the entity advising it to add many methods to support persistence, inclding id generation, versioning, access to the entity manager, various transactional methods: &lt;ul&gt;&lt;br /&gt;&lt;li&gt;persist, &lt;br /&gt;&lt;li&gt;remove,&lt;br /&gt;&lt;li&gt;flush,&lt;br /&gt;&lt;li&gt;merge, &lt;br /&gt;&lt;li&gt;clear &lt;br /&gt;&lt;/ul&gt;and various finder methods&lt;ul&gt;&lt;br /&gt;&lt;li&gt;count&lt;br /&gt;&lt;li&gt;find by id&lt;br /&gt;&lt;li&gt;findAll&lt;br /&gt;&lt;li&gt;and pagable findAll&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Next: Some More entitles and fields&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;As Roo creates objects, it keeps track of the last object you created. The next command defaults to this target,  so there is no need to specify it explicitly. For example, when we created the field, we didn't need to specify what class to create the field for. It assumed we meant the last entity we worked with.. The spring Roo console shows what entity we last worked with in its prompt, much like a command shell might with a prompt showing the current directory path.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now lets create another entity and some fields similar to the ones we created before. Here are the Roo commands:&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[&lt;br /&gt;entity --class ~.domain.Base --testAutomatically&lt;br /&gt;field string --fieldName name --notNull --sizeMin 2&lt;br /&gt;entity --class ~.domain.Pizza --testAutomatically&lt;br /&gt;field string --fieldName name --notNull --sizeMin 2&lt;br /&gt;entity --class ~.domain.Pizza --testAutomatically&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-njzm5ccf5VU/TjVbD5_kggI/AAAAAAAAAFU/liMGlmQaAbw/s1600/sts-project-expandedentities1.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 118px; height: 320px;" src="http://3.bp.blogspot.com/-njzm5ccf5VU/TjVbD5_kggI/AAAAAAAAAFU/liMGlmQaAbw/s320/sts-project-expandedentities1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5635510631389233666" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;That's it. As long as we follow the defaults, things are easy. This is the approach taken by Ruby on Rails: convention over configuration. The command line invokes templated commands to create objects quickly. &lt;/div&gt;&lt;br /&gt;&lt;div&gt;Our project should look basically like this (as seen from the project view)&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Next: Some Relationships for our Entities&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;We are still in JPA land. JPA allows us to create relationships as well as if POJO java classes using well known collections. Roo supports a one-to-one or many-to-one reference, a one-to-many 'set' (and also ways to create many-many). In the above, we have a one-many relationship from Pizza to Topping (a pizza has many toppings) and a one-one relationship (reference) to a base. We'll use the Roo command shell to create these too. The tutorial shows there are two relationships from Pizza, a 'reference' to a base (m:1) where a Pizza has one base, and a set of toppings (m:m relationship to toppings), where a pizza has a set of toppings.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[&lt;br /&gt;field set --fieldName toppings --type ~.domain.Topping&lt;br /&gt;field reference --fieldName base --type ~.domain.Base&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;The above commands assume you are creating the relationship fields to the last entity you created: Pizza as it would show you in a command prompt. If not, make sure to append --class ~.domain.Pizza to the above commands (at least the first one) to assure the relationships are created for the Pizza class. &lt;br /&gt;And we can finish up with PizzaOrder&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[&lt;br /&gt;entity --class ~.domain.PizzaOrder --testAutomatically &lt;br /&gt;field string --fieldName name --notNull --sizeMin 2&lt;br /&gt;field string --fieldName address --sizeMax 30&lt;br /&gt;field number --fieldName total --type java.lang.Float &lt;br /&gt;field date --fieldName deliveryDate --type java.util.Date&lt;br /&gt;field set --fieldName pizzas --type ~.domain.Pizza&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Notice the last command creates another relationship, this time an PizzaOrder has a set of Pizzas ordered, which Roo will create a m:m relationship for of type Set pizzas. As you can see, creating entities, fields and relationships with Roo comes down to running a set of commands to generate the appropriate Java code and Aspects according to Roo convention. In fact, you can save these commands as a 'seed' text file that will create a project for you, generating the project structure, configruation, classes and aspects required.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Next: Lets Test&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;We can now run the integration tests using the roo command perform tests. &lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;perform tests&lt;/blockquote&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Finally: Look at the test classes generated&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-5935331876271808413?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/5935331876271808413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=5935331876271808413' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/5935331876271808413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/5935331876271808413'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2011/07/getting-started-with-spring-roo-gwt-and.html' title='Getting started with Spring Roo, GWT and STS'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-LGT52MfXiI4/TjWI-8sf3yI/AAAAAAAAAFc/-DVZ_A_PANk/s72-c/sts-createrooproject.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-7584099054584285593</id><published>2011-07-08T05:17:00.000-07:00</published><updated>2011-07-18T09:40:40.004-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Testing my RESTful controllers with Spring RESTtemplate</title><content type='html'>I have been playing with Spring's RESTtemplate as an approach to integration testing on my project.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Overview of Testing a RIA with Spring and Spring VMC&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;I feel I should create a set of blog posts related to how I am doing testing with this technology stack. Sometimes this aggregation is helpful. In my team, we are testing at the following levels:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;unit testing of everyting - pure tests, typically single class only, with mock (using &lt;a href="http://mockito.org/"&gt;Mockito&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;integration testing of our services - out of container (web server) testing, but with db&lt;br /&gt;&lt;/li&gt;&lt;li&gt;integration testing of our controllers - in container testing, with db&lt;br /&gt;&lt;/li&gt;&lt;li&gt;functional testing of our ui (TBD) - full in container testing&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;This blog will focus on integration testing.&lt;br /&gt;&lt;br /&gt;Integration testing, different from unit testing, tests the code as it is wired up to other components, the server and the data base as well. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Testing the controller layer in Spring MVC&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;To set the stage, I am using spring 3 with Spring MVC for my application. In particular, I am leveraging a lot of Ajax, accessing the controller from the browser and transporting JSON. I am using the &lt;a href="http://jackson.codehaus.org/"&gt;Jackson JSON mapping implementation&lt;/a&gt; to marshal to from beans to JSON.&lt;br /&gt;&lt;br /&gt;I need to create good integration tests of my controller classes so I can run JUnit tests that connect with the deployed web app and interact RESTfully like the client UI, passing JSON objects back and forth.&lt;br /&gt;&lt;br /&gt;A helpful blog post I have used for guidance: is &lt;a href="http://ralf.schaeftlein.de/2010/03/05/junit-tests-for-spring-3-rest-services/"&gt;ralf.schaeftlein s blog&lt;/a&gt; detailing an approach to integration testing of restful MVC controllers with JSON. Exactly what I was interested in.&lt;br /&gt;The basic steps seem to be:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;create a unit test with java4 leveraging &lt;a href="http://static.springsource.org/spring/docs/3.0.x/reference/testing.html#integration-testing"&gt;Spring 3 Integration Test Annotations&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;configure your application context XML to define your mappers that will convert between JSON and beans&lt;br /&gt;&lt;/li&gt;&lt;li&gt;write your tests pojo style&lt;/li&gt;&lt;/ol&gt;Integration Testing with Spring uses annotations to supply a spring context to your test code. Further, the annotations specify what transaction manager to use and if a rollback should be performed after the test is complete. The tests itself are written with JUnit4. Here is a snippet showing the annotations required placed on your test class.&lt;br /&gt;&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"file:src/test/resources/applicationContext-doc-test.xml"}) @TransactionConfiguration(transactionManager = "myTransactionManager", defaultRollback = true)&lt;br /&gt;@Transactional&lt;br /&gt;public class TestMyRepository {&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;In this case, I am testing my Data Repository, which is essentially my Data Access Object (DAO) for you old schoolers. I will post why Repositories and not DAO in a future blog.&lt;br /&gt;My application context file configures spring with the required setup for my application to run this test. First, the usual name spaces:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: xml"&gt;&lt;![CDATA[ &lt;br /&gt;&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;br /&gt;&lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"&lt;br /&gt; xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"&lt;br /&gt;         xmlns:context="http://www.springframework.org/schema/context"&lt;br /&gt;&lt;br /&gt; xsi:schemaLocation="http://www.springframework.org/schema/beans &lt;br /&gt;  http://www.springframework.org/schema/beans/spring-beans.xsd&lt;br /&gt;  http://www.springframework.org/schema/aop &lt;br /&gt;        http://www.springframework.org/schema/aop/spring-aop.xsd&lt;br /&gt;        http://www.springframework.org/schema/tx&lt;br /&gt;        http://www.springframework.org/schema/tx/spring-tx.xsd&lt;br /&gt;        http://www.springframework.org/schema/context&lt;br /&gt;        http://www.springframework.org/schema/context/spring-context.xsd"&gt;&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;Then, we use automatic annotation discovery of out project&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: js"&gt;&lt;![CDATA[ &lt;br /&gt;    &lt;context:annotation-config /&gt;&lt;br /&gt;    &lt;context:component-scan base-package="org.wentsoft.notable.domain" /&gt;&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;Here is wshere we configure the restTemplate to be used for this integration test of our controller&lt;script type="syntaxhighlighter" class="brush: js"&gt;&lt;![CDATA[ &lt;br /&gt;    &lt;bean id="restTemplate" class="org.springframework.web.client.RestTemplate"&gt;&lt;br /&gt;        &lt;property name="messageConverters"&gt;&lt;br /&gt;            &lt;list&gt;&lt;br /&gt;                &lt;bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"&gt;&lt;br /&gt;                    &lt;property name="supportedMediaTypes" value="application/json" /&gt;&lt;br /&gt;                &lt;/bean&gt;            &lt;br /&gt;            &lt;/list&gt;&lt;br /&gt;        &lt;/property&gt;&lt;br /&gt;    &lt;/bean&gt;&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;Finally the required configuration for our persistence. Notice we are using JPA configuration here&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: xml"&gt;&lt;![CDATA[ &lt;br /&gt;    &lt;bean id="myEMF" &lt;br /&gt;  class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"&gt;&lt;br /&gt;        &lt;property name="persistenceUnitName" value="test-pu" /&gt;&lt;br /&gt;    &lt;/bean&gt;&lt;br /&gt;&lt;br /&gt;    &lt;tx:annotation-driven transaction-manager="myTM" /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;bean id="myTM" class="org.springframework.orm.jpa.JpaTransactionManager"&gt;&lt;br /&gt;        &lt;property name="entityManagerFactory" ref="myEMF" /&gt;&lt;br /&gt;    &lt;/bean&gt;&lt;br /&gt;&lt;br /&gt;    &lt;bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /&gt;&lt;br /&gt;&lt;/beans&gt;&lt;br /&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Finnaly the test code.&lt;br /&gt;&lt;br /&gt;We write an integration test for our controller that connects remotely to the deployed application, sends beans mapped from Pojo to json for the call, and then maps back json to Pojo to assert results.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-7584099054584285593?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/7584099054584285593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=7584099054584285593' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/7584099054584285593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/7584099054584285593'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2011/07/testing-my-restful-controllers-with.html' title='Testing my RESTful controllers with Spring RESTtemplate'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-953733632829204639</id><published>2011-07-08T05:11:00.000-07:00</published><updated>2011-07-08T05:24:01.618-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTML5'/><title type='text'>A shout out to a framework for html5</title><content type='html'>One of my readers sent me a link to &lt;a href="http://www.strobecorp.com/"&gt;Strobe&lt;/a&gt;, (&lt;a href="http://www.strobecorp.com/"&gt;http://www.strobecorp.com/&lt;/a&gt;) an open source platform built from the ground up to leverage html5, but still leverage MVC. Although my ship has already left down the river of &lt;a href="http://www.springsource.org/"&gt;Spring&lt;/a&gt;, I can longingly look at its innovation and see what we can adopt for ourselves. I know I will loose a few hours this weekend on playing with this one. &lt;br /&gt;&lt;br /&gt;Thanks&lt;br /&gt;&lt;br /&gt;PS, I also seem to be wasting my time playing with knew language ides: ever check out &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt;. Yes, it talks with a lisp as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-953733632829204639?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/953733632829204639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=953733632829204639' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/953733632829204639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/953733632829204639'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2011/07/shout-out-to-framework-for-html5.html' title='A shout out to a framework for html5'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-6382001395864960024</id><published>2011-07-08T04:07:00.000-07:00</published><updated>2011-07-08T05:24:01.618-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTML5'/><title type='text'>Crossing the chasm to the new paradigm</title><content type='html'>I titled this post in homage to Moore, the author of &lt;a href="http://en.wikipedia.org/wiki/Crossing_the_Chasm"&gt;Crossing the Chasm&lt;/a&gt;. He clearly described how marketing strategies for high-tech are different from other product categories. He heavily leverages the &lt;a href="http://en.wikipedia.org/wiki/Technology_adoption_lifecycle"&gt;technology adoption life-cycle&lt;/a&gt; bell curve where Rogers et. al. segments people into 5 categories: &lt;ol&gt;&lt;li&gt;innovators, &lt;li&gt;early adopters, &lt;li&gt;early majority, &lt;li&gt;late majority and &lt;li&gt;laggards&lt;/ol&gt; (although the last category seems a bit offensive :)). Moore emphasizes that getting from early adopter to early majority is like crossing a chasm: the former 'visionaries' have very different expectations then the later 'pragmatists'. To mix authors (like metaphors), a '&lt;a href="http://en.wikipedia.org/wiki/The_Tipping_Point"&gt;tipping point&lt;/a&gt;' seems to be required to make the shift. &lt;br /&gt;So it is for developers: new ideas, languages and techniques come by all the time. Some jump in 'where angels dare to tread'. I seem to be the former. At least I like to think of myself as such. Others wait. Some are clearly risk averse, but I think for some, it is hard to let go of the 'it works, why change it' paradigm. Perhaps they are right. They are pragmatists, and by nature practical. But innovators and early adopters seem to reap benefits. Since the technology wave moves incesntly and swiftly, it is best to keep on its cusp, like a surfer, using its power and momentum to guide you on, lest you be left paddling to catch up, far behind.&lt;br /&gt;But many on my team aren't of the innovator ilk. Nor is my company. I work for a very large software company that should be on the leading edge, if not the bleeding edge of innovation adoption. But we're not. We suffer from a stifling bureaucracy (like most large companies or governments, dare I say), and a hefty dose of 'not built here' syndrome. Interestingly enough, by boss isn't a 'laggard' in any stretch of the imagination. He, however, bears the brunt of having to argue for the wacky ideas of his reports in front of very risk averse corporate gatekeepers. Sometimes he wins, sometimes not.&lt;br /&gt;But, within the team, it was surprising to me how shocked people were when I said, &lt;blockquote&gt;"we are not going to write JSP any more."&lt;/blockquote&gt; &lt;br /&gt;I'm sure some of the readers of this blog post (all 1 of you) might be shocked as well. But sometimes we need to be shocked. This is a broad and sweeping statement, but it is powerful, because it hints at our reliance on rendering the UI on the server.  And we shouldn't. This is heresy, and would have been foolish in the past. From early cgi and perl (remember those days) to the development of J2EE, the browser was considered a dumb reader of html, not a smart client platform like thick client apps or client server. Applets were to be that, not the browser. If not Applets, then flash, if not flash then... well, ... the browser. &lt;br /&gt;What is the browser today? Its not dumb. It's not just a reader. It is an operating system. It is a platform that has capabilities to run sophisticated programs delivered to it. HTML5, CSS3 and JavaScript are the languages it speaks. If you know the lingo, you can unleash a vast array of capabilities that just a couple of years before were left to the native or thick client world. &lt;br /&gt;So, my aha moment came when I realized that what we needed to do was to go back to the client server days. In those days, you had vast power of the desktop, its graphical and multimedia power and local storage capability. You connected to the server for data. Yes, business rules and shaping of data occurred on the server.  Certainly secure selection and delivery of data as well. It enforces transactionality and validity. It handles persistence and auditing. But its is never in the business of rendering the user interface--that's the client's job. &lt;br /&gt;Rendering UI on the server was the compromise required to deliver applications over the web. And it was worth it too. Not to wory about the client footprint, not to have to wait for support to install and configure the next version. immediate access to everything a mouse click away. It rocked our world. It changed our world. Thanks &lt;a href="http://en.wikipedia.org/wiki/Tim_Berners-Lee"&gt;Tim&lt;/a&gt; for that. But he was thinking hyperlinked books after all, not applications. It was amazing what we can do even with its obvious limitations. And Tim has moved on too.&lt;br /&gt;&lt;br /&gt;But we no longer need to make this compromise. We can benefit from the zero footprint immediate access to all the worlds knowledge and applications but still leverage graphics, multimedia, processing power and even local storage of the desktop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-6382001395864960024?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/6382001395864960024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=6382001395864960024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6382001395864960024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6382001395864960024'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2011/07/crossing-chasm-to-new-paradigm.html' title='Crossing the chasm to the new paradigm'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-4211239314084279112</id><published>2011-07-06T23:26:00.000-07:00</published><updated>2011-07-08T05:24:01.618-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTML5'/><title type='text'>Fun with HTML5</title><content type='html'>I guess I'm a bit late to the game. However, perhaps not too late. &lt;a href="http://en.wikipedia.org/wiki/HTML5"&gt;HTML5&lt;/a&gt; offers a host of solutions for the kind of application I want to build: rich client, local storage, animated, etc. I walked through several &lt;a href="http://html5-demos.appspot.com/"&gt;HTML5 demos&lt;/a&gt; and examples over the weekend.&lt;div&gt;I can deliver a rich client experience for an application needing local only storage with nothing but HTML5, JavaScript and CSS3. But for real 'client server' or mashups with shared information, we still need connectivity to the server (Ajax based, RESTful, transport in JSON). &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: js"&gt;&lt;![CDATA[&lt;br /&gt;var xhr = new XMLHttpRequest();&lt;br /&gt;xhr.open('GET', '/path/to/image.png', true);&lt;br /&gt;&lt;br /&gt;xhr.responseType = 'arraybuffer';&lt;br /&gt;&lt;br /&gt;xhr.onload = function(e) {&lt;br /&gt;if (this.status == 200) {&lt;br /&gt;&lt;br /&gt;  var uInt8Array = new Uint8Array(this.response); // Note: not xhr.responseText&lt;br /&gt;&lt;br /&gt;  var byte3 = uInt8Array[4]; // byte at offset 4&lt;br /&gt;}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;xhr.send(); &lt;br /&gt;]]&gt;&lt;/script&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-4211239314084279112?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/4211239314084279112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=4211239314084279112' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4211239314084279112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4211239314084279112'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2011/07/fun-with-html5.html' title='Fun with HTML5'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-5899186221700897295</id><published>2011-07-03T07:13:00.000-07:00</published><updated>2011-07-08T05:24:42.386-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>New Technology Stack</title><content type='html'>In my real life, I actually have to deliver software :). So most of my blogs are about the technologies I am using today as well as best practices I am actually practicing (or trying to practice) in my real life.&lt;div&gt;This blog will focus on the following technology stack for now:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://jquery.com/"&gt;JQuery&lt;/a&gt; and &lt;a href="http://jqueryui.com/"&gt;JQuery UI&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CCAQFjAA&amp;amp;url=http%3A%2F%2Fwww.springsource.org%2F&amp;amp;ei=RnoQTvLjGpC40AGg8YSXDg&amp;amp;usg=AFQjCNFJ5T0SOhZD5Qea_gMApqPC3dq_jQ"&gt;Spring&lt;/a&gt; and&lt;a href="http://static.springsource.org/docs/Spring-MVC-step-by-step/"&gt; Spring MVC&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikibooks.org/wiki/Java_Persistence"&gt;Java Persistence API (JPA 2.0)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Also I will be looking at:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.springsource.org/roo"&gt;Spring Roo&lt;/a&gt; &lt;/li&gt;&lt;li&gt;and &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT (Google Web Toolkit)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Some techniques and tools include&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Sun NetBeans IDE&lt;/li&gt;&lt;li&gt;SpringSource Tool Suite&lt;/li&gt;&lt;li&gt;Test Driven Development&lt;/li&gt;&lt;li&gt;Continuous Integration&lt;/li&gt;&lt;li&gt;Maven&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-5899186221700897295?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/5899186221700897295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=5899186221700897295' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/5899186221700897295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/5899186221700897295'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2011/07/new-technology-stack.html' title='New Technology Stack'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-647422452529023699</id><published>2011-07-03T06:19:00.000-07:00</published><updated>2011-07-03T07:12:03.723-07:00</updated><title type='text'>Back again and focusing on Enterprise 2.0</title><content type='html'>&lt;div&gt;Why did I rename this blog Enterprise 2.0 Appplication Tecchnologies?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I am not abandoning ECM and SOA, but I am expanding to incorporate a more generalized concern.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;To me, enterprise 2.0 is bringing the promise of web 2.0 to enterprise applications. Not just in providing a better social experience, but providing a better user experience in general, with more user centered and natural user interfaces.&lt;br /&gt;&lt;br /&gt;Since Sun quoted "the network is the computer", many (myself included) have been trying to find a way to build enterprise applications that have a rich client experience but are not locked into a heavy installation footprint. Conventional web development has allowed us to build Software as a Service (SaaS), minimizing client and installation requirements and maximizing availability. But on the other hand, these applications are typically designed for the least-common-denominator, heavy on server side processing, have very unnatural user experiences, are constructed with a cacophony of languages, and tend to be a slave to bandwidth and availability of the network.&lt;br /&gt;&lt;br /&gt;An ignorant corporate sponsor might ask "Why can't we have the rich user experience of the desktop while leveraging the ubiquity of the web?"&lt;br /&gt;&lt;br /&gt;Well, now we can. Through the power of JavaScript and HTML5 the browser can support truly rich client experiences, while still leveraging the advantages of the web and being available anytime, anywhere on any device. Constructing access to information and actions using the power of REST and semantic net, different user experiences can be developed to share and leverage the knowledge of the enterprise in different ways. And still the enterprise applications can leverage well tested legacy services, be secure and achieve the availability and performance requirements demanded by the corporation.&lt;br /&gt;&lt;br /&gt;However, I am still concerned with requiring constant connectivity. Most of even the best internet applications that deal with transitional data require continuous high bandwidth connectivity to the services. Especially for the mobile worker (an ever increrasing demographic), being able to work 'off-line' sometimes is essential.&lt;br /&gt;&lt;br /&gt;So, my search for the answer to the question "Why can't we have the rich user experience of the desktop while leveraging the ubiquity of the web?" includes the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Rich client experience supporting many user types and many devices, including the use of graphics, multimedia and alternate input technologies&lt;/li&gt;&lt;li&gt;Secure access to semantically rich resources and services that are flexible and can be leveraged from many different clients&lt;/li&gt;&lt;li&gt;Connectivity to other legacy systems and services, supporting synchronous and asynchronous models&lt;/li&gt;&lt;li&gt;Mechanisms that allow users to share and collaborate and work off-line as well as on line&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;We want secure access to corporation's transactional information and services available at any time, from anywhere on any device, while allowing users to organize their own experiences and collaborate with others the way they want to.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The purpose of this blog is to try to address these concerns and others through technology available today, relevant to my own direct work requirements as well as the purely theoretical.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-647422452529023699?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/647422452529023699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=647422452529023699' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/647422452529023699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/647422452529023699'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2011/07/back-again-and-focusing-on-enterprise.html' title='Back again and focusing on Enterprise 2.0'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-426658157014384813</id><published>2010-02-04T07:52:00.000-08:00</published><updated>2010-02-04T08:41:28.005-08:00</updated><title type='text'>Moving On</title><content type='html'>I am shifting my focus in my career from Enterprise Content Management with Service Oriented Architectures to more Service Oriented Architectures and &lt;a href="http://en.wikipedia.org/wiki/Rich_Internet_application"&gt;Rich Internet Application&lt;/a&gt; development.  I will be focusing on the &lt;a href="http://www.oracle.com/us/products/middleware/index.htm"&gt;Oracle Fusion Middleware&lt;/a&gt; stack, not &lt;a href="http://www.alfresco.com/"&gt;Alfresco&lt;/a&gt;, &lt;a href="http://www.jboss.com/products/jbpm/"&gt;jBPM &lt;/a&gt;and &lt;a href="http://servicemix.apache.org/home.html"&gt;ServiceMix&lt;/a&gt;. I will be developing applications using Oracle JDeveloper tools with &lt;a href="http://www.oracle.com/technology/products/adf/index.html"&gt;Oracle's Application Development Framework (ADF)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, I will continue to use this blog, but I will be shifting articles to talk about these technologies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-426658157014384813?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/426658157014384813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=426658157014384813' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/426658157014384813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/426658157014384813'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2010/02/moving-on.html' title='Moving On'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-9103276345253959177</id><published>2009-07-07T08:00:00.001-07:00</published><updated>2009-07-08T08:04:32.276-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Forms Engine'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='Share 3.2 preview'/><title type='text'>Looking at Alfresco Share 3.2 Community - Part 3 - Customizing forms</title><content type='html'>This blog will look at how to display custom types and aspects in Share in the edit metadata feature. The &lt;a href="http://edlovesjava.blogspot.com/2009/06/looking-at-share-32-community-part-2.html"&gt;previous blog article&lt;/a&gt; showed how to associate content with predefined aspects and show them in the edit metadata form.&lt;br /&gt;&lt;br /&gt;This example requires &lt;a href="http://wiki.alfresco.com/wiki/Download_Labs_Preview"&gt;Alfresco 3.2 Labs&lt;/a&gt; (currently Preview).&lt;br /&gt;&lt;br /&gt;Resources:&lt;br /&gt;* &lt;a href="http://wiki.alfresco.com/wiki/Forms"&gt;Alfresco forms engine wiki page&lt;/a&gt;&lt;br /&gt;* &lt;a href="http://wiki.alfresco.com/wiki/Forms_Examples#Configuring_A_Form_Control"&gt;Alfresco forms engine examples wiki page&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Also see my previous blog entries showing how &lt;a href="http://edlovesjava.blogspot.com/2009/06/looking-at-share-32-community-part-2.html"&gt;forms are used in Alfresco Share 3.2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I will use the example project structure offered by Jeff Potts' great article - &lt;a href="http://ecmarchitect.com/archives/2007/06/09/756"&gt;Extending the Alfresco Content model&lt;/a&gt; to extend the content model in Alfresco. For the share customization, I will base my project on the &lt;a href="http://edlovesjava.blogspot.com/2008/12/extending-share-1-creating-share.html"&gt;Share extension project example&lt;/a&gt; in my blog.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Creating the new Custom content type&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For this example, I will create a custom content type and modify the edit metadata form shown in Alfresco Share.  The content type I will create will center around a custom type called MarketingContent, with an additional Aspect called Brandable. This custom metadata will add the ability to identify the 'brand' to which the Marketing content should be associated, and will require a custom single-select drop down.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_QVQz3EsVFfA/SlOR9jdleoI/AAAAAAAAAD4/3DSbFa4sAZQ/s1600-h/example_content_model.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 292px;" src="http://1.bp.blogspot.com/_QVQz3EsVFfA/SlOR9jdleoI/AAAAAAAAAD4/3DSbFa4sAZQ/s320/example_content_model.png" alt="" id="BLOGGER_PHOTO_ID_5355784868551031426" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 1 - Setup the project to extend Alfresco with custom content&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. Download &lt;a href="http://ecmarchitect.com/"&gt;Jeff Potts&lt;/a&gt;' &lt;a href="http://ecmarchitect.com/images/articles/alfresco-content/content-article-project.zip"&gt;custom content example source&lt;/a&gt;&lt;br /&gt;2. Import into Eclipse - assume you already downloaded the Alfresco SDK and imported SDK AlfrescoRemote&lt;br /&gt;3. Fix project references as needed&lt;br /&gt;4. Update build.properties for ant build (alfresco.sdk.remote.home and alfresco.web.root)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 2 - Modify project for new custom content model&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Four files to modify:&lt;br /&gt;* PROJECT_HOME/src/alfresco/extension/someco-model-content.xml&lt;br /&gt;* PROJECT_HOME/src/alfresco/extension/scModel.xml&lt;br /&gt;* PROJECT_HOME/src/alfresco/extension/web-client-config-custom.xml&lt;br /&gt;* PROJECT_HOME/src/alfresco/extension/webclient.properties&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;someco-model-content.xml (renamed to 'orbitz-model-content.xml')&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;beans&amp;gt;&lt;br /&gt;&amp;lt;!-- Registration of new models --&amp;gt;&lt;br /&gt;&amp;lt;bean id="extension.dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap"&amp;gt;&lt;br /&gt;&amp;lt;property name="models"&amp;gt;&lt;br /&gt;&amp;lt;list&amp;gt;&lt;br /&gt;   &amp;lt;value&amp;gt;alfresco/extension/orbModel.xml&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;/list&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;scModel.xml (renamed to 'orbModel.xml')&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!-- Definition of new Model --&amp;gt;&lt;br /&gt;&amp;lt;model name="orb:orbitzmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Optional meta-data about the model --&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;Orbitz Marketing Model&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;author&amp;gt;Ed Wentworth&amp;lt;/author&amp;gt;&lt;br /&gt;&amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Imports are required to allow references to definitions in other models --&amp;gt;&lt;br /&gt;&amp;lt;imports&amp;gt;&lt;br /&gt;  &amp;lt;!-- Import Alfresco Dictionary Definitions --&amp;gt;&lt;br /&gt;  &amp;lt;import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" /&amp;gt;&lt;br /&gt;  &amp;lt;!-- Import Alfresco Content Domain Model Definitions --&amp;gt;&lt;br /&gt;  &amp;lt;import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" /&amp;gt;&lt;br /&gt;&amp;lt;/imports&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Introduction of new namespaces defined by this model --&amp;gt;&lt;br /&gt;&amp;lt;namespaces&amp;gt;&lt;br /&gt;  &amp;lt;namespace uri="http://www.orbitz.com/model/content/1.0" prefix="orb" /&amp;gt;&lt;br /&gt;&amp;lt;/namespaces&amp;gt;&lt;br /&gt;&amp;lt;constraints&amp;gt;&lt;br /&gt;  &amp;lt;constraint name="orb:brands" type="LIST"&amp;gt;&lt;br /&gt;      &amp;lt;parameter name="allowedValues"&amp;gt;&lt;br /&gt;          &amp;lt;list&amp;gt;&lt;br /&gt;              &amp;lt;value&amp;gt;Orbitz&amp;lt;/value&amp;gt;&lt;br /&gt;              &amp;lt;value&amp;gt;CheapTickets&amp;lt;/value&amp;gt;&lt;br /&gt;              &amp;lt;value&amp;gt;eBookers&amp;lt;/value&amp;gt;&lt;br /&gt;          &amp;lt;/list&amp;gt;&lt;br /&gt;      &amp;lt;/parameter&amp;gt;&lt;br /&gt;      &amp;lt;parameter name="caseSensitive"&amp;gt;&amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;&amp;lt;/parameter&amp;gt;&lt;br /&gt;  &amp;lt;/constraint&amp;gt;&lt;br /&gt;&amp;lt;/constraints&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;types&amp;gt;&lt;br /&gt;  &amp;lt;!-- Enterprise-wide generic document type --&amp;gt;&lt;br /&gt;  &amp;lt;type name="orb:doc"&amp;gt;&lt;br /&gt;      &amp;lt;title&amp;gt;Orbitz Document&amp;lt;/title&amp;gt;&lt;br /&gt;      &amp;lt;parent&amp;gt;cm:content&amp;lt;/parent&amp;gt;&lt;br /&gt;      &amp;lt;mandatory-aspects&amp;gt;&lt;br /&gt;        &amp;lt;aspect&amp;gt;cm:generalclassifiable&amp;lt;/aspect&amp;gt;&lt;br /&gt;      &amp;lt;/mandatory-aspects&amp;gt;&lt;br /&gt;  &amp;lt;/type&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;type name="orb:marketing_content"&amp;gt;&lt;br /&gt;      &amp;lt;title&amp;gt;Orbitz Marketing Content&amp;lt;/title&amp;gt;&lt;br /&gt;      &amp;lt;parent&amp;gt;orb:doc&amp;lt;/parent&amp;gt;&lt;br /&gt;      &amp;lt;properties&amp;gt;&lt;br /&gt;          &amp;lt;property name="orb:effective_from"&amp;gt;&lt;br /&gt;              &amp;lt;type&amp;gt;d:date&amp;lt;/type&amp;gt;&lt;br /&gt;          &amp;lt;/property&amp;gt;&lt;br /&gt;          &amp;lt;property name="orb:effective_to"&amp;gt;&lt;br /&gt;              &amp;lt;type&amp;gt;d:date&amp;lt;/type&amp;gt;&lt;br /&gt;          &amp;lt;/property&amp;gt;&lt;br /&gt;      &amp;lt;/properties&amp;gt;&lt;br /&gt;  &amp;lt;/type&amp;gt;&lt;br /&gt;&amp;lt;/types&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;aspects&amp;gt;&lt;br /&gt;  &amp;lt;aspect name="orb:brandable"&amp;gt;&lt;br /&gt;      &amp;lt;title&amp;gt;Orbitz Brandable&amp;lt;/title&amp;gt;&lt;br /&gt;      &amp;lt;properties&amp;gt;&lt;br /&gt;          &amp;lt;property name="orb:brand"&amp;gt;&lt;br /&gt;              &amp;lt;type&amp;gt;d:text&amp;lt;/type&amp;gt;&lt;br /&gt;              &amp;lt;mandatory&amp;gt;true&amp;lt;/mandatory&amp;gt;&lt;br /&gt;              &amp;lt;constraints&amp;gt;&lt;br /&gt;                  &amp;lt;constraint ref="orb:brands"/&amp;gt;&lt;br /&gt;              &amp;lt;/constraints&amp;gt;&lt;br /&gt;          &amp;lt;/property&amp;gt;          &lt;br /&gt;      &amp;lt;/properties&amp;gt;&lt;br /&gt;  &amp;lt;/aspect&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/aspects&amp;gt;&lt;br /&gt;&amp;lt;/model&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;web-client-config-custom.xml&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;alfresco-config&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--  add webable aspect properties to property sheet --&amp;gt;&lt;br /&gt;&amp;lt;config evaluator="aspect-name" condition="orb:brandable"&amp;gt;&lt;br /&gt;  &amp;lt;property-sheet&amp;gt;&lt;br /&gt;      &amp;lt;show-property name="orb:brand" display-label-id="brand" /&amp;gt;&lt;br /&gt;  &amp;lt;/property-sheet&amp;gt;&lt;br /&gt;&amp;lt;/config&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- show related documents association on doc property sheet --&amp;gt;&lt;br /&gt;&amp;lt;config evaluator="node-type" condition="orb:doc"&amp;gt;&lt;br /&gt;  &amp;lt;property-sheet&amp;gt;&lt;br /&gt;  &amp;lt;/property-sheet&amp;gt;&lt;br /&gt;&amp;lt;/config&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- show related documents association on whitepaper property sheet --&amp;gt;&lt;br /&gt;&amp;lt;config evaluator="node-type" condition="orb:marketing_content"&amp;gt;&lt;br /&gt;  &amp;lt;property-sheet&amp;gt;&lt;br /&gt;      &amp;lt;show-property name="orb:effective_from" display-label-id="effective_from" /&amp;gt;&lt;br /&gt;      &amp;lt;show-property name="orb:effective_to" display-label-id="effective_to" /&amp;gt;&lt;br /&gt;  &amp;lt;/property-sheet&amp;gt;&lt;br /&gt;&amp;lt;/config&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--  add orbitz types to add content list --&amp;gt;&lt;br /&gt;&amp;lt;config evaluator="string-compare" condition="Content Wizards"&amp;gt;&lt;br /&gt;  &amp;lt;content-types&amp;gt;&lt;br /&gt;      &amp;lt;type name="orb:doc" /&amp;gt;&lt;br /&gt;      &amp;lt;type name="orb:marketing_content" /&amp;gt;&lt;br /&gt;  &amp;lt;/content-types&amp;gt;&lt;br /&gt;&amp;lt;/config&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;config evaluator="string-compare" condition="Action Wizards"&amp;gt;&lt;br /&gt;  &amp;lt;!-- The list of aspects to show in the add/remove features action --&amp;gt;&lt;br /&gt;  &amp;lt;!-- and the has-aspect condition --&amp;gt;&lt;br /&gt;  &amp;lt;aspects&amp;gt;&lt;br /&gt;      &amp;lt;aspect name="orb:brandable"/&amp;gt;&lt;br /&gt;  &amp;lt;/aspects&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;!-- The list of types shown in the is-subtype condition --&amp;gt;&lt;br /&gt;  &amp;lt;subtypes&amp;gt;&lt;br /&gt;      &amp;lt;type name="orb:doc" /&amp;gt;&lt;br /&gt;      &amp;lt;type name="orb:marketing_content" /&amp;gt;&lt;br /&gt;  &amp;lt;/subtypes&amp;gt;  &lt;br /&gt;&lt;br /&gt;  &amp;lt;!-- The list of content and/or folder types shown in the specialise-type action --&amp;gt;&lt;br /&gt;  &amp;lt;specialise-types&amp;gt;&lt;br /&gt;      &amp;lt;type name="orb:doc" /&amp;gt;&lt;br /&gt;      &amp;lt;type name="orb:marketing_content" /&amp;gt;&lt;br /&gt;  &amp;lt;/specialise-types&amp;gt;  &lt;br /&gt;&amp;lt;/config&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;config evaluator="string-compare" condition="Advanced Search"&amp;gt;&lt;br /&gt;  &amp;lt;advanced-search&amp;gt;&lt;br /&gt;      &amp;lt;content-types&amp;gt;&lt;br /&gt;          &amp;lt;type name="orb:doc" /&amp;gt;&lt;br /&gt;          &amp;lt;type name="orb:marketing_content" /&amp;gt;&lt;br /&gt;      &amp;lt;/content-types&amp;gt;&lt;br /&gt;      &amp;lt;custom-properties&amp;gt;&lt;br /&gt;          &amp;lt;meta-data aspect="orb:brandable" property="orb:brand" display-label-id="brand" /&amp;gt;&lt;br /&gt;      &amp;lt;/custom-properties&amp;gt;&lt;br /&gt;  &amp;lt;/advanced-search&amp;gt;&lt;br /&gt;&amp;lt;/config&amp;gt;&lt;br /&gt;&amp;lt;/alfresco-config&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;webclient.properties&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;#orb:marketing_content&lt;br /&gt;effective_from=Effective From&lt;br /&gt;effective_to=Effective To&lt;br /&gt;&lt;br /&gt;#orb:brandable&lt;br /&gt;brand=Brand&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 3 - Deploy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Make sure that build.properties is properly configured&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Run ant deploy&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 4 - Test Model&lt;/span&gt;&lt;br /&gt;As a prerequisite, you should go to Share client and create a new site (i.e. 'Merchandising')&lt;br /&gt;&lt;ol&gt;&lt;li&gt;In Alfresco Explorer client - Upload content as type 'Marketing Content'&lt;/li&gt;&lt;li&gt;Apply 'Brandable' aspect&lt;/li&gt;&lt;li&gt;Modify content propertis -- should look like picture below&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QVQz3EsVFfA/SlOQ0Nm0x1I/AAAAAAAAADw/dDPP9uOmQjA/s1600-h/example-custom-model-prop-sheet.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 262px;" src="http://2.bp.blogspot.com/_QVQz3EsVFfA/SlOQ0Nm0x1I/AAAAAAAAADw/dDPP9uOmQjA/s320/example-custom-model-prop-sheet.png" alt="" id="BLOGGER_PHOTO_ID_5355783608553752402" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;In order for this form to render, we need to modify the forms configuration to let Share know how to render our custom type and aspect. For details on this, see the &lt;a href="http://wiki.alfresco.com/wiki/Forms"&gt;forms wiki&lt;/a&gt; and &lt;a href="http://wiki.alfresco.com/wiki/Forms_Examples"&gt;forms examples&lt;/a&gt; wiki pages.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 5: Configure share to render the orb:market_content type and orb:brandable aspect&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Create a file named &lt;i&gt;'web-framework-config-custom.xml'&lt;/i&gt; and deploy it to the share/WEB-INF/classes/alfresco/web-extension directory with the contents:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;alfresco-config&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;config evaluator="node-type" condition="orb:marketing_content"&amp;gt;&lt;br /&gt;    &amp;lt;forms&amp;gt;&lt;br /&gt;       &amp;lt;form&amp;gt;&lt;br /&gt;          &amp;lt;field-visibility&amp;gt;&lt;br /&gt;             &amp;lt;!-- inherited from cm:content --&amp;gt;&lt;br /&gt;             &amp;lt;show id="cm:name" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="cm:title" force="true" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="cm:description" force="true" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="mimetype" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="cm:author" force="true" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="size" for-mode="view" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="cm:creator" for-mode="view" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="cm:created" for-mode="view" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="cm:modifier" for-mode="view" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="cm:modified" for-mode="view" /&amp;gt;&lt;br /&gt;           &lt;br /&gt;             &amp;lt;!--  specific for orb:marketing_content --&amp;gt;&lt;br /&gt;             &amp;lt;show id="orb:effective_from" /&amp;gt;&lt;br /&gt;             &amp;lt;show id="orb:effective_to" /&amp;gt;&lt;br /&gt;&lt;br /&gt;             &amp;lt;!--  aspect orb:brandable --&amp;gt;             &lt;br /&gt;             &amp;lt;show id="orb:brand" /&amp;gt;&lt;br /&gt;           &lt;br /&gt;          &amp;lt;/field-visibility&amp;gt;&lt;br /&gt;          &amp;lt;appearance&amp;gt;&lt;br /&gt;             &amp;lt;field id="orb:effective_from" label="Effective From"/&amp;gt;&lt;br /&gt;             &amp;lt;field id="orb:effective_to" label="Effective To"/&amp;gt;&lt;br /&gt;             &amp;lt;field id="orb:brand" label="Brand"&amp;gt;&lt;br /&gt;                &amp;lt;control template="controls/selectone.ftl"&amp;gt;&lt;br /&gt;                   &amp;lt;control-param name="options"&amp;gt;Orbitz,CheapTickets,eBookers&amp;lt;/control-param&amp;gt;&lt;br /&gt;                &amp;lt;/control&amp;gt;&lt;br /&gt;             &amp;lt;/field&amp;gt;&lt;br /&gt;          &amp;lt;/appearance&amp;gt;&lt;br /&gt;       &amp;lt;/form&amp;gt;&lt;br /&gt;    &amp;lt;/forms&amp;gt;&lt;br /&gt; &amp;lt;/config&amp;gt;&lt;br /&gt;&amp;lt;/alfresco-config&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As we see here, we needed to copy all of the default properties from cm:content as well as add our unique properties for orb:marketing_content, and add the orb:brands aspect. This gives us very fine-grained control, but we can see there could be a lot of repeated configurations if we use types with aspects in complex ways.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 5: Run the example&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we can go ahead and restart share and log in and select 'edit metadata' of our content previously checked in with the type orb:marketing_content and set with the orb:brandable aspect.&lt;br /&gt;&lt;br /&gt;Now we should see the following:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QVQz3EsVFfA/SlSytVb-yPI/AAAAAAAAAEA/24l4WzPaIuU/s1600-h/example-custom-model-share-prop-sheet.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 275px;" src="http://2.bp.blogspot.com/_QVQz3EsVFfA/SlSytVb-yPI/AAAAAAAAAEA/24l4WzPaIuU/s320/example-custom-model-share-prop-sheet.png" alt="" id="BLOGGER_PHOTO_ID_5356102348768725234" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We customized the selectone.ftl control template to provide our list of brands. One can consider an extension to this control would be to look up this list from a data web-script.&lt;br /&gt;&lt;br /&gt;We should create our own selectone lookup from an external source in an ajax way. We will do so in a further blog article.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-9103276345253959177?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/9103276345253959177/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=9103276345253959177' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/9103276345253959177'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/9103276345253959177'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2009/07/alfresco-forms-engine-customization.html' title='Looking at Alfresco Share 3.2 Community - Part 3 - Customizing forms'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QVQz3EsVFfA/SlOR9jdleoI/AAAAAAAAAD4/3DSbFa4sAZQ/s72-c/example_content_model.png' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-3812886361656042731</id><published>2009-06-30T10:46:00.001-07:00</published><updated>2009-07-08T08:04:18.352-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Forms Engine'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='Share 3.2 preview'/><title type='text'>Looking at Alfresco Share 3.2 Community - Part 2 - Edit Custom Metadata</title><content type='html'>This series of blog entries is intended to walk through the new features of Alfresco Share 3.2 Labs. In the &lt;a href="http://edlovesjava.blogspot.com/2009/06/looking-at-share-32-community.html"&gt;previous blog entry&lt;/a&gt;, I built the community version from source, and looked at the new Admin Console feature. This blog, I will look at how Share exposes Custom metadata, and allows users to assign aspects to uploaded content.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt; &lt;span style="font-weight: bold;"&gt;Viewing and Editing Custom Metadata&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;I have Alfresco 3.2 Labs running on my Windows XP Laptop, built from source updated June 23, 2009, and I have deployed both Alfrsco.war and share.war to an instance of Tomcat 6.&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;In previous versions of Share, it wasn't possible to view or edit custom metadata. Share 3.2 Labs addresses this deficit. Further, it leverages Surf's new forms architecture to render the metadata form dynamically. We will look at this in detail later. First, I will walk through the user interface for metadata.&lt;br /&gt;&lt;br /&gt;In order to show Share's ability to view custom metadata, we need to create a new Site and Upload some content. Here are the steps briefly:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Log into Share (as admin/admin) --&gt; The User Dashboard renders with the 'My Sites' dashlet.&lt;/li&gt;&lt;li&gt;Click on 'Create Site' in the My Sites dashlet (or select 'create site' from the 'Sites' drop down in the top menu) --&gt; The Create Site popup will render.&lt;/li&gt;&lt;li&gt;Enter the Name, URL name, and Description (optional) of this new site. (In my example I created a site with Name=Merchandising, URL name=Merchandising).&lt;/li&gt;&lt;li&gt;Press 'Ok' when complete and the new site will be created, returning you to the user dashboard.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Select the new site from the 'My Sites' dashlet, or the top menu's Sites dropdown --&gt; the Site dashboard will render.&lt;/li&gt;&lt;li&gt;Navigate to the 'Document Library' page to upload new content --&gt; the Document Library page renders.&lt;/li&gt;&lt;li&gt;Click on 'Upload' button to upload some content to the default documents folder.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Now that we have content, we should be able to view the metadata.&lt;br /&gt;&lt;br /&gt;Here I am looking at Document Library in the merchandising site, where have uploaded an XML file and a couple of image files...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QVQz3EsVFfA/SkpTKbqZCLI/AAAAAAAAADA/QImjjbQnjD0/s1600-h/share32-doclib.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 275px;" src="http://3.bp.blogspot.com/_QVQz3EsVFfA/SkpTKbqZCLI/AAAAAAAAADA/QImjjbQnjD0/s320/share32-doclib.png" alt="" id="BLOGGER_PHOTO_ID_5353182545772611762" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Hovering over one of the files in the list renders the actions that can be performed on that file.&lt;br /&gt;Actions include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Download&lt;/li&gt;&lt;li&gt;Edit Metadata&lt;/li&gt;&lt;li&gt;Upload new Version&lt;/li&gt;&lt;li&gt;More &gt; (we will look at some of these later)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;This list of actions is very configurable. We may show how to do this in a later blog.&lt;br /&gt;The 'Edit Metadata' action is what we want. Select the 'Edit Metadata' action for the uploaded document.&lt;br /&gt;&lt;br /&gt;Here I selected edit metadata for an XML ddocument named 'Article.EnableCookies.xml'...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_QVQz3EsVFfA/SkpU0GIT9xI/AAAAAAAAADQ/Aj7VzYcY7bA/s1600-h/share32-doclib-editmetadata.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 275px;" src="http://4.bp.blogspot.com/_QVQz3EsVFfA/SkpU0GIT9xI/AAAAAAAAADQ/Aj7VzYcY7bA/s320/share32-doclib-editmetadata.png" alt="" id="BLOGGER_PHOTO_ID_5353184361058662162" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This looks pretty normal. It is the same popup as with previous version of Share allowing edit of basic metadata properties like Name, Title, Description and tags. But notice in the Upper right corner 'Full metadata Edit page...'. Selecting this will render a full screen rendering all of the document's metadata.&lt;br /&gt;&lt;br /&gt;Here I am showing the full metadata page of the xml file I uploaded...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QVQz3EsVFfA/SkpVVHJt8ZI/AAAAAAAAADY/y3dcFhgBAx8/s1600-h/share32-doclib-editmetadata-full.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 275px;" src="http://2.bp.blogspot.com/_QVQz3EsVFfA/SkpVVHJt8ZI/AAAAAAAAADY/y3dcFhgBAx8/s320/share32-doclib-editmetadata-full.png" alt="" id="BLOGGER_PHOTO_ID_5353184928268677522" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;In this example, two new fields are rendered: the Mimetype, and the Author.&lt;br /&gt;&lt;br /&gt;This full page renders the metadata form in 'Edit' mode using the new &lt;a href="http://wiki.alfresco.com/wiki/Forms"&gt;forms engine&lt;/a&gt;. The form is rendered by obtaining a form configuration from the remote alfresco repository. This form configuration is dynamically generated from the available metadata on the content item being viewed. The form archtiecture is capable of rendering the following types of controls (see more detail in the &lt;a href="http://wiki.alfresco.com/wiki/Forms"&gt;forms service&lt;/a&gt; wiki:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;mimetype -- &amp;lt;select&amp;gt; &amp;lt;option&amp;gt; from a list of mime types (i.e. application/pdf, ...)&lt;/li&gt;&lt;li&gt;size -- display file size&lt;br /&gt;&lt;/li&gt;&lt;li&gt;textarea -- &amp;lt;textarea&amp;gt; field configurable to r rows and c columns&lt;br /&gt;&lt;/li&gt;&lt;li&gt;slectone -- &amp;lt;select&amp;gt; field with &amp;lt;option&amp;gt; tags dynamically rendered&lt;br /&gt;&lt;/li&gt;&lt;li&gt;textfiled -- &amp;lt;input type="text"&amp;gt; field&lt;br /&gt;&lt;/li&gt;&lt;li&gt;category -- picker selecting one or more categories to associate with the content&lt;br /&gt;&lt;/li&gt;&lt;li&gt;endocding -- &amp;lt;select&amp;gt; field to choose &amp;lt;option&amp;gt; from list of encoding types (i.e. UTF-8, ISO-8859-1, ...)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;association -- picker selecting one or more other content items to associate this content item too&lt;br /&gt;&lt;/li&gt;&lt;li&gt;checkbox -- &amp;lt;input type="checkbox"&amp;gt; field&lt;br /&gt;&lt;/li&gt;&lt;li&gt;readonly -- &amp;lt;input type="text"&gt; rendered as read only&lt;br /&gt;&lt;/li&gt;&lt;li&gt;date -- renders a date picker setting value to an &amp;lt;input type="text"&amp;gt; field&lt;br /&gt;&lt;/li&gt;&lt;li&gt;period -- selecting x days, weeks, etc.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Associating Aspects&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To really show the custom metadata feature, we will look at another great feature added to Share 3.2, the ability to associate new aspects to documents. When we associate a new aspect, new properties can be added to the document and the edit metadata full form should reflect those changes. To do this, let us add the 'dublin core' aspect to the document we just looked at.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Hover over the document --&gt; the actions should render&lt;/li&gt;&lt;li&gt;Select the 'more' option --&gt; the more options should render&lt;/li&gt;&lt;li&gt;Select the 'manage aspects' option --&gt; the manage aspects popup will render&lt;/li&gt;&lt;li&gt;Select the '+' by the 'Dublin Core' aspect in the 'Available to Add' list --&gt;  The 'Dublin core' should be removed from the 'Available to Add' and added to the 'Currently Selected' list&lt;/li&gt;&lt;li&gt;Select the 'Apply changes' button to save the changes&lt;/li&gt;&lt;/ol&gt;Now we can look at the edit metadata again and see the new metadata properties added via the Dublin Core aspect&lt;br /&gt;&lt;br /&gt;Here we see the edit metadata full page with the dublin core properties&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_QVQz3EsVFfA/Skpif955LfI/AAAAAAAAADg/SBScrHrW83s/s1600-h/share32-doclib-editmetadata-full-dublin.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 275px;" src="http://1.bp.blogspot.com/_QVQz3EsVFfA/Skpif955LfI/AAAAAAAAADg/SBScrHrW83s/s320/share32-doclib-editmetadata-full-dublin.png" alt="" id="BLOGGER_PHOTO_ID_5353199408416108018" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The next blog entry will look at customizing share to display our own content types and aspects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-3812886361656042731?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/3812886361656042731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=3812886361656042731' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/3812886361656042731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/3812886361656042731'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2009/06/looking-at-share-32-community-part-2.html' title='Looking at Alfresco Share 3.2 Community - Part 2 - Edit Custom Metadata'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QVQz3EsVFfA/SkpTKbqZCLI/AAAAAAAAADA/QImjjbQnjD0/s72-c/share32-doclib.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-700365714292359165</id><published>2009-06-26T06:35:00.000-07:00</published><updated>2009-07-08T08:03:59.816-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='Share 3.2 preview'/><title type='text'>Looking at Alfresco Share 3.2 Community</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;Building Alfresco Labs 3.2 from Community&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This blog and others to follow will walk through the new features of Alfresco Share 3.2 Labs. First, I will walk through some of the key features. Then I will open up the box and look in side at a few choice features. Finally, I will show examples of the extensibility of this new version of Share.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://wiki.alfresco.com/wiki/Source_Code"&gt;Building from source&lt;/a&gt; was fairly straight forward. I use &lt;a href="http://tortoisesvn.tigris.org/"&gt;Tortoise SVN&lt;/a&gt; as my svn client (on my Windows XP laptop). I 'updated' to the latest code (as of 23 June 09). I used ant to build, with my environment setup as recommended in the &lt;a href="http://wiki.alfresco.com/wiki/Alfresco_SVN_Development_Environment"&gt;Alfresco SVN Development environment wiki&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;When attempting to deploy to tomcat using '&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;ant build-tomcat&lt;/span&gt;&lt;/span&gt;' and '&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;ant incremental-tomcat&lt;/span&gt;&lt;/span&gt;', the ant task complained that I needed to use tomcat 6. I downloaded &lt;a href="http://tomcat.apache.org/"&gt;Apache tomcat 6.0.20&lt;/a&gt;. I noticed that tomcat 6 doesn't create a 'shared' folder by default, which is used by alfresco for extension. But I found a wiki page for &lt;a href="http://wiki.alfresco.com/wiki/Install_Tomcat6"&gt;configuring tomcat 6&lt;/a&gt; that explains how to configure tomcat 6 for this purpose.&lt;br /&gt;&lt;br /&gt;Because I have multiple versions of alfresco on this machine, I didn't want to sacrifice the default db (mysql database named alfresco). I had problems with configuring other db vendor, however. I followed the &lt;a href="http://wiki.alfresco.com/wiki/Database_Configuration"&gt;configuring db wiki page for 3.2&lt;/a&gt; and tried boty Derby and HSQL as alternatives. However, various problems occurred. HSQL and Derby didn't seem to have corrected hibernate mappings and/or sql build scripts. So I chose to create another db instance on mysql named alfresco2. I'm sure with a little more patience, I would have succeeded. But I'm impatient.&lt;br /&gt;&lt;br /&gt;In order to configure to this new db (and as described on the &lt;a href="http://wiki.alfresco.com/wiki/Database_Configuration"&gt;database configuration wiki page&lt;/a&gt;), I found that there is now a file 'alfresco-global.properties' that you can copy from your TOMCAT_HOME/webapps/alfresco/WEB-INF/classes directory (named 'alfresco-global.properties.sample') to TOMCAT_HOME/shared/classes directory, renamed to 'alfresc-global.properties'. I noted that this did NOT go into an 'alfresco/extensions' subdirectory as in the past with 'custom-repository.properties'.&lt;br /&gt;&lt;br /&gt;Starting up tomcat on my windows xp with the default configurations caused a problem with out of heap space and, later PermGen. I changed the startup parameters to add more heap and PermGen (-Xms256M -Xmx512M -XX:MaxPermSize=256m) and finally I was in business.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;First Impressions of Share 3.2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After logging in to share (i.e. http://localhost:8080/share) with the default user account admin/admin, the admin user dashboard is rendered first. Nothing new here. However in the header, right justified I saw a 'Admin Console' button. Clicking it, I see you can now create new users and groups from Share directly!&lt;br /&gt;&lt;br /&gt;Here I logged in as admin/admin...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_QVQz3EsVFfA/Skoy4jrRIZI/AAAAAAAAAC4/x0G9-dH-TVs/s1600-h/share32-userdashboard.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 275px;" src="http://4.bp.blogspot.com/_QVQz3EsVFfA/Skoy4jrRIZI/AAAAAAAAAC4/x0G9-dH-TVs/s320/share32-userdashboard.png" alt="" id="BLOGGER_PHOTO_ID_5353147054314037650" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Admin Console&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It seems there is a new role for Share users, that of 'Manager'. This role is described in &lt;a href="http://forums.alfresco.com/en/viewtopic.php?f=47&amp;amp;t=16600"&gt;the forums&lt;/a&gt;. The 'Manager' role has permisions to expose the new 'admin console.'&lt;br /&gt;&lt;br /&gt;The Admin Console is accesssed by clicking the 'Admin Console' button on the top menu. This console is configured with an extensible list of console 'tools'. The console opens up showing the first tool: Groups.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Groups Tool&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here, I clicked on the 'Admin Console' button...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QVQz3EsVFfA/SkjRkAP7NhI/AAAAAAAAACY/CV4iVHjg8UE/s1600-h/share32-adminconsole-groups.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 248px;" src="http://2.bp.blogspot.com/_QVQz3EsVFfA/SkjRkAP7NhI/AAAAAAAAACY/CV4iVHjg8UE/s320/share32-adminconsole-groups.png" alt="" id="BLOGGER_PHOTO_ID_5352758573602125330" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The 'Groups' tool allows a user to drill down through the hierarchy of groups, and create new groups, edit them and remove them. To represent the hierarchy, the user interface represents levels of groups by showing child groups in a new list panel created to the right of the group list panel with the selected group. The successive levels of group lists all have similar functionality (recursively rendered) to add, edit and remove groups and their children. This UI approach is a bit odd, but effective.&lt;br /&gt;&lt;br /&gt;Clicking 'new group' opens the 'Create Group' form, prompting the user to enter the required fields for: Identifier and Display name. Once entered, the buttons 'Create Group', 'Create and Create Another' are enabled. The 'Create Group' creates a group with the given Identifier and Display name, and returns back to the 'Groups' tool main page. The 'Create and Create Another' creates a group as the 'Create Group' button but clears the form to enter another group. The labels of these buttons might be a bit confusing at first.&lt;br /&gt;&lt;br /&gt;Here I clicked the 'New group' button ...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QVQz3EsVFfA/SkjTofx7j0I/AAAAAAAAACg/ruv6S7uDsWg/s1600-h/share32-adminconsole-groups-create.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 248px;" src="http://3.bp.blogspot.com/_QVQz3EsVFfA/SkjTofx7j0I/AAAAAAAAACg/ruv6S7uDsWg/s320/share32-adminconsole-groups-create.png" alt="" id="BLOGGER_PHOTO_ID_5352760849808985922" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I tried creating a new group and the group called 'testg', but it wasn't added to the list immediately. Reopening the admin console later, I saw the group I created listed correctly (see https://issues.alfresco.com/jira/browse/ALFCOM-3110).&lt;br /&gt;&lt;br /&gt;In the Groups tool of the Admin Console, hovering over an item indicates other actions that can be performed on that item, including 'edit' and 'delete'.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Users tool&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The users tool of the 'Admin Console' allows the manager to create new users and edit users. The search box requires at least one character entered before search works. (Perhaps adding a note on this screen or disabling/enabling the 'search' button might help.)  This search text seems to be a partial match to find anything with the text entered 'in' the user's name.&lt;br /&gt;&lt;br /&gt;Here I typed 'a' and pressed 'Search'...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QVQz3EsVFfA/Skowgn-bXYI/AAAAAAAAACo/ScgMhoyEukg/s1600-h/share32-adminconsole-users.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 275px;" src="http://2.bp.blogspot.com/_QVQz3EsVFfA/Skowgn-bXYI/AAAAAAAAACo/ScgMhoyEukg/s320/share32-adminconsole-users.png" alt="" id="BLOGGER_PHOTO_ID_5353144444128025986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;A new user can be created from the users tool main page by clicking the 'New User' button upper right, or an existing user details can be viewed, and later edited, by clicking on the user name in the list.&lt;br /&gt;&lt;br /&gt;Here I clicked on the 'Jane Smith' name in the users list...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_QVQz3EsVFfA/Skox44BlumI/AAAAAAAAACw/YA0lCF37U4M/s1600-h/share32-adminconsole-users-edit.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 275px;" src="http://1.bp.blogspot.com/_QVQz3EsVFfA/Skox44BlumI/AAAAAAAAACw/YA0lCF37U4M/s320/share32-adminconsole-users-edit.png" alt="" id="BLOGGER_PHOTO_ID_5353145960264743522" border="0" /&gt;&lt;/a&gt;From the user profile view page there are two buttons: Edit User and Delete User. From the Edit User page, you can enter basic information, assign the user to groups, set a quota, change passwords and select photos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Next blog entry -- look at edit metadata feature.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-700365714292359165?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/700365714292359165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=700365714292359165' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/700365714292359165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/700365714292359165'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2009/06/looking-at-share-32-community.html' title='Looking at Alfresco Share 3.2 Community'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QVQz3EsVFfA/Skoy4jrRIZI/AAAAAAAAAC4/x0G9-dH-TVs/s72-c/share32-userdashboard.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-5298941075868416465</id><published>2009-05-12T14:32:00.000-07:00</published><updated>2009-05-12T14:59:06.671-07:00</updated><title type='text'>Alfresco Regional Meetup</title><content type='html'>On Wednesday April 29, 2009, The Chicago area hosted a &lt;a href=":   http://www.alfresco.com/about/events/2009/04/chicagomeetup/"&gt;regional alfresco meetup&lt;/a&gt; where I was in attendance. There were a few Alfrewsco speakers and a few community speakers. Among the speakers were &lt;a href="http://ecmarchitect.com/"&gt;Jeff Potts&lt;/a&gt; talking about Drupal integration, and &lt;a href="http://blogs.alfresco.com/wp/uzi/"&gt;Michael Uzquiano&lt;/a&gt; talking about WCM roadmap and Share. Also, &lt;a href="http://drquyong.com/myblog/"&gt;Yong Qu&lt;/a&gt; presented a bit on integration to email clients. &lt;br /&gt;&lt;br /&gt;I also presented some of our work on Alfresco Share developing a custom contribution client for our marketing content. For those interested, my &lt;a href="http://www.wentsoft.com/Alf%20Community%20Meetup%20Presentation.zip"&gt;PowerPoint presentation&lt;/a&gt; is located here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-5298941075868416465?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/5298941075868416465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=5298941075868416465' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/5298941075868416465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/5298941075868416465'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2009/05/alfresco-regional-meetup.html' title='Alfresco Regional Meetup'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-6451309944310642602</id><published>2009-04-07T18:47:00.001-07:00</published><updated>2009-04-07T19:38:06.765-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='working with workflows'/><category scheme='http://www.blogger.com/atom/ns#' term='BPM'/><category scheme='http://www.blogger.com/atom/ns#' term='jBPM'/><title type='text'>Working with jBPM workflows in Alfresco - Part 3 : Alfresco scripts</title><content type='html'>In the previous blog entry: &lt;a href="http://edlovesjava.blogspot.com/2009/04/working-with-jbpm-workflows-in-alfresco.html"&gt;Working with jBPM Workflows in Alfresco - Part 1 : jBPM&lt;/a&gt;, we saw how to create a simple jBPM workflow and test it.&lt;br /&gt;&lt;br /&gt;In a blog entry before that: &lt;a href="http://edlovesjava.blogspot.com/2009/04/working-with-jbpm-workflows-in-alfresco_07.html"&gt;Working with jBPM Workflows in Alfresco - Part 2 : Embedded Alf - SDK&lt;/a&gt;, we saw how to run our workflow in Alfresco Embedded using the SDK.&lt;br /&gt;&lt;br /&gt;In this blog entry, we will add some Alfresco scripts into our workflow that make use of Alfresco APIs.&lt;br /&gt;&lt;br /&gt;Step 1 - Logging in JavaScript via Alfresco logger&lt;br /&gt;&lt;br /&gt;Starting simple, lets modify our process definition to print out a log message every time we transition to a new state. This is a handy technique if we're not sure our logic is going the way we think it should. Here is the updated processs definiton:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="publishContentBasic"&amp;gt;&lt;br /&gt;  &amp;lt;start-state name="start"&amp;gt;&lt;br /&gt;      &amp;lt;transition name="to_requested" to="requested"&amp;gt;&lt;br /&gt;          &amp;lt;action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript"&amp;gt;&lt;br /&gt;              &amp;lt;script&amp;gt;&lt;br /&gt;                  logger.log("Going to requested state");&lt;br /&gt;              &amp;lt;/script&amp;gt;&lt;br /&gt;          &amp;lt;/action&amp;gt;&lt;br /&gt;      &amp;lt;/transition&amp;gt;&lt;br /&gt;  &amp;lt;/start-state&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;state name="requested"&amp;gt;&lt;br /&gt;      &amp;lt;transition to="processing" name="to_processing"&amp;gt;&lt;br /&gt;          &amp;lt;action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript"&amp;gt;&lt;br /&gt;              &amp;lt;script&amp;gt;&lt;br /&gt;                  logger.log("Going to processing state");&lt;br /&gt;              &amp;lt;/script&amp;gt;&lt;br /&gt;          &amp;lt;/action&amp;gt;&lt;br /&gt;      &amp;lt;/transition&amp;gt;&lt;br /&gt;  &amp;lt;/state&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;state name="processing"&amp;gt;&lt;br /&gt;      &amp;lt;transition to="succeeded" name="to_succeeded"&amp;gt;&lt;br /&gt;          &amp;lt;action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript"&amp;gt;&lt;br /&gt;              &amp;lt;script&amp;gt;&lt;br /&gt;                  logger.log("Going to succeeded state");&lt;br /&gt;              &amp;lt;/script&amp;gt;&lt;br /&gt;          &amp;lt;/action&amp;gt;&lt;br /&gt;      &amp;lt;/transition&amp;gt;&lt;br /&gt;      &amp;lt;transition to="failed" name="to_failed"&amp;gt;&lt;br /&gt;          &amp;lt;action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript"&amp;gt;&lt;br /&gt;              &amp;lt;script&amp;gt;&lt;br /&gt;                  logger.log("Going to failed state");&lt;br /&gt;              &amp;lt;/script&amp;gt;&lt;br /&gt;          &amp;lt;/action&amp;gt;&lt;br /&gt;      &amp;lt;/transition&amp;gt;&lt;br /&gt;  &amp;lt;/state&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;state name="succeeded"&amp;gt;&lt;br /&gt;      &amp;lt;transition to="end" name="to_end"&amp;gt;&lt;br /&gt;          &amp;lt;action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript"&amp;gt;&lt;br /&gt;              &amp;lt;script&amp;gt;&lt;br /&gt;                  logger.log("Going to end state");&lt;br /&gt;              &amp;lt;/script&amp;gt;&lt;br /&gt;          &amp;lt;/action&amp;gt;&lt;br /&gt;      &amp;lt;/transition&amp;gt;&lt;br /&gt;  &amp;lt;/state&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;state name="failed"&amp;gt;&lt;br /&gt;      &amp;lt;transition to="end" name="to_end"&amp;gt;&lt;br /&gt;          &amp;lt;action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript"&amp;gt;&lt;br /&gt;              &amp;lt;script&amp;gt;&lt;br /&gt;                  logger.log("Finishing");&lt;br /&gt;              &amp;lt;/script&amp;gt;&lt;br /&gt;          &amp;lt;/action&amp;gt;&lt;br /&gt;      &amp;lt;/transition&amp;gt;&lt;br /&gt;  &amp;lt;/state&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;end-state name="end"&amp;gt;&amp;lt;/end-state&amp;gt;&lt;br /&gt;&amp;lt;/process-definition&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Here we see the new process containing an action element in the transition element calling out the org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript class. This class provides a java script environment with the Alfresco JavaScript API default objects instantiated and ready to use. One of which is the logger.&lt;br /&gt;This action wraps a &amp;lt;script&amp;gt; element containing the javascript to run.&lt;br /&gt;&lt;br /&gt;To view the results, first change the log4j.properties config to show the javascipt log messages (and reduce some of the noise).&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;# Set root logger level to DEBUG and its only appender to CONSOLE.&lt;br /&gt;log4j.rootLogger=WARN, CONSOLE&lt;br /&gt;&lt;br /&gt;# CONSOLE&lt;br /&gt;log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender&lt;br /&gt;log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout&lt;br /&gt;log4j.appender.CONSOLE.layout.ConversionPattern=%d{HH:mm:ss,SSS} [%t] %-5p %C{1} : %m%n&lt;br /&gt;&lt;br /&gt;# LIMIT CATEGORIES&lt;br /&gt;log4j.logger.org.jbpm=INFO&lt;br /&gt;#log4j.logger.org.jbpm.graph=DEBUG&lt;br /&gt;log4j.logger.com.sample=DEBUG&lt;br /&gt;# Hibernate debugging levels and their output&lt;br /&gt;log4j.logger.org.hibernate=WARN&lt;br /&gt;#Log all SQL DML statements as they are executed&lt;br /&gt;#log4j.logger.org.hibernate.SQL=TRACE&lt;br /&gt;#Log all JDBC parameters&lt;br /&gt;#log4j.logger.org.hibernate.type=TRACE&lt;br /&gt;#Log all SQL DDL statements as they are executed&lt;br /&gt;#log4j.logger.org.hibernate.tool.hbm2ddl=DEBUG  &lt;br /&gt;#Log the state of all entities (max 20 entities) associated with the session at flush time&lt;br /&gt;#log4j.logger.org.hibernate.pretty=DEBUG  &lt;br /&gt;#Log all second-level cache activity&lt;br /&gt;#log4j.logger.org.hibernate.cache=DEBUG  &lt;br /&gt;#Log transaction related activity&lt;br /&gt;#log4j.logger.org.hibernate.transaction=DEBUG  &lt;br /&gt;#Log all JDBC resource acquisition&lt;br /&gt;#log4j.logger.org.hibernate.jdbc=TRACE  &lt;br /&gt;#Log HQL and SQL ASTs and other information about query parsing&lt;br /&gt;#log4j.logger.org.hibernate.hql.ast=DEBUG  &lt;br /&gt;#Log all JAAS authorization requests&lt;br /&gt;#log4j.logger.org.hibernate.secure=DEBUG  &lt;br /&gt;#Log everything (a lot of information, but very useful for troubleshooting)&lt;br /&gt;#log4j.logger.org.hibernate=DEBUG  &lt;br /&gt;#log4j.logger.org.hibernate.tools=DEBUG  &lt;br /&gt;&lt;br /&gt;log4j.logger.org.alfresco=INFO&lt;br /&gt;&lt;br /&gt;log4j.logger.org.alfresco.repo.jscript=DEBUG&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The last line: log4j.logger.org.alfresco.repo.jscript=DEBUG does the trick. Now run the PublishContentBasicProcessAlfTest as a JUnit test and see the results. You should get something like the following in the log:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;20:42:22,574 [main] DEBUG ScriptResourceHelper : Imports resolved, adding resource '_root&lt;br /&gt;20:42:22,761 [main] DEBUG ScriptLogger : Going to requested state&lt;br /&gt;20:42:22,765 [main] DEBUG RhinoScriptProcessor : Time to execute script: 189ms&lt;br /&gt;20:42:22,893 [main] DEBUG ScriptResourceHelper : Imports resolved, adding resource '_root&lt;br /&gt;20:42:22,899 [main] DEBUG ScriptLogger : Going to processing state&lt;br /&gt;20:42:22,901 [main] DEBUG RhinoScriptProcessor : Time to execute script: 6ms&lt;br /&gt;20:42:22,936 [main] DEBUG ScriptResourceHelper : Imports resolved, adding resource '_root&lt;br /&gt;20:42:22,942 [main] DEBUG ScriptLogger : Going to succeeded state&lt;br /&gt;20:42:22,943 [main] DEBUG RhinoScriptProcessor : Time to execute script: 5ms&lt;br /&gt;20:42:23,004 [main] DEBUG ScriptResourceHelper : Imports resolved, adding resource '_root&lt;br /&gt;20:42:23,010 [main] DEBUG ScriptLogger : Going to end state&lt;br /&gt;20:42:23,011 [main] DEBUG RhinoScriptProcessor : Time to execute script: 5ms&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Lets do something more interesting. Supposing we wanted to create and/or update some content. The Alfresco JavaScipt API cookbook has an interesting example which I will steal for this purpose. Add the following javascript to the script element of the 'to_requested' transition:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;script&amp;gt;&lt;br /&gt;    logger.log(&amp;quot;Going to requested state&amp;quot;);&lt;br /&gt;    logger.log(&amp;quot;trying to create file and make it versionable&amp;quot;);&lt;br /&gt;    &lt;br /&gt;    var doc = userhome.createFile(&amp;quot;checkmeout.txt&amp;quot;);&lt;br /&gt;    doc.addAspect(&amp;quot;cm:versionable&amp;quot;);&lt;br /&gt;    doc.content = &amp;quot;original text&amp;quot;;&lt;br /&gt;    logger.log(&amp;quot;created versionable doc with content '&amp;quot;+doc.content+&amp;quot;'&amp;quot;);&lt;br /&gt;&lt;br /&gt;    var workingCopy = doc.checkout();&lt;br /&gt;    workingCopy.content = &amp;quot;updated text 1&amp;quot;;&lt;br /&gt;&lt;br /&gt;    doc = workingCopy.checkin();&lt;br /&gt;&lt;br /&gt;    workingCopy = doc.checkout();&lt;br /&gt;    workingCopy.content = &amp;quot;updated text 2&amp;quot;;&lt;br /&gt;&lt;br /&gt;    doc = workingCopy.checkin(&amp;quot;a history note&amp;quot;, true);&lt;br /&gt;    logger.log(&amp;quot;checked doc out and in a couple of times&amp;quot;);&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In this example, we create a new item of content with some text and make it versionable. Then we check it out and updated it. And again checkout and update it, and on check in we use a comment. &lt;br /&gt;&lt;br /&gt;Note: be careful as to what syntax you use in the script element. Since this appears in XML, we must escape any characters that can cause this script body to parse incorrectly (such as &amp;lt; and &amp;gt; characters). I had to remove the // comment lines to make this work correctly.&lt;br /&gt;&lt;br /&gt;Step 2 - Running a Java class with Alfresco&lt;br /&gt;&lt;br /&gt;Now we will configure to run &lt;a href="http://wiki.alfresco.com/wiki/Java_Foundation_API"&gt;alfresco java foundation API&lt;/a&gt; services.&lt;br /&gt;&lt;br /&gt;END&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-6451309944310642602?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/6451309944310642602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=6451309944310642602' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6451309944310642602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6451309944310642602'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2009/04/working-with-jbpm-workflows-in-alfresco_6038.html' title='Working with jBPM workflows in Alfresco - Part 3 : Alfresco scripts'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-6650032635530935773</id><published>2009-04-07T09:32:00.001-07:00</published><updated>2009-04-07T14:02:28.556-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='working with workflows'/><category scheme='http://www.blogger.com/atom/ns#' term='BPM'/><category scheme='http://www.blogger.com/atom/ns#' term='jBPM'/><title type='text'>Working with jBPM workflows in Alfresco - Part 2: Embedded Alf - SDK</title><content type='html'>This part focuses on extending the &lt;a href="http://edlovesjava.blogspot.com/2009/04/working-with-jbpm-workflows-in-alfresco.html"&gt;previous blog post: Working with Workflows in Alfresco - Part 1: jBPM&lt;/a&gt; to run as an Embedded Alf SDK project, and to configure and use Alfresco scripts as actions in the workflows.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 1 - Install SDK&lt;/span&gt;&lt;br /&gt;Make sure you install the SDK according to the documentation on the Alfresco Wiki&lt;br /&gt;Import the SDK projects into the same workspace you are using for this tutorial&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 2 - Configure Project to Run with Embedded Alfresco&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Go to project properties &gt; Java buid path &gt; Projects tab and select 'add' to add SDK AlfrescoEmbedded&lt;/li&gt;&lt;li&gt;From the SDK FirstFoundationClient, copy alfresco.extensions package from the 'source' source folder and paste into the 'src/main/config' source directory of your project (i.e. 'orchestration-example'). This will include the files 'custom-alfresco-shared.xml', 'custom-repository-context.xml' and 'custom-repository.properties'&lt;/li&gt;&lt;li&gt;From the SDK FirstFoundationClient, copy the org.alfresco.sample package and paste into the src/main/java source folder of your project. This will give us something to test running as Alfresco Embedded&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Update the 'custom-repository.properties' to point dir.root to your Alfresco installation&lt;/li&gt;&lt;li&gt;Remove the JBPM library from project properties, as it will conflict with the Alfresco version of these dependencies&lt;/li&gt;&lt;li&gt;I recommend that you modify the log4j.properties to set the root logger to INFO,  CONSOLE not DEBUG, CONSOLE or you will be watching the log messages for half the day&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:130%;"&gt;Step 3 - Test it out&lt;/span&gt;&lt;br /&gt;Run the FirstFoundationClient as Java Application. There should be no 'red ink' and the line near the end of the log messages should read something like 'Alfresco started (Labs): Current version 3.0.0 (Stable 1526) schema 1002 - Installed version 3.1.0 (142) schema 1008'&lt;br /&gt;If you see this line, likely you were able to run using Alfresco Embedded SDK&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;Step 4 - Create an Embedded Alf test&lt;/span&gt;&lt;br /&gt;To test within the Alfresco context using Embedded approach, your workflow must be deployed, and you must run your test code, like the FirstFoundationClient example within a transaction service callback.&lt;br /&gt;We will create a base test class, extending TestCase of JUnit 3 to simplify writing tests like this.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;package com.sample;&lt;br /&gt;&lt;br /&gt;import junit.framework.TestCase;&lt;br /&gt;&lt;br /&gt;import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;&lt;br /&gt;import org.alfresco.service.ServiceRegistry;&lt;br /&gt;import org.alfresco.service.transaction.TransactionService;&lt;br /&gt;import org.alfresco.util.ApplicationContextHelper;&lt;br /&gt;import org.apache.log4j.Logger;&lt;br /&gt;import org.springframework.context.ApplicationContext;&lt;br /&gt;&lt;br /&gt;public abstract class EmbeddedAlfTestBase extends TestCase {&lt;br /&gt;&lt;br /&gt;Logger logger = Logger.getLogger(EmbeddedAlfTestBase.class);&lt;br /&gt;protected ServiceRegistry serviceRegistry;&lt;br /&gt;protected TransactionService transactionService;&lt;br /&gt;protected ApplicationContext ctx;&lt;br /&gt;&lt;br /&gt;public void setUp() throws Exception {&lt;br /&gt;ctx = ApplicationContextHelper.getApplicationContext();&lt;br /&gt;serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);&lt;br /&gt;transactionService = serviceRegistry.getTransactionService();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void tearDown() throws Exception {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void runTestInEmbeddedAlf(RetryingTransactionCallback&amp;lt;Object&amp;gt; testWork) throws Exception {&lt;br /&gt;transactionService.getRetryingTransactionHelper().doInTransaction(testWork);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This code gets the application context and gets some services from Spring, including the serviceRegistry and the transactionService. The helper method, runtestInEmbeddedAlf takes a class of type RetryingtransactionCallback and runs it it using the transactionService's RetryingTransactionHelper doInTransaction(callback) method.&lt;br /&gt;&lt;br /&gt;We will subclass this base test class and write our process test.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Create a class PublishContentBasicProcessAlfTest, copying from PublishContentBasicProcessTest created in the previous blog entry.&lt;/li&gt;&lt;li&gt;Change it to extend from EmbeddedAlfTestBase class&lt;/li&gt;&lt;li&gt;Rename testSimpleProcess to a signature 'public void doTestSimpleProcess(ServiceRegistry serviceRegistry) throws Exception'&lt;/li&gt;&lt;li&gt;Create a new testSimpleProcess like the following:&lt;/li&gt;&lt;/ol&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    public void testSimpleProcess() throws Exception {&lt;br /&gt;RetryingTransactionCallback&amp;lt;Object&amp;gt; publishContentWFExistsCB = new RetryingTransactionCallback&amp;lt;Object&amp;gt;() {&lt;br /&gt; public Object execute() throws Exception {&lt;br /&gt;     doTestSimpleProcess(serviceRegistry);&lt;br /&gt;     return null;&lt;br /&gt; }&lt;br /&gt;};&lt;br /&gt;this.runTestInEmbeddedAlf(publishContentWFExistsCB);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Now run 'PublishContentBasicProcessAlfTest' as a JUnit test.&lt;br /&gt;This should run as an alfresco project properly. But we are not leveraging Alfresco's services yet.&lt;br /&gt;&lt;br /&gt;Step 5 - Test in Alf Using Workflow Service (foundation services)&lt;br /&gt;&lt;br /&gt;What we are going to do:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Authenticate and deploy in setUp for test&lt;/li&gt;&lt;li&gt;Start workflow using workflow service&lt;/li&gt;&lt;li&gt;Signal workflow using workflow service&lt;/li&gt;&lt;/ol&gt;Create a class PublishContentBasicProcessAlfTest extends EmbeddedAlfTestBase&lt;br /&gt;To start, we will create a setUp() method to set us up for testing, like authenticating and deploying the service&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    private WorkflowService workflowService;&lt;br /&gt;&lt;br /&gt;public void setUp() throws Exception {&lt;br /&gt;super.setUp();&lt;br /&gt;workflowService = serviceRegistry.getWorkflowService();&lt;br /&gt;&lt;br /&gt;authenticate("admin","admin");&lt;br /&gt;&lt;br /&gt;deployDefinition(PROCESS_DEF_FILE);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;We get the workflow service from the service registry (obtained in the setUp of the EmbeddedAlfTestBase class). Then we authenticate, and then deploy our process definition 'publichContentBasic/processdefinition.xml'.&lt;br /&gt;Lets look at the methods we need to create:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;authenticate method&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    private void authenticate(String user, String password) {&lt;br /&gt;  AuthenticationService authenticationService = serviceRegistry.getAuthenticationService();&lt;br /&gt;  authenticationService.authenticate(user, password.toCharArray());&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;We get the AuthenticationService, and call authenticate. We need to do this first or else we wont be able to deploy our workflow.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;deployDefinition method&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    private WorkflowDeployment deployDefinition(String processDefName) {&lt;br /&gt;   //Deploy definition&lt;br /&gt;   String engineId = ENGINE_ID;&lt;br /&gt;   InputStream workflowDefinition = getClass().getResourceAsStream("/"+processDefName);&lt;br /&gt;   String mimeType = XML_MIMETYPE;&lt;br /&gt;   return workflowService.deployDefinition(engineId, workflowDefinition, mimeType);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;We use the deployDefinition method of the workflow service. THis requires us to pass an engineId. this Id for jbpm is 'jbpm'. The mime type is 'text/xml'. The stream is obtained as a resource from this class loader by reading the 'publishContentBasic/processdefinition.xml' file.&lt;br /&gt;&lt;br /&gt;Now we start the test like we did before, using the transactionservice and its callback:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    public void testSimpleProcess() throws Exception {&lt;br /&gt;    RetryingTransactionCallback&amp;lt;Object&amp;gt; publishContentWFExistsCB = new RetryingTransactionCallback&amp;lt;Object&amp;gt;() {&lt;br /&gt;        public Object execute() throws Exception {&lt;br /&gt;            doTestSimpleProcessInAlf();&lt;br /&gt;            return null;&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    this.runTestInEmbeddedAlf(publishContentWFExistsCB);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void doTestSimpleProcessInAlf() throws Exception {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ok. Now that we've got the test method ready. Lets put something in it. The first thing we have to do is start our workflow:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    public void doTestSimpleProcessInAlf() throws Exception {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    NodeRef content = null;&lt;br /&gt;    String wfAssigneeName = "admin";&lt;br /&gt;    String workflowName = ENGINE_ID+"$"+PROCESS_DEF_NAME;&lt;br /&gt;&lt;br /&gt;    WorkflowPath wfPath = startWorkflow(content, wfAssigneeName, workflowName);&lt;br /&gt;    assertNotNull(wfPath);&lt;br /&gt;&lt;br /&gt;    assertEquals(&lt;br /&gt;            "Instance is in start state",&lt;br /&gt;            wfPath.node.name,&lt;br /&gt;            "start");&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This calls the startWorkflow helper method with the content to go in the workflow package (currently null for testing purposes). We also need a name to assign the workflow to. We use 'admin'. And, finally we need the workflow name to start. Alfresco uses a naming convention prepending the engine id and a '$' to the beginning of BPM engine objects. The value for jbpm is 'jbpm'.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;startWorkflow method&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    private WorkflowPath startWorkflow(NodeRef content, String wfAssigneeName, String workflowName) throws Exception {&lt;br /&gt;     //Start workflow&lt;br /&gt;     NodeRef wfPackage = workflowService.createPackage(content );&lt;br /&gt;  &lt;br /&gt;     PersonService personService = serviceRegistry.getPersonService();&lt;br /&gt;     NodeRef assigneeNodeRef = personService.getPerson(wfAssigneeName );&lt;br /&gt;&lt;br /&gt;     Map&amp;lt;QName, Serializable&amp;gt; workflowProps = new HashMap&amp;lt;QName, Serializable&amp;gt;(16);&lt;br /&gt;     workflowProps.put(WorkflowModel.ASSOC_PACKAGE, wfPackage);&lt;br /&gt;     workflowProps.put(WorkflowModel.ASSOC_ASSIGNEE, assigneeNodeRef);&lt;br /&gt;&lt;br /&gt;     // get the moderated workflow&lt;br /&gt;&lt;br /&gt;     WorkflowDefinition wfDefinition = workflowService.getDefinitionByName(workflowName );&lt;br /&gt;     if (wfDefinition == null) {&lt;br /&gt;         // handle workflow definition does not exist&lt;br /&gt;         throw new Exception("noworkflow: " + workflowName);&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     // start the workflow&lt;br /&gt;     WorkflowPath wfPath = workflowService.startWorkflow(wfDefinition.getId(), workflowProps);&lt;br /&gt;     return wfPath;&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;In this code, we create the package for the workflow that should contain the content we are workflowing. This is a content manager after all :). Next we get the user we will assign this workflow too. Since this process has no 'tasks', nothing will be noticable to the user. For this kind of process orchestration, the 'admin' user will do nicely. Perhaps in a real system, we want to create a special user just for back office processing like this?&lt;br /&gt;&lt;br /&gt;Next we get the definition from the service using the given name 'jbpm$publishContentBasic'. Finally, we use the service to start the workflow, passing the definition and the workflow package.  The startWorkflow service returns a WorkflowPath object. This corresponds to the workflow token of the execution of the workflow.&lt;br /&gt;&lt;br /&gt;We can test this now to make sure we can deploy and start our workflow.&lt;br /&gt;&lt;br /&gt;Next, we will signal the workflow to transition to the next state. This code snippet should be added to the end of the doTestSimpleProcessInAlf method&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;        // Move the process instance from its start state to the first state.&lt;br /&gt;      wfPath = signalTransition(wfPath, null);&lt;br /&gt;      assertEquals(&lt;br /&gt;              "Instance is in reqested state",&lt;br /&gt;              wfPath.node.name,&lt;br /&gt;              "requested");&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Here we call the 'signalTransition' helper method passing the current path (token) and a transition name to take. Our helper method takes the first transition from the current state if no transition name is supplied.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;signalTransition method&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    private WorkflowPath signalTransition(WorkflowPath wfPath, String transitionName) throws Exception {&lt;br /&gt;     String wfPathId = wfPath.id;&lt;br /&gt;     WorkflowTransition[] wfTransitions = wfPath.node.transitions;&lt;br /&gt;     String wfTransitionId = null;&lt;br /&gt;     if (transitionName == null || transitionName.trim().length()==0) {&lt;br /&gt;         WorkflowTransition wfTransition = wfTransitions[0];&lt;br /&gt;         wfTransitionId = wfTransition.id;&lt;br /&gt;     } else {&lt;br /&gt;         int i = 0;&lt;br /&gt;         for (i = 0; i&amp;lt;wfTransitions.length; i++) {&lt;br /&gt;             if (wfTransitions[i].title.equals(transitionName)) break;&lt;br /&gt;         }&lt;br /&gt;         if (i &amp;gt; wfTransitions.length) throw new Exception("Failed to find transition with nanme '"+transitionName+"'");&lt;br /&gt;         WorkflowTransition wfTransition = wfTransitions[i];&lt;br /&gt;         wfTransitionId = wfTransition.id;&lt;br /&gt;     }&lt;br /&gt;    &lt;br /&gt;     wfPath = workflowService.signal(wfPathId, wfTransitionId);&lt;br /&gt;     return wfPath;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Ok. This pattern can be repeated to transition to the next states to complete our test&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;        //move to processing state&lt;br /&gt;        wfPath = signalTransition(wfPath, null);&lt;br /&gt;        assertEquals(&lt;br /&gt;                &amp;quot;Instance is in processing state&amp;quot;,&lt;br /&gt;                &amp;quot;processing&amp;quot;,&lt;br /&gt;                wfPath.node.name);&lt;br /&gt;&lt;br /&gt;        //move to succeeded state&lt;br /&gt;        wfPath = signalTransition(wfPath, &amp;quot;to_succeeded&amp;quot;);&lt;br /&gt;        assertEquals(&lt;br /&gt;                &amp;quot;Instance is in processing state&amp;quot;, &lt;br /&gt;                &amp;quot;succeeded&amp;quot;, &lt;br /&gt;                wfPath.node.name);&lt;br /&gt;&lt;br /&gt;        // Move the process instance to the end state. The configured action &lt;br /&gt;        // should execute again. The message variable contains a new value.&lt;br /&gt;        wfPath = signalTransition(wfPath, null);&lt;br /&gt;        assertEquals(&lt;br /&gt;                &amp;quot;Instance is in end state&amp;quot;, &lt;br /&gt;                &amp;quot;end&amp;quot;, &lt;br /&gt;                wfPath.node.name);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This completes the code to use the workflow service foundation client approach to deploy, start and signal our workflow.&lt;br /&gt;&lt;br /&gt;Here is the complete code of the PublishContentBasicAlfTest&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;package com.sample;&lt;br /&gt;&lt;br /&gt;import java.io.InputStream;&lt;br /&gt;import java.io.Serializable;&lt;br /&gt;import java.util.HashMap;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;&lt;br /&gt;import org.alfresco.repo.workflow.WorkflowModel;&lt;br /&gt;import org.alfresco.service.cmr.repository.NodeRef;&lt;br /&gt;import org.alfresco.service.cmr.security.AuthenticationService;&lt;br /&gt;import org.alfresco.service.cmr.security.PersonService;&lt;br /&gt;import org.alfresco.service.cmr.workflow.WorkflowDefinition;&lt;br /&gt;import org.alfresco.service.cmr.workflow.WorkflowDeployment;&lt;br /&gt;import org.alfresco.service.cmr.workflow.WorkflowPath;&lt;br /&gt;import org.alfresco.service.cmr.workflow.WorkflowService;&lt;br /&gt;import org.alfresco.service.cmr.workflow.WorkflowTransition;&lt;br /&gt;import org.alfresco.service.namespace.QName;&lt;br /&gt;&lt;br /&gt;public class PublishContentBasicProcessAlfTest extends EmbeddedAlfTestBase {&lt;br /&gt;&lt;br /&gt;    private static final String XML_MIMETYPE = &amp;quot;text/xml&amp;quot;;&lt;br /&gt;    private static final String PROCESS_DEF_FILE = &amp;quot;publishContentBasic/processdefinition.xml&amp;quot;;&lt;br /&gt;    private static final String PROCESS_DEF_NAME = &amp;quot;publishContentBasic&amp;quot;;&lt;br /&gt;    private static final String ENGINE_ID = &amp;quot;jbpm&amp;quot;;&lt;br /&gt;&lt;br /&gt;    private WorkflowService workflowService;&lt;br /&gt;&lt;br /&gt;    public void setUp() throws Exception {&lt;br /&gt;        super.setUp();&lt;br /&gt;        workflowService = serviceRegistry.getWorkflowService();        &lt;br /&gt;&lt;br /&gt;        authenticate(&amp;quot;admin&amp;quot;,&amp;quot;admin&amp;quot;);&lt;br /&gt;        &lt;br /&gt;        deployDefinition(PROCESS_DEF_FILE);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void tearDown() throws Exception {&lt;br /&gt;        super.tearDown();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void testSimpleProcess() throws Exception {&lt;br /&gt;        RetryingTransactionCallback&amp;lt;Object&amp;gt; publishContentWFExistsCB = new RetryingTransactionCallback&amp;lt;Object&amp;gt;() {&lt;br /&gt;            public Object execute() throws Exception {&lt;br /&gt;                doTestSimpleProcessInAlf();&lt;br /&gt;                return null;&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;        this.runTestInEmbeddedAlf(publishContentWFExistsCB);&lt;br /&gt;        &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void doTestSimpleProcessInAlf() throws Exception {&lt;br /&gt;        &lt;br /&gt;        &lt;br /&gt;        NodeRef content = null;&lt;br /&gt;        String wfAssigneeName = &amp;quot;admin&amp;quot;;&lt;br /&gt;        String workflowName = ENGINE_ID+&amp;quot;$&amp;quot;+PROCESS_DEF_NAME;&lt;br /&gt;        &lt;br /&gt;        WorkflowPath wfPath = startWorkflow(content, wfAssigneeName, workflowName);&lt;br /&gt;        assertNotNull(wfPath);&lt;br /&gt;&lt;br /&gt;        assertEquals(&lt;br /&gt;                &amp;quot;Instance is in start state&amp;quot;, &lt;br /&gt;                wfPath.node.name, &lt;br /&gt;                &amp;quot;start&amp;quot;);&lt;br /&gt;&lt;br /&gt;        // Move the process instance from its start state to the first state.&lt;br /&gt;        wfPath = signalTransition(wfPath, null);&lt;br /&gt;        assertEquals(&lt;br /&gt;                &amp;quot;Instance is in reqested state&amp;quot;, &lt;br /&gt;                wfPath.node.name, &lt;br /&gt;                &amp;quot;requested&amp;quot;);&lt;br /&gt;&lt;br /&gt;        //move to processing state&lt;br /&gt;        wfPath = signalTransition(wfPath, null);&lt;br /&gt;        assertEquals(&lt;br /&gt;                &amp;quot;Instance is in processing state&amp;quot;,&lt;br /&gt;                &amp;quot;processing&amp;quot;,&lt;br /&gt;                wfPath.node.name);&lt;br /&gt;&lt;br /&gt;        //move to succeeded state&lt;br /&gt;        wfPath = signalTransition(wfPath, &amp;quot;to_succeeded&amp;quot;);&lt;br /&gt;        assertEquals(&lt;br /&gt;                &amp;quot;Instance is in processing state&amp;quot;, &lt;br /&gt;                &amp;quot;succeeded&amp;quot;, &lt;br /&gt;                wfPath.node.name);&lt;br /&gt;&lt;br /&gt;        // Move the process instance to the end state. The configured action &lt;br /&gt;        // should execute again. The message variable contains a new value.&lt;br /&gt;        wfPath = signalTransition(wfPath, null);&lt;br /&gt;        assertEquals(&lt;br /&gt;                &amp;quot;Instance is in end state&amp;quot;, &lt;br /&gt;                &amp;quot;end&amp;quot;, &lt;br /&gt;                wfPath.node.name);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private WorkflowPath startWorkflow(NodeRef content, String wfAssigneeName, String workflowName) throws Exception {&lt;br /&gt;        //Start workflow&lt;br /&gt;        NodeRef wfPackage = workflowService.createPackage(content );&lt;br /&gt;        &lt;br /&gt;        PersonService personService = serviceRegistry.getPersonService();&lt;br /&gt;        NodeRef assigneeNodeRef = personService.getPerson(wfAssigneeName );&lt;br /&gt;    &lt;br /&gt;        Map&amp;lt;QName, Serializable&amp;gt; workflowProps = new HashMap&amp;lt;QName, Serializable&amp;gt;(16);&lt;br /&gt;        workflowProps.put(WorkflowModel.ASSOC_PACKAGE, wfPackage);&lt;br /&gt;        workflowProps.put(WorkflowModel.ASSOC_ASSIGNEE, assigneeNodeRef);&lt;br /&gt;    &lt;br /&gt;        // get the moderated workflow&lt;br /&gt;    &lt;br /&gt;        WorkflowDefinition wfDefinition = workflowService.getDefinitionByName(workflowName );&lt;br /&gt;        if (wfDefinition == null) {&lt;br /&gt;            // handle workflow definition does not exist&lt;br /&gt;            throw new Exception(&amp;quot;noworkflow: &amp;quot; + workflowName);&lt;br /&gt;        }&lt;br /&gt;    &lt;br /&gt;        // start the workflow&lt;br /&gt;        WorkflowPath wfPath = workflowService.startWorkflow(wfDefinition.getId(), workflowProps);&lt;br /&gt;        return wfPath;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private WorkflowDeployment deployDefinition(String processDefName) {&lt;br /&gt;        //Deploy definition&lt;br /&gt;        String engineId = ENGINE_ID;&lt;br /&gt;        InputStream workflowDefinition = getClass().getResourceAsStream(&amp;quot;/&amp;quot;+processDefName);&lt;br /&gt;        String mimeType = XML_MIMETYPE;&lt;br /&gt;        return workflowService.deployDefinition(engineId, workflowDefinition, mimeType);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private WorkflowPath signalTransition(WorkflowPath wfPath, String transitionName) throws Exception {&lt;br /&gt;      String wfPathId = wfPath.id;&lt;br /&gt;      WorkflowTransition[] wfTransitions = wfPath.node.transitions;&lt;br /&gt;      String wfTransitionId = null;&lt;br /&gt;      if (transitionName == null &amp;#124;&amp;#124; transitionName.trim().length()==0) {&lt;br /&gt;          WorkflowTransition wfTransition = wfTransitions[0];&lt;br /&gt;          wfTransitionId = wfTransition.id;&lt;br /&gt;      } else {&lt;br /&gt;          int i = 0;&lt;br /&gt;          for (i = 0; i&amp;lt;wfTransitions.length; i++) {&lt;br /&gt;              if (wfTransitions[i].title.equals(transitionName)) break;&lt;br /&gt;          }&lt;br /&gt;          if (i &amp;gt; wfTransitions.length) throw new Exception(&amp;quot;Failed to find transition with nanme '&amp;quot;+transitionName+&amp;quot;'&amp;quot;);&lt;br /&gt;          WorkflowTransition wfTransition = wfTransitions[i];&lt;br /&gt;          wfTransitionId = wfTransition.id;&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      wfPath = workflowService.signal(wfPathId, wfTransitionId);&lt;br /&gt;      return wfPath;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;    private boolean authenticate(String user, String password) {&lt;br /&gt;        AuthenticationService authenticationService = serviceRegistry.getAuthenticationService();&lt;br /&gt;        authenticationService.authenticate(user, password.toCharArray());&lt;br /&gt;        return authenticationService.authenticationExists(user);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the next blog post, we will use alfresco scripts in the workflow definition we have just created. And finally, for orchestration, we will interact with JMS.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-6650032635530935773?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/6650032635530935773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=6650032635530935773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6650032635530935773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6650032635530935773'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2009/04/working-with-jbpm-workflows-in-alfresco_07.html' title='Working with jBPM workflows in Alfresco - Part 2: Embedded Alf - SDK'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-2880828885987725791</id><published>2009-04-07T07:24:00.000-07:00</published><updated>2009-05-13T03:52:44.676-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='working with workflows'/><category scheme='http://www.blogger.com/atom/ns#' term='BPM'/><category scheme='http://www.blogger.com/atom/ns#' term='jBPM'/><title type='text'>Working with jBPM workflows in Alfresco - Part 1: jBPM</title><content type='html'>The following set of blog articles will track my usage of jBPM in Alfresco to help orchestrate external content processing for publishing, and integrate with Review and Approval Advanced workflows.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;My starting point is &lt;a href="http://ecmarchitect.com/"&gt;Jeff Potts articles and blogs&lt;/a&gt; on &lt;a href="http://ecmarchitect.com/alfresco-developer-series"&gt;advanced workflows.&lt;/a&gt; Also read &lt;a href="http://ecmarchitect.com/archives/2008/10/29/862"&gt;his book&lt;/a&gt;!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Also, read the &lt;a href="http://wiki.alfresco.com/wiki/Workflow_Reqs_and_Design"&gt;Alfresco wiki documentation on workflows&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.jboss.org/jbossjbpm/"&gt;jBoss jBPM documentation&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 1 - Design&lt;/span&gt;&lt;br /&gt;In order to collaborate with external publishing processes, we have chosen to use JMS topics. This approach offers robustness and flexibility in communication. The workflow described here will be an 'orchestration' workflow. Its responsibility is to call out external processes and monitor progress. This workflow will be associated to content, however, the content will be in the form of a 'work order' that is created when a user requests to publish a set of content. The user may view the workflow on this work order to see the progress of the external processes orchestrated by the workflow. Later on, we will integrate with the publish review and approve workflow where user tasks will be created to coordinate user activity.&lt;br /&gt;&lt;br /&gt;Alfresco will be the container for the orchestration workflows. Actions in the workflow will be responsible for creating and sending messages to JMS topics to choreograph external publishing processes. A simulator will be used to act as the publisher processes for testing purposes. ActiveMQ is used as the JMS provider in these examples. There will also be a message handler created with the responsibi8lity of subscribing to topics that the publisher processes use to provide feedback and communicate status to the workflow. The following diagram represents this intended configuration.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QVQz3EsVFfA/SdtrPnNjxJI/AAAAAAAAACI/QtQqbfVPib4/s1600-h/Alf-BPM-Publishing.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 296px;" src="http://3.bp.blogspot.com/_QVQz3EsVFfA/SdtrPnNjxJI/AAAAAAAAACI/QtQqbfVPib4/s320/Alf-BPM-Publishing.png" alt="" id="BLOGGER_PHOTO_ID_5321965300636435602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Component descriptions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Alfresco&lt;/span&gt; - contains jbpm implementation and content being workflowed&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jBPM&lt;/span&gt; - library for jBPM accessed via the workflowService&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;process definition&lt;/span&gt; - jBPM process defining the process steps to orchestrate the publishing process&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;content event producer action&lt;/span&gt; - BPM action invoked from process to publish a content event message to the content topic&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;content event message&lt;/span&gt; - jms message indicating which content to publish and where to publish too&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;content event topic&lt;/span&gt; - jms topic storing the content event messages to be processed by the publisher&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;content event consumer&lt;/span&gt; - consumes content event messages and calls publishing services to invoke the publishing processes&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;publish process&lt;/span&gt; - implements the publishing functionality and calls publisher event producer to&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;publish event producer&lt;/span&gt; - creates and publishes publish event messages to the publish event topic indicating status of publishing&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;publish event consumer handler&lt;/span&gt; - consumes publish event messages and signals corresponding transitions on the publish process definition via the jbpm library&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 2 - Environment Setup&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Install Alfresco SDK: follow instructions on the &lt;a href="http://wiki.alfresco.com/wiki/Alfresco_SDK"&gt;alfresco wiki&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Install ActiveMQ: follow the instructions on the &lt;a href="http://activemq.apache.org/getting-started.html"&gt;ActiveMQ site&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Install jBPM (3.2.x): follow the instructions on the &lt;a href="http://docs.jboss.com/jbpm/v3.2/userguide/html/gettingstarted.html"&gt;JBoss jBPM&lt;/a&gt; site: I installed &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=70542&amp;package_id=145174"&gt;jbpm-3.2.2&lt;/a&gt; for best compatibility with Alfresco&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Install &lt;a href="http://docs.jboss.org/tools/2.0.0.GA/jbpm/en/html/index.html"&gt;jBPM Process Designer&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;Note: compatibility problems. As of Alfresco 3.1, the jBPM 3.2.2 is supported. The only issue I had with this version is that there are no hibernate tasks for the Mail Node.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 3 - Create the Eclipse Project&lt;/span&gt;&lt;br /&gt;For this project, I created a project called 'orchestration -example' using the jboss - jbpm process project' wizard.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 4 - Create the process&lt;/span&gt;&lt;br /&gt;The following image shows the workflow configuration created to orchestrate and monitor the publishing process.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QVQz3EsVFfA/Sdtt7LiZ71I/AAAAAAAAACQ/LyWt21_hEE4/s1600-h/processimage.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 306px; height: 228px;" src="http://3.bp.blogspot.com/_QVQz3EsVFfA/Sdtt7LiZ71I/AAAAAAAAACQ/LyWt21_hEE4/s320/processimage.jpg" alt="" id="BLOGGER_PHOTO_ID_5321968248145178450" border="0" /&gt;&lt;/a&gt;Workflow states:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Start&lt;/span&gt; - initial state when workflow is created&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Requested&lt;/span&gt; - state indicating that a request was made to the publisher (the content event msg was sent to the content topic)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Processing&lt;/span&gt; - state indicating that the publisher has received the request and is processing&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Succeeded&lt;/span&gt; - the publish process completed normally&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Failed&lt;/span&gt; - the publish process failed&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;End&lt;/span&gt; - workflow has ended&lt;/li&gt;&lt;/ul&gt;Using this workflow, the state can be queried to indicate the status of the publishing process.&lt;br /&gt;Here is the first version of this process definition:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="publishContentBasic"&amp;gt;&lt;br /&gt;&amp;lt;start-state name="start"&amp;gt;&lt;br /&gt;&amp;lt;transition name="to_requested" to="requested"&amp;gt;&lt;br /&gt;  &amp;lt;action name="action" class="com.sample.action.MessageActionHandler"&amp;gt;&lt;br /&gt;      &amp;lt;message&amp;gt;Going to the first state - requested!&amp;lt;/message&amp;gt;&lt;br /&gt;  &amp;lt;/action&amp;gt;&lt;br /&gt;&amp;lt;/transition&amp;gt;&lt;br /&gt;&amp;lt;/start-state&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;state name="requested"&amp;gt;&lt;br /&gt;&amp;lt;transition to="processing" name="to_processing"&amp;gt;&amp;lt;/transition&amp;gt;&lt;br /&gt;&amp;lt;/state&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;state name="processing"&amp;gt;&lt;br /&gt;&amp;lt;transition to="succeeded" name="to_succeeded"&amp;gt;&amp;lt;/transition&amp;gt;&lt;br /&gt;&amp;lt;transition to="failed" name="to_failed"&amp;gt;&amp;lt;/transition&amp;gt;&lt;br /&gt;&amp;lt;/state&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;state name="succeeded"&amp;gt;&lt;br /&gt;&amp;lt;transition to="end" name="to_end"&amp;gt;&lt;br /&gt;&amp;lt;action name="action" class="com.sample.action.MessageActionHandler"&amp;gt;&lt;br /&gt;      &amp;lt;message&amp;gt;About to finish - succeeded!&amp;lt;/message&amp;gt;&lt;br /&gt;  &amp;lt;/action&amp;gt;&lt;br /&gt;&amp;lt;/transition&amp;gt;&lt;br /&gt;&amp;lt;/state&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;state name="failed"&amp;gt;&lt;br /&gt;&amp;lt;transition to="end" name="to_end"&amp;gt;&lt;br /&gt;  &amp;lt;action name="action" class="com.sample.action.MessageActionHandler"&amp;gt;&lt;br /&gt;      &amp;lt;message&amp;gt;About to finish - failed!&amp;lt;/message&amp;gt;&lt;br /&gt;  &amp;lt;/action&amp;gt;&lt;br /&gt;&amp;lt;/transition&amp;gt;&lt;br /&gt;&amp;lt;/state&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;end-state name="end"&amp;gt;&amp;lt;/end-state&amp;gt;&lt;br /&gt;&amp;lt;/process-definition&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This first configuration of the process is basic and simple. It will be embellished later with processing and business logic. This example uses the &lt;span style="font-family:courier new;"&gt;com.sample.action.MessageActionHandler&lt;/span&gt; class that is created by default using the 'create jbpm project' option in Eclipse.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 5 - The first test&lt;/span&gt;&lt;br /&gt;In this first pass, we are using jBPM out of the box, without Alfresco. This mode allows us to configure and test our process in as much isolation as possible. Later we will use the Alfresco SDK to run as an Embedded Alfresco when we need Alfresco workflow services.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;package com.sample;&lt;br /&gt;&lt;br /&gt;import junit.framework.TestCase;&lt;br /&gt;&lt;br /&gt;import org.jbpm.graph.def.ProcessDefinition;&lt;br /&gt;import org.jbpm.graph.exe.ProcessInstance;&lt;br /&gt;&lt;br /&gt;public class PublishContentBasicProcessTest extends TestCase {&lt;br /&gt;&lt;br /&gt;public void testSimpleProcess() throws Exception {&lt;br /&gt;&lt;br /&gt;  // Extract a process definition from the processdefinition.xml file.&lt;br /&gt;  ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("publishContentBasic/processdefinition.xml");&lt;br /&gt;  assertNotNull("Definition should not be null", processDefinition);&lt;br /&gt;&lt;br /&gt;  // Create an instance of the process definition.&lt;br /&gt;  ProcessInstance instance = new ProcessInstance(processDefinition);&lt;br /&gt;  assertEquals(&lt;br /&gt;          "Instance is in start state",&lt;br /&gt;          instance.getRootToken().getNode().getName(),&lt;br /&gt;          "start");&lt;br /&gt;  assertNull(&lt;br /&gt;          "Message variable should not exist yet",&lt;br /&gt;          instance.getContextInstance().getVariable("message"));&lt;br /&gt;&lt;br /&gt;  // Move the process instance from its start state to the first state.&lt;br /&gt;  // The configured action should execute and the appropriate message&lt;br /&gt;  // should appear in the message process variable.&lt;br /&gt;  instance.signal();&lt;br /&gt;  assertEquals(&lt;br /&gt;          "Instance is in reqested state",&lt;br /&gt;          instance.getRootToken().getNode().getName(),&lt;br /&gt;          "requested");&lt;br /&gt;  assertEquals(&lt;br /&gt;          "Message variable contains message",&lt;br /&gt;          "Going to the first state - requested!",&lt;br /&gt;          instance.getContextInstance().getVariable("message"));&lt;br /&gt;&lt;br /&gt;  //move to processing state&lt;br /&gt;  instance.signal();&lt;br /&gt;  assertEquals(&lt;br /&gt;          "Instance is in processing state",&lt;br /&gt;          "processing",&lt;br /&gt;          instance.getRootToken().getNode().getName());&lt;br /&gt;&lt;br /&gt;  //move to succeeded state&lt;br /&gt;  instance.signal("to_succeeded");&lt;br /&gt;  assertEquals(&lt;br /&gt;          "Instance is in processing state",&lt;br /&gt;          "succeeded",&lt;br /&gt;          instance.getRootToken().getNode().getName());&lt;br /&gt;&lt;br /&gt;  // Move the process instance to the end state. The configured action&lt;br /&gt;  // should execute again. The message variable contains a new value.&lt;br /&gt;  instance.signal();&lt;br /&gt;  assertEquals(&lt;br /&gt;          "Instance is in end state",&lt;br /&gt;          "end",&lt;br /&gt;          instance.getRootToken().getNode().getName());&lt;br /&gt;  assertTrue("Instance has ended", instance.hasEnded());&lt;br /&gt;  assertEquals(&lt;br /&gt;          "Message variable contains message",&lt;br /&gt;          "About to finish!",&lt;br /&gt;          instance.getContextInstance().getVariable("message"));&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Next Part, on to running workflows in Alfresco Embedded mode and running alfresco scripts in the workflow.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-2880828885987725791?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/2880828885987725791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=2880828885987725791' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/2880828885987725791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/2880828885987725791'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2009/04/working-with-jbpm-workflows-in-alfresco.html' title='Working with jBPM workflows in Alfresco - Part 1: jBPM'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QVQz3EsVFfA/SdtrPnNjxJI/AAAAAAAAACI/QtQqbfVPib4/s72-c/Alf-BPM-Publishing.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-6015687551174806767</id><published>2009-01-08T10:02:00.000-08:00</published><updated>2009-04-12T06:51:17.680-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='extending share'/><title type='text'>Extending Share 3 - Adding new pages to share</title><content type='html'>In a previous blog article '&lt;a href="http://edlovesjava.blogspot.com/2008/12/extending-share-2-adding-new-content.html"&gt;Extending Share 2 - Adding a New Content button to Document Library&lt;/a&gt;', we walked through the process of modifying Document Library to add a new toolbar component that included a button titled 'New Content'. In this article, We will walk through the process of creating a new page for Share that can be included for a site, adding to the existing pages including wiki, blog, discussion, document library, calendar etc. that can be selected from the site navigation bar. As an example, the new page we add will present a new view of document library content, leveraging some existing components form the Document Library page such as the tree navigation component.&lt;br /&gt;&lt;br /&gt;This blog article will add these new pages into the share extension project structure discussed in the previous blog article '&lt;a href="http://edlovesjava.blogspot.com/2008/12/extending-share-1-creating-share.html"&gt;Extending Share 1 - Creating a share extension project&lt;/a&gt;' that provides a clean way to isolate our changes from the existing share code. The new page will be able to be added to existing or new sites by using the 'Customize Site' feature of the site dashboard and selecting the new page.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 1 - Setting up the project&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We will start with creating a project structure similar to that referenced in the previous blog article '&lt;a href="http://edlovesjava.blogspot.com/2008/12/extending-share-1-creating-share.html"&gt;Extending Share 1 - Creating a share extension project&lt;/a&gt;' and the latest &lt;a href="http://wiki.alfresco.com/wiki/Alfresco_SDK"&gt;Alfresco SDK&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;1. Create a new project (i.e. 'someco-share-extension') with the following source directories :&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;source/java - contains java code to be packaged in someco-share-ext.jar&lt;/li&gt;&lt;li&gt;config/alfresco/web-extension - contains 'web-framework-config-custom.xml'&lt;/li&gt;&lt;li&gt;config/alfresco/web-extension/site-data - contains custom model objects like pages, template-instances, and components&lt;br /&gt;&lt;/li&gt;&lt;li&gt;config/alfresco/web-extension/site-webscripts containing folder /com/someco to contain webscripts in a unique namespace&lt;br /&gt;&lt;/li&gt;&lt;li&gt;config/alfresco/templates - contains custom templates containing folder /com/someco to contain templates in unique namespace&lt;br /&gt;&lt;/li&gt;&lt;li&gt;source/web - contains web assets and delivered to the war, used for javascript and css as included by html templates&lt;br /&gt;&lt;/li&gt;&lt;li&gt;lib - contains required library elements (includes junit.jar for testing&lt;br /&gt;&lt;/li&gt;&lt;li&gt;test - contains java test code and configuration&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I created each of these folders as a 'source directory' in Eclipse.  Source directories in Eclipse automatically copy files to the classpath. This project depends on SDK Embedded to allow embedded testing (unit testing of custom data web scripts) (see the '&lt;a href="http://edlovesjava.blogspot.com/2008/12/writing-webscripts-1-unit-testing-web.html"&gt;Unit Testing Web Scripts&lt;/a&gt;' blog article for using the SDK to run embedded unit tests of data web scripts.&lt;br /&gt;&lt;br /&gt;2. Create the 'web-framework-config-custom.xml' file in the to contain a reference to our new page so that it can be included by customizing a site.&lt;br /&gt;&lt;br /&gt;3. Copy the ant build.xml file from the source in the previous '&lt;a href="http://edlovesjava.blogspot.com/2008/12/extending-share-1-creating-share.html"&gt;Extending Share&lt;/a&gt;' blog article into the root of the project. This build script has some handy tasks. Some of which were derived from the great works by &lt;a href="http://ecmarchitect.com/"&gt;Jeff Potts&lt;/a&gt; and his great new book &lt;a href="http://www.packtpub.com/alfresco-developer-guide/book"&gt;Alfresco Developers Guide from Packt Publishing&lt;/a&gt;. Make sure to change the project name in the build.xml file as appropriate (i.e. 'someco-share-extension').&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The 'deploy' tasks will  call the 'package' task and copy the created jar to the APP_TOMCAT_HOME/WEB-INF/lib directory (should be configured to point to the expanded share war file directory in tomcat), and copy the contents of the 'source/web' and 'config/alfresco/*' folders to the APP_TOMCAT_HOME/WEB-INF/classes/alfresco directory.&lt;/li&gt;&lt;li&gt;The 'package' task will call the 'compile' taks and create a jar (someco-share-ext.jar) including our java code in the source/java folder, web scripts in the 'config/someco/site-webscripts' and templates in the 'config/someco/templates' folders. &lt;/li&gt;&lt;/ul&gt;Make sure APP_TOMCAT_HOME environment variable is configured to point to the directory where share war is deployed. In Eclipse, you can add this to the ant configuration (windows &gt; preferences &gt; ant &gt; runtime, 'properties' tab as env.APP_TOMCAT_HOME).&lt;br /&gt;&lt;br /&gt;4. Create (or copy) the build.properties file to the project root directory containing the following:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;#directory names&lt;br /&gt;&lt;br /&gt;dir.name.assemble=assemble&lt;br /&gt;dir.name.bin=bin&lt;br /&gt;dir.name.build=build&lt;br /&gt;dir.name.classes=classes&lt;br /&gt;dir.name.config=config&lt;br /&gt;dir.name.source=source&lt;br /&gt;dir.name.devenv=devenv&lt;br /&gt;dir.name.dist=dist&lt;br /&gt;dir.name.distro=distro&lt;br /&gt;dir.name.docs=docs&lt;br /&gt;dir.name.generated=generated&lt;br /&gt;dir.name.java=java&lt;br /&gt;dir.name.lib=lib&lt;br /&gt;dir.name.test.results=&lt;br /&gt;dir.name.test.results=test-results&lt;br /&gt;dir.name.test.resources=test-resources&lt;br /&gt;dir.name.web=web&lt;br /&gt;&lt;br /&gt;file.name.jar=someco-share-ext.jar&lt;br /&gt;&lt;br /&gt;dir.junit.lib=lib&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Now we are ready to start creating our custom configuration. You can adjust these to make the ant build work with your own project structure.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 2 - Creating the page and template instance&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To start out, we will create a new page called 'Content Grid' that is intended to display a list of content in a way similar to Document Library but as a grid showing meta-data and a content extract in columns. This extension follows the model object structure as outlined in the &lt;a href="http://wiki.alfresco.com/wiki/Surf_Platform_-_Developers_Guide"&gt;Alfresco Surf Platform - Developers Guide&lt;/a&gt; page, and analyzed in the '&lt;a href="http://edlovesjava.blogspot.com/2008/10/examining-slingshot-configuration.html"&gt;Learning Surf 2 - Examining Slingshot configuration&lt;/a&gt;' blog article.&lt;br /&gt;&lt;br /&gt;The custom model objects we create will be added to the 'config/alfresco/web-extension' source directory. The contents of this directory will be copied into the Share war directory using the &lt;span style="font-weight: bold;"&gt;ant deploy&lt;/span&gt; task in the Ant build file.&lt;br /&gt;&lt;br /&gt;1. Create 'contentgrid.xml' file in the 'pages' folder of the 'source/alfresco/web-extension/site-data' source directory, with the following content:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;br /&gt;&amp;lt;page&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;Content Grid&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;Document library with Tree view&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;template-instance&amp;gt;contentgrid&amp;lt;/template-instance&amp;gt;&lt;br /&gt;&amp;lt;authentication&amp;gt;user&amp;lt;/authentication&amp;gt;&lt;br /&gt;&amp;lt;/page&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This defines a page with the title 'Content Grid'. It refers to a template instance called 'contentgrid' defined next.&lt;br /&gt;&lt;br /&gt;2. Create the 'contentgrid.xml' template instance in the 'template-instances' folder of the 'config/alfresco/web-extension/site-data' source folder with the following contents:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;br /&gt;&amp;lt;template-instance&amp;gt;&lt;br /&gt;&amp;lt;template-type&amp;gt;org/alfresco/simple-contentgrid&amp;lt;/template-type&amp;gt;&lt;br /&gt;&amp;lt;properties&amp;gt;&lt;br /&gt;&amp;lt;hasBreadcrumb&amp;gt;true&amp;lt;/hasBreadcrumb&amp;gt;&lt;br /&gt;&amp;lt;hasTreeview&amp;gt;true&amp;lt;/hasTreeview&amp;gt;&lt;br /&gt;&amp;lt;hasPackager&amp;gt;true&amp;lt;/hasPackager&amp;gt;&lt;br /&gt;&amp;lt;/properties&amp;gt;&lt;br /&gt;&amp;lt;/template-instance&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This file tells Surf to use the template found from path org/alfresco/contentgrid path of the config/alfresco/templates folder.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 3 - Creating the template type&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The template we will create first will be a simple test template with no functionality, to test our configuration and deployment. This template is a gutted out version of the documentlibrary.ftl found in the config/alfresco/templates source folder in the org/alfresco package.  It includes a standard  set of  included global regions with a simple body announcing that the template has rendered.&lt;br /&gt;&lt;br /&gt;1. Create 'simple-contentgrid.ftl' freemarker template in the org/alfresco path of the 'config/alfresco/templates' source folder with the following contents:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;#import "/org/alfresco/import/alfresco-template.ftl" as template /&amp;gt;&lt;br /&gt;&amp;lt;@template.header&amp;gt;&lt;br /&gt;&amp;lt;link rel="stylesheet" type="text/css" href="${url.context}/templates/documentlibrary/documentlibrary.css" /&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;//&amp;lt;![CDATA[&lt;br /&gt;(function()&lt;br /&gt;{&lt;br /&gt;// If no location.hash exists, convert a location.search to a location.hash and replace the page&lt;br /&gt;var loc = window.location;&lt;br /&gt;if (loc.hash === "" &amp;amp;&amp;amp; loc.search !== "")&lt;br /&gt;{&lt;br /&gt; var url = loc.protocol + "//" + loc.host + loc.pathname + "#" + loc.search.substring(1);&lt;br /&gt; window.location.replace(url);&lt;br /&gt;}&lt;br /&gt;})();&lt;br /&gt;//]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${url.context}/templates/documentlibrary/documentlibrary.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${url.context}/modules/documentlibrary/doclib-actions.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/@&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;@template.body&amp;gt;&lt;br /&gt;&amp;lt;div id="hd"&amp;gt;&lt;br /&gt;&amp;lt;@region id="header" scope="global" protected=true /&amp;gt;&lt;br /&gt;&amp;lt;@region id="title" scope="template" protected=true /&amp;gt;&lt;br /&gt;&amp;lt;@region id="navigation" scope="template" protected=true /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div id="bd"&amp;gt;&lt;br /&gt;This is the Content Grid template&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;/@&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;@template.footer&amp;gt;&lt;br /&gt;&amp;lt;div id="ft"&amp;gt;&lt;br /&gt;&amp;lt;@region id="footer" scope="global" protected=true /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/@&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;2. Modify 'web-framework-config-custom.xml' file in the 'config/alfresco/web-extensions' folder to add a reference to the new page we just created to allow this page to be added when customizing the site. It should read:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;alfresco-config&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;config evaluator="string-compare" condition="SitePages" replace="true"&amp;gt;&lt;br /&gt;&amp;lt;pages&amp;gt;&lt;br /&gt;   &amp;lt;page id="calendar"&amp;gt;calendar&amp;lt;/page&amp;gt;&lt;br /&gt;   &amp;lt;page id="wiki-page"&amp;gt;wiki-page?title=Main_Page&amp;lt;/page&amp;gt;&lt;br /&gt;   &amp;lt;page id="documentlibrary"&amp;gt;documentlibrary&amp;lt;/page&amp;gt;&lt;br /&gt;   &amp;lt;page id="contentgrid"&amp;gt;contentgrid&amp;lt;/page&amp;gt;&lt;br /&gt;   &amp;lt;page id="discussions-topiclist"&amp;gt;discussions-topiclist&amp;lt;/page&amp;gt;&lt;br /&gt;   &amp;lt;page id="blog-postlist"&amp;gt;blog-postlist&amp;lt;/page&amp;gt;&lt;br /&gt;&amp;lt;/pages&amp;gt;&lt;br /&gt;&amp;lt;/config&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/alfresco-config&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;When Share is started, the new page will not be configured to display with any sites. The new page can be added to existing sites by using the 'customize site' feature. If you wish this new page to be automatically added to new sites, add it to the 'presets.xml' file.&lt;br /&gt;&lt;br /&gt;3. Run the ant deploy task to copy the configuration components to the deployed share war (APP_TOMCAT_HOME/webapps/share)&lt;br /&gt;&lt;br /&gt;4. Start alfresco and share by starting tomcat&lt;br /&gt;&lt;br /&gt;5. Login to share&lt;br /&gt;&lt;br /&gt;6. Create the new site (or select it if already created)&lt;br /&gt;&lt;br /&gt;7. Select the 'Customize Site' button and click 'Add Page' and select the 'Content Grid' page. The 'Content Grid' page should be added to the navigation bar.&lt;br /&gt;&lt;br /&gt;8. Press this option to see the page we just created with the simple-contentgrid.ftl template. The message 'This is the Content Grid template' should be displayed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 4 - Mapping the page components&lt;/span&gt;&lt;br /&gt;Now we can advance to a more interesting page template. The previous simple-contentgrid.ftl only demonstrated that we could add a page and it would render, now we will create a page template that will be similar to the Document Library template, but display our custom grid view UI.&lt;br /&gt;1. create contentgrid.ftl in the /org/alfresco directory of the /config/alfresco/templates source folder, with containing the following:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;#import "/org/alfresco/import/alfresco-template.ftl" as template /&amp;gt;&lt;br /&gt;&amp;lt;@template.header&amp;gt;&lt;br /&gt;&amp;lt;link rel="stylesheet" type="text/css" href="${url.context}/templates/documentlibrary/documentlibrary.css" /&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;//&amp;lt;![CDATA[&lt;br /&gt;(function()&lt;br /&gt;{&lt;br /&gt; // If no location.hash exists, convert a location.search to a location.hash and replace the page&lt;br /&gt; var loc = window.location;&lt;br /&gt; if (loc.hash === "" &amp;amp;&amp;amp; loc.search !== "")&lt;br /&gt; {&lt;br /&gt;    var url = loc.protocol + "//" + loc.host + loc.pathname + "#" + loc.search.substring(1);&lt;br /&gt;    window.location.replace(url);&lt;br /&gt; }&lt;br /&gt;})();&lt;br /&gt;//]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${url.context}/templates/documentlibrary/documentlibrary.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${url.context}/modules/documentlibrary/doclib-actions.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/@&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;@template.body&amp;gt;&lt;br /&gt;&amp;lt;div id="hd"&amp;gt;&lt;br /&gt; &amp;lt;@region id="header" scope="global" protected=true /&amp;gt;&lt;br /&gt; &amp;lt;@region id="title" scope="template" protected=true /&amp;gt;&lt;br /&gt; &amp;lt;@region id="navigation" scope="template" protected=true /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div id="bd"&amp;gt;&lt;br /&gt; &amp;lt;div class="yui-t1" id="divDocLibraryWrapper"&amp;gt;&lt;br /&gt;    &amp;lt;div id="yui-main"&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-b" id="divDocLibraryDocs"&amp;gt;&lt;br /&gt;          &amp;lt;@region id="toolbar" scope="template" protected=true /&amp;gt;&lt;br /&gt;          &amp;lt;@region id="gridview" scope="template" protected=true /&amp;gt;&lt;br /&gt;       &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;div class="yui-b" id="divDocLibraryFilters"&amp;gt;&lt;br /&gt;       &amp;lt;@region id="filter" scope="template" protected=true /&amp;gt;&lt;br /&gt;       &amp;lt;@region id="tree" scope="template" protected=true /&amp;gt;&lt;br /&gt;       &amp;lt;@region id="tags" scope="template" protected=true /&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt; &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;/@&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;@template.footer&amp;gt;&lt;br /&gt;&amp;lt;div id="ft"&amp;gt;&lt;br /&gt; &amp;lt;@region id="footer" scope="global" protected=true /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/@&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This template contains several regions, some global and some template specific. The template specific regions must have component configuraton xml files to indicate what ui webscript will be used to render in that region. The components follow a naming convention: &lt;scope&gt;.&lt;region&gt;.&lt;template&gt;.xml. Each template contains the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a scope (global or template in our example)&lt;/li&gt;&lt;li&gt;a region-id refering to the region of the template&lt;/li&gt;&lt;li&gt;a source-id refering to the template&lt;/li&gt;&lt;li&gt;a url refering to the ui web script to render in this region&lt;/li&gt;&lt;/ul&gt;Components are found in the share webapp in WEB-INF/classes/alfresco/site-data/components. To start with, we will copy similar 'template' scope components from the documentlibrary template. For each of these 'template' components, we will also have to change the source-id value to refer to our 'contentgrid' template. We will just use the existing 'global' templates as is.&lt;br /&gt;&lt;table cellpadding="4"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Region&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Scope&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Component&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;header&lt;/td&gt;&lt;td&gt;global&lt;/td&gt;&lt;td&gt;global.header.xml exists&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;title&lt;/td&gt;&lt;td&gt;template&lt;/td&gt;&lt;td&gt;template.title.contentgrid.xml copied from template.title.documentlibrary.xml&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;navigation&lt;/td&gt;&lt;td&gt;template&lt;/td&gt;&lt;td&gt;template.navigation.contentgrid.xml copied from template.navigation.documentlibrary.xml&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;toolbar&lt;/td&gt;&lt;td&gt;template&lt;/td&gt;&lt;td&gt;template.toolbar.contentgrid.xml copied from template.toolbar.documentlibrary.xml&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;gridview&lt;/td&gt;&lt;td&gt;template&lt;/td&gt;&lt;td&gt;template.gridview.contentgrid.xml created new&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;filter&lt;/td&gt;&lt;td&gt;template&lt;/td&gt;&lt;td&gt;template.filter.contentgrid.xml copied from template.filter.documentlibrary.xml&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;tree&lt;/td&gt;&lt;td&gt;template&lt;/td&gt;&lt;td&gt;template.tree.contentgrid.xml copied from template.tree.documentlibrary.xml&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;tags&lt;/td&gt;&lt;td&gt;template&lt;/td&gt;&lt;td&gt;template.tags.contentgrid.xml copied from template.tags.documentlibrary.xml&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;footer&lt;/td&gt;&lt;td&gt;global&lt;/td&gt;&lt;td&gt;global.footer.xml exists&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;All the other template components should be copied as is, with the source-id changed to refer to the 'contentgrid' template. The 'template.gridview.contentgrid.xml' component is new. Create the 'template.gridview.contentgrid.xml' file to contain our custom view. It should contain the following:&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;br /&gt;&amp;lt;component&amp;gt;&lt;br /&gt;  &amp;lt;scope&amp;gt;template&amp;lt;/scope&amp;gt;&lt;br /&gt;  &amp;lt;region-id&amp;gt;gridview&amp;lt;/region-id&amp;gt;&lt;br /&gt;  &amp;lt;source-id&amp;gt;contentgrid&amp;lt;/source-id&amp;gt;&lt;br /&gt;  &amp;lt;url&amp;gt;/someco/components/contentgrid/gridview&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;/component&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Create a temporary ui webscript to render a simple message. In the alfresco/site-webscripts source folder, create folders com/orbitz/components/contentgrid to contain our ui webscripts supporting the content grid. Create the following three files:&lt;br /&gt;&lt;br /&gt;gridview.get.desc.xml&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;webscript&amp;gt;&lt;br /&gt;  &amp;lt;shortname&amp;gt;gridview&amp;lt;/shortname&amp;gt;&lt;br /&gt;  &amp;lt;description&amp;gt;A simple grid view to view content in a grid layout&amp;lt;/description&amp;gt;&lt;br /&gt;  &amp;lt;url&amp;gt;/orbitz/components/contentgrid/gridview&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;/webscript&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;gridview.get.html.ftl&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;This is the grid view!&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;gridview.get.properties&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;## Titles&lt;br /&gt;title=New Content&lt;br /&gt;header=New Content Details&lt;br /&gt;&lt;br /&gt;## Labels&lt;br /&gt;label.name=Name&lt;br /&gt;label.title=Title&lt;br /&gt;label.description=Description&lt;br /&gt;label.content=Content&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The last file 'gridview.get.properties' isn't needed yet, but we should have it around when we need it.&lt;br /&gt;&lt;br /&gt;Next, modify the contentgrid.xml file in the config/alfresco/site-data/template directory to reference this 'contentgrid.ftl' template.&lt;br /&gt;&lt;br /&gt;Finally, create a content template: . Restart the Share app and navigate to the site where this page is configured, and view the page. It should render similar to the document library page.&lt;br /&gt;&lt;br /&gt;Now we can test our new contentgrid template with our temporary ui webscript displayed. Deploy (ant deploy) and restart Share. Navigate to our site and display the 'content grid' page.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 5 - Creating a new page component using ui web scripts&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;The next blog articles will add the desired functionality to share as time allows. We will create a new UI web script that calls a data webscript that serves the metadata and content extract from the document library to display in a grid form. &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/template&gt;&lt;/region&gt;&lt;/scope&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-6015687551174806767?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/6015687551174806767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=6015687551174806767' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6015687551174806767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6015687551174806767'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2009/01/extending-share-3-adding-new-pages-to.html' title='Extending Share 3 - Adding new pages to share'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-1962204234078766578</id><published>2008-12-19T14:15:00.000-08:00</published><updated>2009-01-08T08:38:58.050-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><title type='text'>Writing Webscripts 1 - Unit Testing Web Scripts</title><content type='html'>There is a big push in the &lt;a href="http://www.agilealliance.org/"&gt;agile community&lt;/a&gt; to develop code using a &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;Test Driven Development&lt;/a&gt; approach. This could be anything from 'test first' &lt;a href="http://www.extremeprogramming.org/"&gt;extreme programming&lt;/a&gt; to assuring a certain coverage metric is achieved with unit tests that accompany delivered code. Either case, the test driven approach yields better code in a shorter period of time, is more self documented, better factored, and is not as prone to chaos effects when changed.  Should web scripts be subject to unit testing? I believe it is important to test at least the data web scripts using a testing harness like &lt;a href="http://www.martinfowler.com/bliki/Xunit.html"&gt;xUnit&lt;/a&gt; that can be run during builds or in continuous integration. There are examples of this type of test within the &lt;a href="http://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/HEAD/root/projects/remote-api/source/test/java/org/alfresco/repo/cmis/ws/"&gt;Alfresco 3.0 source tree&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This blog entry will focus on creating a project in Eclipse that leverages the &lt;a href="http://wiki.alfresco.com/wiki/Installing_Labs_3#Alfresco_SDK_and_APIs"&gt;Alfresco SDK&lt;/a&gt; (currently 3c) to test and deploy web scripts to the Alfresco repository. These unit tests will run with Embedded Alfresco configuration to be as self-contained as possible. Although these tests will not be unit tests in the strictest sense of the word, they will help facilitate more rapid development of code with the appropriate tests within an IDE. These tests can also be run as part of continuous integration.&lt;br /&gt;&lt;br /&gt;The sourcecode for this article is available from &lt;a href="http://www.wentsoft.com/unit-test-webscripts.tar.gz"&gt;this site&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step 1 - Download and Install SDK with Eclipse&lt;/span&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;Follow the &lt;a href="http://wiki.alfresco.com/wiki/Alfresco_SDK"&gt;Alfresco SDK wiki page&lt;/a&gt; to install the SDK. Essentially, you will execute the following steps:&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Download &lt;a href="http://wiki.alfresco.com/wiki/Installing_Labs_3#Alfresco_SDK_and_APIs"&gt;alfresco-sdk-3c&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Import into Eclipse&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Add dependency libraries to SDK AlfrescoEmbedded&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Validate with SDK FirstFoundationClient&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step 2 - Setup the project&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;In order to run unit tests that test data web scripts properly, we need to set up a project that can lauch Alfresco as an Embedded server, with sufficient configuration files to allow us to test our data web scripts. &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Here is a summary of the steps I followed:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Copy SDK FirstFoundatoinClient as a starting point.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Set project dependency to SDK AlfrescoEmbedded&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Modify dir.root of custom-repository.properties&lt;/li&gt;&lt;li&gt;Test run as application main of FirstFoundationClient &lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;To create the project 'unit-test-webscripts', I copied the SDK's FirstFoundationClient in Eclipse and renamed it to 'unit-test-webscripts'. This project should already reference the SDK AlfrescoEmbedded project, and be configured to run Alfresco as Embedded, but it will need to be altered to run web scripts this way. &lt;/div&gt;&lt;div&gt;Modify the 'custom-repository.properties' file to reference the alfresco data root directory that you have configured when running Alfresco. It will be necessary to reference the same dir.root as alfresco when it is run standalone to share a database instance on the same machine, and allow you to test in either embedded mode or remote mode. I also added the line 'index.recovery.mode=FULL' to force the indexer to recover any out of sync references.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At this point, you should be able to run the 'main' method of the FirstFoundationClass of this project with eclipse' 'Run as Application' to make sure all is well. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;NOTE: This step failed for me with a class not found error until I included a library reference to: alfresco-jlan-embed.jar in the java build path of the SDK AlfrescoEmbedded project and exported it.  &lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After running, you should see in the console the line 'Alfresco started' to indicate the test was completed. The result of the run should be a new content item created in the repository with the name 'Foundation API sample (&lt;span class="Apple-style-span" style="font-style: italic;"&gt;current Time in Milliseconds&lt;/span&gt;)' within the 'Company Home' folder. Start tomcat where alfresco is deployed and log in to view the Company Home folder. You should see the new files added. Make sure to stop tomcat before running embedded tests.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step 3 - Configure to Run Web scripts via embedded alfresco&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Once the project is copied and we can run the test class, we can now configure it to run our test webscripts.  To summarize the steps:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Create a source folder 'test' to contain configuration files and unit test code&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create a folder 'alfresco' within the 'test' source folder to which we will copy the necessary spring context files&lt;br /&gt;&lt;/li&gt;&lt;li&gt;copy web-scripts-application-context.xml from $TOMCAT_HOME/webapps/alfresco/WEB-INF/classes/alfresco to test/alfresco&lt;br /&gt;&lt;/li&gt;&lt;li&gt;copy webscript-framework-application-context.xml from $TOMCAT_HOME/webapps/alfresco/WEB-INF/classes/alfresco  to test/alfresco&lt;br /&gt;&lt;/li&gt;&lt;li&gt;copy web-scripts-application-context-test.xml from $TOMCAT_HOME/webapps/alfresco/WEB-INF/classes/alfresco  to test/alfresco&lt;br /&gt;&lt;/li&gt;&lt;li&gt;comment out web Script messages bean 'webscripts.resources' of webscript-framework-application-context.xml&lt;br /&gt;&lt;/li&gt;&lt;li&gt;copy web-scripts-config.xml from $TOMCAT_HOME/webapps/alfresco/WEB-INF/classes/alfresco  to test/alfresco&lt;/li&gt;&lt;li&gt;comment out bean 'webscript.org.alfresco.repository.dictionary.getchildassoc.get' from web-scripts-application-context.xml since class 'org.afresco.repo.web.scripts.dictionary.GetChildAssociationDef' no longer exists in jars&lt;br /&gt;&lt;/li&gt;&lt;li&gt;comment out bean 'webscript.org.alfresco.repository.dictionary.getchildassocs.get' from web-scripts-application-context.xml since class 'org.afresco.repo.web.scripts.dictionary.GetChildAssociationDefs' no longer exists in jars&lt;br /&gt;&lt;/li&gt;&lt;li&gt;create required directory source/alfresco/templates/webscripts&lt;br /&gt;&lt;/li&gt;&lt;li&gt;create required directory source/alfresco/webscripts&lt;/li&gt;&lt;li&gt;copy webscript-framework-config.xml from  $TOMCAT_HOME/webapps/alfresco/WEB-INF/classes/alfresco  to test/alfresco&lt;/li&gt;&lt;li&gt;create required directory source/alfresco/templates/activities&lt;/li&gt;&lt;li&gt;create directory source/alfresco/extension/templates/webscripts where our webscritps will go&lt;/li&gt;&lt;li&gt;copy 'status.ftl' from  $TOMCAT_HOME/webapps/alfresco/WEB-INF/classes/alfresco  to test/alfresco/extension/templates/webscripts to the new extension/templates/webscripts directory to provide a default status template&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Now the project is set up to run our webscripts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-weight: bold;"&gt;Step 4 - Write the unit test and webscript&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Add our data webscript to test into the source/alfresco/extension/templates/webscripts folder&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Create 'test.get.desc.xml' with the following contents:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;webscript&amp;gt;&lt;br /&gt;&amp;lt;shortname&amp;gt;test&amp;lt;/shortname&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;Return runas user name&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;format&amp;gt;argument&amp;lt;/format&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/someco/test&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;authentication runas="RunAsOne"&amp;gt;user&amp;lt;/authentication&amp;gt;&lt;br /&gt;&amp;lt;transaction&amp;gt;required&amp;lt;/transaction&amp;gt;&lt;br /&gt;&amp;lt;/webscript&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;This description describes the webscript 'someco/test' that will run as the user RunAsOne.&lt;br /&gt;Create 'test.get.html.ftl' with the following contents:&lt;br /&gt;&lt;div&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;${userName!"&amp;lt;notset&amp;gt;"}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This template will display the value of userName.&lt;br /&gt;Create 'test.get.js' with the following code:&lt;br /&gt;&lt;div&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;model.userName = person.properties.userName;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;This script will set the value of userName with the current userName we are running as.&lt;br /&gt;Thats it for the webscript. Now create the unit test into the test/org/someco directory called 'RunAsTest' to test the data webscript:&lt;br /&gt;&lt;div&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;package org.someco;&lt;br /&gt;&lt;br /&gt;import org.alfresco.model.ContentModel;&lt;br /&gt;import org.alfresco.repo.web.scripts.BaseWebScriptTest;&lt;br /&gt;import org.alfresco.service.cmr.security.AuthenticationService;&lt;br /&gt;import org.alfresco.service.cmr.security.PersonService;&lt;br /&gt;import org.alfresco.util.PropertyMap;&lt;br /&gt;import org.alfresco.web.scripts.TestWebScriptServer.GetRequest;&lt;br /&gt;import org.alfresco.web.scripts.TestWebScriptServer.Response;&lt;br /&gt;&lt;br /&gt;public class RunAsTest extends BaseWebScriptTest {&lt;br /&gt;  private AuthenticationService authenticationService;&lt;br /&gt;  private PersonService personService;&lt;br /&gt;&lt;br /&gt;  private static final String USER_ONE = "RunAsOne";&lt;br /&gt;&lt;br /&gt;  private static final String URL_GET_CONTENT = "/someco/test";&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  protected void setUp() throws Exception&lt;br /&gt;  {&lt;br /&gt;      super.setUp();&lt;br /&gt;&lt;br /&gt;      this.authenticationService = (AuthenticationService) getServer().getApplicationContext().getBean(&lt;br /&gt;              "AuthenticationService");&lt;br /&gt;      this.personService = (PersonService) getServer().getApplicationContext().getBean("PersonService");&lt;br /&gt;&lt;br /&gt;      // Create users&lt;br /&gt;      createUser(USER_ONE);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private void createUser(String userName)&lt;br /&gt;  {&lt;br /&gt;      if (this.authenticationService.authenticationExists(userName) == false)&lt;br /&gt;      {&lt;br /&gt;          this.authenticationService.createAuthentication(userName, "PWD".toCharArray());&lt;br /&gt;&lt;br /&gt;          PropertyMap ppOne = new PropertyMap(4);&lt;br /&gt;          ppOne.put(ContentModel.PROP_USERNAME, userName);&lt;br /&gt;          ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");&lt;br /&gt;          ppOne.put(ContentModel.PROP_LASTNAME, "lastName");&lt;br /&gt;          ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");&lt;br /&gt;          ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");&lt;br /&gt;&lt;br /&gt;          this.personService.createPerson(ppOne);&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  protected void tearDown() throws Exception&lt;br /&gt;  {&lt;br /&gt;      super.tearDown();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void testRunAs() throws Exception&lt;br /&gt;  {&lt;br /&gt;      Response response = sendRequest(new GetRequest(URL_GET_CONTENT), 200, "admin");&lt;br /&gt;      assertEquals(USER_ONE, response.getContentAsString());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;This test creates 'UserOne', runs the 'someco/test' webscript, and checks the result code as 200 (success) and to see if the user name this script 'run as' was returned in the response.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 5 - Run the unit test&lt;/span&gt;&lt;div&gt;&lt;br /&gt;In order to see results, you should copy the log4j.properties file from $TOMCAT_HOME/webapps/alfresco/WEB_INF/classes into your source directory and configure log4j.properties to show debugging information for running web scripts by setting 'log4j.logger.org.alfresco.web.scripts=debug' and 'log4j.logger.org.alfresco.repo.web.scripts=debug' as recommended in the logging session of the &lt;a href="http://wiki.alfresco.com/wiki/Web_Scripts_Framework#Logging"&gt;3.0 Web scripts Framework&lt;/a&gt; page of alfresco wiki.&lt;br /&gt;&lt;br /&gt;To run the test, simply select the test/com/someco/RunAsTest class in Eclipse and select the 'run as' JUnit test. The test should pass and the console should show something like 'Processed script url (get) /someco/test in 517.601ms' as its last line.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-weight: bold;"&gt;Step 6 - Deploy the web script&lt;/div&gt;&lt;div&gt;Once confirmed, the web script tested can be deployed either by uploading it to the Company Home/Data Dictionary/Web Scripts Extensions space or add the web scripts to the $TOMCAT_HOME/webapps/alfresco/WEB-INF/classes/alfresco/extension/templates/webscripts folder and restarting alfresco.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-1962204234078766578?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/1962204234078766578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=1962204234078766578' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/1962204234078766578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/1962204234078766578'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/12/writing-webscripts-1-unit-testing-web.html' title='Writing Webscripts 1 - Unit Testing Web Scripts'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-7366489627418091298</id><published>2008-12-08T13:53:00.001-08:00</published><updated>2009-04-11T09:19:54.314-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='extending share'/><title type='text'>Extending Share 2 - Adding a New Content button to Document Library</title><content type='html'>In the &lt;a href="http://edlovesjava.blogspot.com/2008/12/extending-share-1-creating-share.html"&gt;Extending Share 1 blog entry&lt;/a&gt;, we created a share extension project. Now we will write code to add a 'new content' button to the document library section of Share, based on the code created in the &lt;a href="http://edlovesjava.blogspot.com/2008/12/learning-surf-6-creating-webscript.html"&gt; learning surf 1-6 blog entries&lt;/a&gt;.&lt;br /&gt;&lt;div&gt;&lt;blockquote&gt;NOTE: the complete sourceocde for this project can be downloaded from &lt;a href="http://www.wentsoft.com/deals-share-extension.tar.gz"&gt;here.&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;font-size:130%;" &gt;&lt;span class="Apple-style-span"&gt;Step 1 - Create a new form component&lt;/span&gt;&lt;/span&gt;&lt;div&gt;We will create a ui web script to open a create content form. In the 'config/alfresco/site-webscripts' source folder in package 'com.orbitz.components.documentlibrary', add the following files:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-weight: bold;"&gt;create-content.get.desc.xml&lt;/div&gt;&lt;div&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;webscript&amp;gt;&lt;br /&gt;&amp;lt;shortname&amp;gt;create-content&amp;lt;/shortname&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;Create Content module primarily for Document Library&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/components/documentlibrary/create-content&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;/webscript&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div style="font-weight: bold;"&gt;create-content.get.html.ftl&lt;/div&gt;&lt;div&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;div id="${args.htmlid}-dialog" class="create-folder"&amp;gt;&lt;br /&gt;&amp;lt;div class="hd"&amp;gt;${msg("title")}&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="bd"&amp;gt;&lt;br /&gt;&amp;lt;form id="${args.htmlid}-form" action="" method="post" accept-charset="utf-8"&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-g"&amp;gt;&lt;br /&gt;&amp;lt;h2&amp;gt;${msg("header")}:&amp;lt;/h2&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-name"&amp;gt;${msg("label.name")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-u"&amp;gt;&amp;lt;input id="${args.htmlid}-name" type="text" name="name" tabindex="1" /&amp;gt;&amp;amp;nbsp;*&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-title"&amp;gt;${msg("label.title")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-u"&amp;gt;&amp;lt;input id="${args.htmlid}-title" type="text" name="title" tabindex="2" /&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-description"&amp;gt;${msg("label.description")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-u"&amp;gt;&amp;lt;textarea id="${args.htmlid}-description" name="description" rows="3" cols="20" tabindex="3" &amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-content"&amp;gt;${msg("label.content")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="yui-u"&amp;gt;&amp;lt;textarea id="${args.htmlid}-content" name="content" rows="3" cols="20" tabindex="3" &amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="bdft"&amp;gt;&lt;br /&gt;&amp;lt;input type="button" id="${args.htmlid}-ok" value="${msg("button.ok")}" tabindex="4" /&amp;gt;&lt;br /&gt;&amp;lt;input type="button" id="${args.htmlid}-cancel" value="${msg("button.cancel")}" tabindex="5" /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div style="font-weight: bold;"&gt;create-content.get.properties&lt;/div&gt;&lt;div&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;## Titles&lt;br /&gt;title=New Content&lt;br /&gt;header=New Content Details&lt;br /&gt;&lt;br /&gt;## Labels&lt;br /&gt;label.name=Name&lt;br /&gt;label.title=Title&lt;br /&gt;label.description=Description&lt;br /&gt;label.content=Content&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;To test the new form,&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Deploy the web script by running the 'deploy' an task. (Make sure that share was started at least once so that the share war is expanded in the webapps/share directory of tomcat, and that the APP_TOMCAT_HOME and TOMCAT_HOME is properly set. This will copy the web scripts to the share directory.&lt;/li&gt;&lt;li&gt;Start tomcat&lt;/li&gt;&lt;li&gt;Check the ui web script by going to the url &lt;a href="http://localhost:8080/share/service/components/documentlibrary/create-content?htmlid"&gt;http://localhost:8080/share/service/components/documentlibrary/create-content?htmlid &lt;/a&gt;which should render the form (without any CSS, though). &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;Step 2 - Create a new toolbar for Document Library adding the 'New Content' button&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;The document library toolbar will be modified to render the 'New Content' button linked to an action handler that will open the create-content form via the simple dialog mechanism. To do this, we will create a new toolbar component '/orbitz/components/documentlibrary/toolbar' that will augment the existing '/components/documentlibrary/toolbar' with minimal code replication. This is a bit dangerous since it is entirely possible that the document library toolbar will change over time, so perhaps overriding it in this way is not the best approach, however, I have tried to minimize the exposure to code change as much as possible. if others have a better approach, I would gladly accept it. The source for this new component will also be in the 'config/alfresco/site-webscripts' source folder in the 'com.orbitz.components.documentlibrary' package, with the following files:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;toobar.get.desc.xml&lt;br /&gt;&lt;/span&gt;&lt;span&gt;This component description alters the url to '/orbitz/component/documentlibrary/toolbar' which will have to be mapped for the 'toolbar' the region of the documentlibary template.&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;webscript&amp;gt;&lt;br /&gt;&amp;lt;shortname&amp;gt;DocLib Toolbar&amp;lt;/shortname&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;Document Library: Toolbar Component&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/orbitz/components/documentlibrary/toolbar&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;/webscript&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;toolbar.get.head.ftl&lt;br /&gt;&lt;/span&gt;&lt;span&gt;This is a copy of the original 'toolbar.get.head.ftl' with the addition of DocListOrbitzToolbar Assets including 'orbitz.toolbar.css' and 'orbitz.toolbar.js' which provide custom styles and behavior for the 'New Content' button.&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;!-- DocListOrbitzToolbar Assets --&amp;gt;&lt;br /&gt;&amp;lt;link rel="stylesheet" type="text/css" href="${page.url.context}/components/documentlibrary/orbitz.toolbar.css" /&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${page.url.context}/components/documentlibrary/orbitz.toolbar.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;!-- DocListToolbar Assets --&amp;gt;&lt;br /&gt;&amp;lt;link rel="stylesheet" type="text/css" href="${page.url.context}/components/documentlibrary/toolbar.css" /&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${page.url.context}/components/documentlibrary/toolbar.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;!-- Simple Dialog Assets --&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${page.url.context}/modules/simple-dialog.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;!-- File-Upload Assets --&amp;gt;&lt;br /&gt;&amp;lt;link rel="stylesheet" type="text/css" href="${page.url.context}/modules/flash-upload.css" /&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${page.url.context}/modules/flash-upload.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;link rel="stylesheet" type="text/css" href="${page.url.context}/modules/html-upload.css" /&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${page.url.context}/modules/html-upload.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" src="${page.url.context}/modules/file-upload.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;toolbar.get.html.ftl&lt;/span&gt;&lt;br /&gt;This is a copy of the original 'toolbar.get.html.ftl' with a new javascript block instantiating 'alfresco.DocListOrbitzToolbar' as well as 'Alfresco.DocListToolbar'. This new javascript object will be defined in the new javascript file 'orbitz.toolbar.js' referenced in 'toolbar.get.head.ftl' above. Also, the 'new-content' button is added beneath the 'new folder' button.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;script type="text/javascript"&amp;gt;//&amp;lt;![CDATA[&lt;br /&gt;new Alfresco.DocListToolbar("${args.htmlid}").setOptions(&lt;br /&gt;{&lt;br /&gt;siteId: "${page.url.templateArgs.site!""}"&lt;br /&gt;}).setMessages(&lt;br /&gt;${messages}&lt;br /&gt;);&lt;br /&gt;new Alfresco.DocListOrbitzToolbar("${args.htmlid}").setOptions(&lt;br /&gt;{&lt;br /&gt;siteId: "${page.url.templateArgs.site!""}"&lt;br /&gt;}).setMessages(&lt;br /&gt;${messages}&lt;br /&gt;);&lt;br /&gt;//]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;div id="${args.htmlid}-body" class="toolbar"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div id="${args.htmlid}-headerBar" class="header-bar flat-button"&amp;gt;&lt;br /&gt;&amp;lt;div class="new-folder hideable DocListTree"&amp;gt;&amp;lt;button id="${args.htmlid}-newFolder-button" name="newFolder"&amp;gt;${msg("button.new-folder")}&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="new-content hideable DocListTree"&amp;gt;&amp;lt;button id="${args.htmlid}-newContent-button" name="newContent"&amp;gt;${msg("button.new-content")}&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="separator hideable DocListTree"&amp;gt;&amp;amp;nbsp;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="file-upload hideable DocListTree"&amp;gt;&amp;lt;button id="${args.htmlid}-fileUpload-button" name="fileUpload"&amp;gt;${msg("button.upload")}&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="separator hideable DocListTree"&amp;gt;&amp;amp;nbsp;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="selected-items hideable DocListTree DocListFilter DocListTags"&amp;gt;&lt;br /&gt;&amp;lt;button class="no-access-check" id="${args.htmlid}-selectedItems-button" name="doclist-selectedItems-button"&amp;gt;${msg("menu.selected-items")}&amp;lt;/button&amp;gt;&lt;br /&gt;&amp;lt;div id="${args.htmlid}-selectedItems-menu" class="yuimenu"&amp;gt;&lt;br /&gt;&amp;lt;div class="bd"&amp;gt;&lt;br /&gt;&amp;lt;ul&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;a rel="" href="#"&amp;gt;&amp;lt;span class="onActionCopyTo"&amp;gt;${msg("menu.selected-items.copy")}&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;a rel="" href="#"&amp;gt;&amp;lt;span class="onActionMoveTo"&amp;gt;${msg("menu.selected-items.move")}&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;a rel="delete" href="#"&amp;gt;&amp;lt;span class="onActionDelete"&amp;gt;${msg("menu.selected-items.delete")}&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;a type="document" rel="" href="#"&amp;gt;&amp;lt;span class="onActionAssignWorkflow"&amp;gt;${msg("menu.selected-items.assign-workflow")}&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;a rel="permissions" href="#"&amp;gt;&amp;lt;span class="onActionManagePermissions"&amp;gt;${msg("menu.selected-items.manage-permissions")}&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;hr/&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;a rel="" href="#"&amp;gt;&amp;lt;span class="onActionDeselectAll"&amp;gt;${msg("menu.selected-items.deselect-all")}&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="rss-feed"&amp;gt;&amp;lt;button id="${args.htmlid}-rssFeed-button" name="rssFeed"&amp;gt;${msg("link.rss-feed")}&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div id="${args.htmlid}-navBar" class="nav-bar flat-button"&amp;gt;&lt;br /&gt;&amp;lt;div class="folder-up hideable DocListTree"&amp;gt;&amp;lt;button class="no-access-check" id="${args.htmlid}-folderUp-button" name="folderUp"&amp;gt;${msg("button.up")}&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="separator hideable DocListTree"&amp;gt;&amp;amp;nbsp;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div id="${args.htmlid}-breadcrumb" class="breadcrumb hideable DocListTree"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div id="${args.htmlid}-description" class="description hideable DocListFilter DocListTags"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;toobar.get.properties&lt;/span&gt;&lt;br /&gt;This is a copy of the original toolbar.get.properties with only a new couple of new properties:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;button.new-content&lt;/li&gt;&lt;li&gt;message.new-content&lt;/li&gt;&lt;/ul&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;## Buttons&lt;br /&gt;button.delete=Delete&lt;br /&gt;button.new-folder=New Folder&lt;br /&gt;button.new-content=New Content&lt;br /&gt;button.up=Up&lt;br /&gt;button.upload=Upload&lt;br /&gt;&lt;br /&gt;## Links&lt;br /&gt;link.rss-feed=RSS Feed&lt;br /&gt;&lt;br /&gt;## Drop-down Menus&lt;br /&gt;menu.selected-items=Selected Items...&lt;br /&gt;menu.selected-items.copy=Copy to...&lt;br /&gt;menu.selected-items.move=Move to...&lt;br /&gt;menu.selected-items.delete=Delete&lt;br /&gt;menu.selected-items.assign-workflow=Assign Workflow...&lt;br /&gt;menu.selected-items.manage-permissions=Manage Permissions...&lt;br /&gt;menu.selected-items.deselect-all=Deselect All&lt;br /&gt;&lt;br /&gt;## Pop-up Messages&lt;br /&gt;message.new-folder.success=Folder '{0}' created&lt;br /&gt;message.new-content.success=Content '{0}' created&lt;br /&gt;message.new-folder.failure=Could not create '{0}'&lt;br /&gt;message.new-content.failure=Could not create '{0}'&lt;br /&gt;message.multiple-delete.success=Successfully deleted {0} item(s)&lt;br /&gt;message.multiple-delete.failure=Could not delete items&lt;br /&gt;title.multiple-delete.confirm=Confirm Multiple Delete&lt;br /&gt;message.multiple-delete.confirm=Are you sure you want to delete the following {0} items?&lt;br /&gt;message.multiple-delete.please-wait=Please wait. Files being deleted...&lt;br /&gt;&lt;br /&gt;## Toolbar Modes&lt;br /&gt;description.path=&lt;br /&gt;description.path.more=&lt;br /&gt;description.all=All Documents in the Document Library&lt;br /&gt;description.all.more=&lt;br /&gt;description.editingMe=Documents I'm Editing&lt;br /&gt;description.editingMe.more=(working copies)&lt;br /&gt;description.editingOthers=Documents Others are Editing&lt;br /&gt;description.editingOthers.more=(working copies)&lt;br /&gt;description.recentlyModified=Documents Recently Modified&lt;br /&gt;description.recentlyModified.more=&lt;br /&gt;description.recentlyAdded=Documents Added Recently&lt;br /&gt;description.recentlyAdded.more=&lt;br /&gt;description.tag=Documents and Folders Tagged with&lt;br /&gt;description.tag.more={0}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Step 3, create the javascript to support the toolbar&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Within the 'source/web' source folder 'components.documentlibrary' package, the new javascript and css assets referenced in 'toolbar.get.head.ftl' are defined:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;orbitz.toolbar.js&lt;/span&gt;&lt;/div&gt;&lt;div&gt;This javascript creates a new object: 'Alfresco.DocListOrbitzToolbar' instantiated in 'toolbar.get.html.ftl' that decorates the 'newContent' button as a YUI button mapped to the 'onNewContent' action handler to open the new-content form using the SimpleDialog mechanism&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;/**&lt;br /&gt;* DocumentList Toolbar component.&lt;br /&gt;*&lt;br /&gt;* @namespace Alfresco&lt;br /&gt;* @class Alfresco.DocListToolbar&lt;br /&gt;*/&lt;br /&gt;(function()&lt;br /&gt;{&lt;br /&gt;/**&lt;br /&gt;* YUI Library aliases&lt;br /&gt;*/&lt;br /&gt;var Dom = YAHOO.util.Dom,&lt;br /&gt;Event = YAHOO.util.Event,&lt;br /&gt;Element = YAHOO.util.Element;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Alfresco Slingshot aliases&lt;br /&gt;*/&lt;br /&gt;var $html = Alfresco.util.encodeHTML;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* DocListToolbar constructor.&lt;br /&gt;*&lt;br /&gt;* @param {String} htmlId The HTML id of the parent element&lt;br /&gt;* @return {Alfresco.DocListToolbar} The new DocListToolbar instance&lt;br /&gt;* @constructor&lt;br /&gt;*/&lt;br /&gt;Alfresco.DocListOrbitzToolbar = function(htmlId)&lt;br /&gt;{&lt;br /&gt;// Mandatory properties&lt;br /&gt;this.name = "Alfresco.DocListOrbitzToolbar";&lt;br /&gt;this.id = htmlId;&lt;br /&gt;&lt;br /&gt;// Initialise prototype properties&lt;br /&gt;this.widgets = {};&lt;br /&gt;this.modules = {};&lt;br /&gt;this.selectedFiles = [];&lt;br /&gt;this.currentFilter =&lt;br /&gt;{&lt;br /&gt;filterId: "",&lt;br /&gt;filterOwner: "",&lt;br /&gt;filterData: ""&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// Register this component&lt;br /&gt;Alfresco.util.ComponentManager.register(this);&lt;br /&gt;&lt;br /&gt;// Load YUI Components&lt;br /&gt;Alfresco.util.YUILoaderHelper.require(["button", "menu", "container"], this.onComponentsLoaded, this);&lt;br /&gt;&lt;br /&gt;// Decoupled event listeners&lt;br /&gt;//YAHOO.Bubbling.on("pathChanged", this.onPathChanged, this);&lt;br /&gt;//YAHOO.Bubbling.on("folderRenamed", this.onPathChanged, this);&lt;br /&gt;//YAHOO.Bubbling.on("filterChanged", this.onFilterChanged, this);&lt;br /&gt;YAHOO.Bubbling.on("deactivateAllControls", this.onDeactivateAllControls, this);&lt;br /&gt;//YAHOO.Bubbling.on("selectedFilesChanged", this.onSelectedFilesChanged, this);&lt;br /&gt;YAHOO.Bubbling.on("userAccess", this.onUserAccess, this);&lt;br /&gt;&lt;br /&gt;return this;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Alfresco.DocListOrbitzToolbar.prototype =&lt;br /&gt;{&lt;br /&gt;/**&lt;br /&gt;* Object container for initialization options&lt;br /&gt;*&lt;br /&gt;* @property options&lt;br /&gt;* @type object&lt;br /&gt;*/&lt;br /&gt;options:&lt;br /&gt;{&lt;br /&gt;/**&lt;br /&gt;* Current siteId.&lt;br /&gt;*&lt;br /&gt;* @property siteId&lt;br /&gt;* @type string&lt;br /&gt;*/&lt;br /&gt;siteId: "",&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* ContainerId representing root container&lt;br /&gt;*&lt;br /&gt;* @property containerId&lt;br /&gt;* @type string&lt;br /&gt;* @default "documentLibrary"&lt;br /&gt;*/&lt;br /&gt;containerId: "documentLibrary",&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Number of multi-file uploads before grouping the Activity Post&lt;br /&gt;*&lt;br /&gt;* @property groupActivitiesAt&lt;br /&gt;* @type int&lt;br /&gt;* @default 5&lt;br /&gt;*/&lt;br /&gt;groupActivitiesAt: 5,&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Flag indicating whether navigation bar is visible or not.&lt;br /&gt;*&lt;br /&gt;* @property hideNavBar&lt;br /&gt;* @type boolean&lt;br /&gt;*/&lt;br /&gt;hideNavBar: false&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Current path being browsed.&lt;br /&gt;*&lt;br /&gt;* @property currentPath&lt;br /&gt;* @type string&lt;br /&gt;*/&lt;br /&gt;currentPath: "",&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Current filter to choose toolbar view and populate description.&lt;br /&gt;*&lt;br /&gt;* @property currentFilter&lt;br /&gt;* @type string&lt;br /&gt;*/&lt;br /&gt;currentFilter: null,&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* FileUpload module instance.&lt;br /&gt;*&lt;br /&gt;* @property fileUpload&lt;br /&gt;* @type Alfresco.module.FileUpload&lt;br /&gt;*/&lt;br /&gt;fileUpload: null,&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Object container for storing YUI widget instances.&lt;br /&gt;*&lt;br /&gt;* @property widgets&lt;br /&gt;* @type object&lt;br /&gt;*/&lt;br /&gt;widgets: null,&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Object container for storing module instances.&lt;br /&gt;*&lt;br /&gt;* @property modules&lt;br /&gt;* @type object&lt;br /&gt;*/&lt;br /&gt;modules: null,&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Array of selected states for visible files.&lt;br /&gt;*&lt;br /&gt;* @property selectedFiles&lt;br /&gt;* @type array&lt;br /&gt;*/&lt;br /&gt;selectedFiles: null,&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Set multiple initialization options at once.&lt;br /&gt;*&lt;br /&gt;* @method setOptions&lt;br /&gt;* @param obj {object} Object literal specifying a set of options&lt;br /&gt;* @return {Alfresco.DocListToolbar} returns 'this' for method chaining&lt;br /&gt;*/&lt;br /&gt;setOptions: function DLTB_setOptions(obj)&lt;br /&gt;{&lt;br /&gt;this.options = YAHOO.lang.merge(this.options, obj);&lt;br /&gt;return this;&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Set messages for this component.&lt;br /&gt;*&lt;br /&gt;* @method setMessages&lt;br /&gt;* @param obj {object} Object literal specifying a set of messages&lt;br /&gt;* @return {Alfresco.DocListToolbar} returns 'this' for method chaining&lt;br /&gt;*/&lt;br /&gt;setMessages: function DLTB_setMessages(obj)&lt;br /&gt;{&lt;br /&gt;Alfresco.util.addMessages(obj, this.name);&lt;br /&gt;return this;&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Fired by YUILoaderHelper when required component script files have&lt;br /&gt;* been loaded into the browser.&lt;br /&gt;*&lt;br /&gt;* @method onComponentsLoaded&lt;br /&gt;*/&lt;br /&gt;onComponentsLoaded: function DLTB_onComponentsLoaded()&lt;br /&gt;{&lt;br /&gt;Event.onContentReady(this.id, this.onReady, this, true);&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Fired by YUI when parent element is available for scripting.&lt;br /&gt;* Component initialisation, including instantiation of YUI widgets and event listener binding.&lt;br /&gt;*&lt;br /&gt;* @method onReady&lt;br /&gt;*/&lt;br /&gt;onReady: function DLTB_onReady()&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;// New Content button: user needs "create" access&lt;br /&gt;this.widgets.newContent = Alfresco.util.createYUIButton(this, "newContent-button", this.onNewContent,&lt;br /&gt;{&lt;br /&gt;disabled: true,&lt;br /&gt;value: "create"&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;// Finally show the component body here to prevent UI artifacts on YUI button decoration&lt;br /&gt;//Dom.setStyle(this.id + "-body", "visibility", "visible");&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* YUI WIDGET EVENT HANDLERS&lt;br /&gt;* Handlers for standard events fired from YUI widgets, e.g. "click"&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* New Content button click handler&lt;br /&gt;*&lt;br /&gt;* @method onNewContent&lt;br /&gt;* @param e {object} DomEvent&lt;br /&gt;* @param p_obj {object} Object passed back from addListener method&lt;br /&gt;*/&lt;br /&gt;onNewContent: function DLTB_onNewContent(e, p_obj)&lt;br /&gt;{&lt;br /&gt;var actionUrl = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "slingshot/doclib/action/folder/site/{site}/{container}/{path}",&lt;br /&gt;{&lt;br /&gt;site: this.options.siteId,&lt;br /&gt;container: this.options.containerId,&lt;br /&gt;path: this.currentPath&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;var doSetupFormsValidation = function DLTB_oNF_doSetupFormsValidation(p_form)&lt;br /&gt;{&lt;br /&gt;// Validation&lt;br /&gt;// Name: mandatory value&lt;br /&gt;p_form.addValidation(this.id + "-createContent-name", Alfresco.forms.validation.mandatory, null, "keyup");&lt;br /&gt;// Name: valid filename&lt;br /&gt;p_form.addValidation(this.id + "-createContent-name", Alfresco.forms.validation.nodeName, null, "keyup");&lt;br /&gt;p_form.setShowSubmitStateDynamically(true, false);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;if (!this.modules.createContent)&lt;br /&gt;{&lt;br /&gt;this.modules.createContent = new Alfresco.module.SimpleDialog(this.id + "-createContent").setOptions(&lt;br /&gt;{&lt;br /&gt;width: "30em",&lt;br /&gt;templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "components/documentlibrary/create-content",&lt;br /&gt;actionUrl: actionUrl,&lt;br /&gt;doSetupFormsValidation:&lt;br /&gt;{&lt;br /&gt;   fn: doSetupFormsValidation,&lt;br /&gt;   scope: this&lt;br /&gt;},&lt;br /&gt;firstFocus: this.id + "-createContent-name",&lt;br /&gt;onSuccess:&lt;br /&gt;{&lt;br /&gt;   fn: function DLTB_onCreateContent_callback(response)&lt;br /&gt;   {&lt;br /&gt;      var file = response.json.results[0];&lt;br /&gt;      YAHOO.Bubbling.fire("folderCreated",&lt;br /&gt;      {&lt;br /&gt;         name: file.name,&lt;br /&gt;         parentPath: file.parentPath,fileCopied&lt;br /&gt;         nodeRef: file.nodeRef&lt;br /&gt;      });&lt;br /&gt;      Alfresco.util.PopupManager.displayMessage(&lt;br /&gt;      {&lt;br /&gt;         text: this._msg("message.new-content.success", file.name)&lt;br /&gt;      });&lt;br /&gt;   },&lt;br /&gt;   scope: this&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;this.modules.createContent.setOptions(&lt;br /&gt;{&lt;br /&gt;actionUrl: actionUrl,&lt;br /&gt;clearForm: true&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;this.modules.createContent.show();&lt;br /&gt;},&lt;br /&gt;/**&lt;br /&gt;* Deactivate All Controls event handler&lt;br /&gt;*&lt;br /&gt;* @method onDeactivateAllControls&lt;br /&gt;* @param layer {object} Event fired&lt;br /&gt;* @param args {array} Event parameters (depends on event type)&lt;br /&gt;*/&lt;br /&gt;onDeactivateAllControls: function DLTB_onDeactivateAllControls(layer, args)&lt;br /&gt;{&lt;br /&gt;var widget;&lt;br /&gt;for (widget in this.widgets)&lt;br /&gt;{&lt;br /&gt;if (this.widgets.hasOwnProperty(widget))&lt;br /&gt;{&lt;br /&gt;this.widgets[widget].set("disabled", true);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* User Access event handler&lt;br /&gt;*&lt;br /&gt;* @method onUserAccess&lt;br /&gt;* @param layer {object} Event fired&lt;br /&gt;* @param args {array} Event parameters (depends on event type)&lt;br /&gt;*/&lt;br /&gt;onUserAccess: function DLTB_onUserAccess(layer, args)&lt;br /&gt;{&lt;br /&gt;var obj = args[1];&lt;br /&gt;if ((obj !== null) &amp;amp;&amp;amp; (obj.userAccess !== null))&lt;br /&gt;{&lt;br /&gt;var widget, widgetPermissions, index;&lt;br /&gt;for (index in this.widgets)&lt;br /&gt;{&lt;br /&gt;if (this.widgets.hasOwnProperty(index))&lt;br /&gt;{&lt;br /&gt;   widget = this.widgets[index];&lt;br /&gt;   if (widget.get("srcelement").className != "no-access-check")&lt;br /&gt;   {&lt;br /&gt;      widget.set("disabled", false);&lt;br /&gt;      if (widget.get("value") !== null)&lt;br /&gt;      {&lt;br /&gt;         widgetPermissions = widget.get("value").split(",");&lt;br /&gt;         for (var i = 0, ii = widgetPermissions.length; i &amp;lt; ii; i++)&lt;br /&gt;         {&lt;br /&gt;            if (!obj.userAccess[widgetPermissions[i]])&lt;br /&gt;            {&lt;br /&gt;               widget.set("disabled", true);&lt;br /&gt;               break;&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Gets a custom message&lt;br /&gt;*&lt;br /&gt;* @method _msg&lt;br /&gt;* @param messageId {string} The messageId to retrieve&lt;br /&gt;* @return {string} The custom message&lt;br /&gt;* @private&lt;br /&gt;*/&lt;br /&gt;_msg: function DLTB__msg(messageId)&lt;br /&gt;{&lt;br /&gt;return Alfresco.util.message.call(this, messageId, "Alfresco.DocListOrbitzToolbar", Array.prototype.slice.call(arguments).slice(1));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;})();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This script at first will be configured to run the web script to create a new folder:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;var actionUrl = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "slingshot/doclib/action/folder/site/{site}/{container}/{path}",&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;In the following steps, we will create our own script that will create a new file.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-weight: bold;"&gt;orbitz.toolbar.css&lt;/div&gt;&lt;div&gt;&lt;br /&gt;This css defines the images and style used for the 'newContent' button:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;.toolbar .new-content button&lt;br /&gt;{&lt;br /&gt;background: transparent url(images/content-new-16.png) no-repeat 12px 4px;&lt;br /&gt;padding-left: 32px;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toolbar .new-content .yui-button-disabled button&lt;br /&gt;{&lt;br /&gt;background-image: url(images/content-new-disabled-16.png);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;these images are copies of the slingshot project's 'source/web/components/images/edit-blog-16.png' image.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Step 4 - Create the component to map to the 'toolbar' region of the document library template&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Finally in the 'config/alfresco/site-data' source folder in the 'components' package, we override the existing 'toolbar' region in the 'documentlibrary' template to reference the /orbitz/components/documentlibrary/toolbar' component:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;template.toolbar.documentlibrary.xml&lt;/span&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;br /&gt;&amp;lt;component&amp;gt;&lt;br /&gt;&amp;lt;scope&amp;gt;template&amp;lt;/scope&amp;gt;&lt;br /&gt;&amp;lt;region-id&amp;gt;toolbar&amp;lt;/region-id&amp;gt;&lt;br /&gt;&amp;lt;source-id&amp;gt;documentlibrary&amp;lt;/source-id&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/orbitz/components/documentlibrary/toolbar&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;/component&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Step 5 - Deploy and Test&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;First, we need to make sure the 'share' war is installed and expanded in the tomcat host. I use the Alfresco project build.xml's&lt;br /&gt;&lt;blockquote&gt;ant incremental-slingshot-tomcat-exploded&lt;/blockquote&gt;But for a war distribtuion, just make sure it is run at least once.&lt;br /&gt;&lt;br /&gt;To use the build.xml, make sure to set APP_TOMCAT_HOME and TOMCAT_HOME environment variables as recommended in the previous blog article: &lt;a href="http://edlovesjava.blogspot.com/2008/12/extending-share-1-creating-share.html"&gt;Extending Share 1 - Creating a Share Extension Project&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To build and deploy the share webapp expanded in the tomcat directory. Now we can deploy our extension code from the 'deals-share-extension' project's build.xml file:&lt;br /&gt;&lt;blockquote&gt;ant deploy&lt;/blockquote&gt;This will create the 'deals-share-ext.jar' jar file and copy to the share/WEB-INF/lib directory, copy the configuration files from the config/alfresco/** source folders to the share/weB-INF/classes directory, and copy the web assets from the source/web source folders to the share root directory.&lt;br /&gt;&lt;br /&gt;We can test our toolbar code directly using the url:  &lt;a href="http://localhost:8080/share/service/orbitz/components/documentlibrary/toolbar?htmlid"&gt;http://localhost:8080/share/service/orbitz/components/documentlibrary/toolbar?htmlid&lt;/a&gt; , but this will not render with CSS, and without CSS, the YUI components wont work.&lt;br /&gt;&lt;br /&gt;Now we can test within the Share:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Launch share &lt;a href="http://localhost:8080/share"&gt;http://localhost:8080/share&lt;/a&gt;, opens to the share dashboard&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create and/or select a Site, opens to the site dashboard&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Select the 'document library' section should render our new toolbar with the 'New Content' button&lt;/li&gt;&lt;li&gt;Press the 'New Content' button and the 'create-content' form should open&lt;/li&gt;&lt;li&gt;Enter the new content's name, title, description and content int he form and press 'ok' and the dialog should close, but instead of a file created, we should see a new folder created. In the next steps we will create the web script necessary to create a new file.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;"&gt;Step 6 - Creating a custom web script action&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we need to create a webscript service to use instead of the slingshot/doclib/action/folder service. for this blog, I will extend the action services to implement the following url pattern:&lt;br /&gt;&lt;br /&gt;POST slingshot/doclib/action/file/site/{site}/{container}/{path}&lt;br /&gt;&lt;br /&gt;To do this, we will add a new webscript service to the remote alfresco.war by uploading it to the Data Dictionary space. Later, we can separate this to our own amp module. As a starting point, we will copy the folder.post.* files to create file.post.* files in Remote API/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/action directory to create the following files:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;file.post.desc.xml&lt;/li&gt;&lt;li&gt;file.post.json.ftl&lt;/li&gt;&lt;li&gt;file.post.json.js&lt;/li&gt;&lt;/ul&gt;Now we can modify these files to do the work of creating a file instead of a folder. for 'file.post.desc.xml' we modify the url pattern to the following:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;webscript&amp;gt;&lt;br /&gt;&amp;lt;shortname&amp;gt;folder&amp;lt;/shortname&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;Document List Action - Create folder&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/slingshot/doclib/action/file/site/{site}/{container}&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/slingshot/doclib/action/file/site/{site}/{container}/{path}&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;format default="json"&amp;gt;argument&amp;lt;/format&amp;gt;&lt;br /&gt;&amp;lt;authentication&amp;gt;user&amp;lt;/authentication&amp;gt;&lt;br /&gt;&amp;lt;transaction&amp;gt;required&amp;lt;/transaction&amp;gt;&lt;br /&gt;&amp;lt;/webscript&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;file.post.json.ftl will be changed, it imports the action.lib.ftl to create a standard results response json format. But I will combine the import. Its contents are the following:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;#macro resultsJSON results&amp;gt;&lt;br /&gt;&amp;lt;#escape x as jsonUtils.encodeJSONString(x)&amp;gt;&lt;br /&gt;{&lt;br /&gt;"totalResults": ${results?size},&lt;br /&gt;"overallSuccess": ${overallSuccess?string},&lt;br /&gt;"successCount": ${successCount},&lt;br /&gt;"failureCount": ${failureCount},&lt;br /&gt;"results":&lt;br /&gt;[&lt;br /&gt;   &amp;lt;#list results as r&amp;gt;&lt;br /&gt;   {&lt;br /&gt;      &amp;lt;#list r?keys as key&amp;gt;&lt;br /&gt;         &amp;lt;#assign value = r[key]&amp;gt;&lt;br /&gt;         &amp;lt;#if value?is_number || value?is_boolean&amp;gt;&lt;br /&gt;      "${key}": ${value?string}&amp;lt;#if key_has_next&amp;gt;,&amp;lt;/#if&amp;gt;&lt;br /&gt;         &amp;lt;#else&amp;gt;&lt;br /&gt;      "${key}": "${value}"&amp;lt;#if key_has_next&amp;gt;,&amp;lt;/#if&amp;gt;&lt;br /&gt;         &amp;lt;/#if&amp;gt;&lt;br /&gt;         &amp;lt;/#list&amp;gt;&lt;br /&gt;   }&amp;lt;#if r_has_next&amp;gt;,&amp;lt;/#if&amp;gt;&lt;br /&gt;   &amp;lt;/#list&amp;gt;&lt;br /&gt;]&lt;br /&gt;}&lt;br /&gt;&amp;lt;/#escape&amp;gt;&lt;br /&gt;&amp;lt;/#macro&amp;gt;&lt;br /&gt;&amp;lt;@resultsJSON results=results /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;file.post.json.js needs to be modified to handle a file instead of a folder.&lt;br /&gt;&lt;br /&gt;The main changes I will make to this script:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;get a 'content' field from the json request object from the create-content form that we added previously.&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt; if (!json.isNull("content"))&lt;br /&gt;{&lt;br /&gt;content = json.get("content");&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Rename variables folderName, folderDescription, folderTitle, folderPath to fileName, fileDescription, fileTitle, fileDescription and filePath respectively.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create a file node instead of a folder node&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;var fileNode = parentNode.createFile(fileName);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;set the content on the newly created fileNode variable arfter the fileNode.save(); method&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;      fileNode.save();&lt;br /&gt;// Add uifacets aspect for the web client&lt;br /&gt;fileNode.content = content;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Change messaging to reflect saving a file, not a folder.&lt;/li&gt;&lt;/ol&gt;The completed file.post.json.js looks like this:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;/**&lt;br /&gt;* Document List Component: action&lt;br /&gt;*&lt;br /&gt;* For a single-asset action, template paramters address the asset.&lt;br /&gt;* For multi-asset actions, template parameters address the source or destination node,&lt;br /&gt;* and a JSON body addresses the assets involved in the action.&lt;br /&gt;* (note: HTTP DELETE methods must use URI)&lt;br /&gt;*&lt;br /&gt;* @param uri {string} site/{siteId}/{containerId}/{filepath} : full path to file or folder name involved in the action&lt;br /&gt;* @param uri {string} node/{store_type}/{store_id}/{id}/{filepath} : full path to file or folder name involved in the action&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Main script entry point&lt;br /&gt;* @method main&lt;br /&gt;*/&lt;br /&gt;function main()&lt;br /&gt;{&lt;br /&gt;// Params object contains commonly-used arguments&lt;br /&gt;var params = {};&lt;br /&gt;var files, rootNode;&lt;br /&gt;&lt;br /&gt;if (url.templateArgs.store_type != undefined)&lt;br /&gt;{&lt;br /&gt;   params = getNodeRefInputParams();&lt;br /&gt;}&lt;br /&gt;else if (url.templateArgs.site != undefined)&lt;br /&gt;{&lt;br /&gt;   params = getSiteInputParams();&lt;br /&gt;}&lt;br /&gt;if (typeof params == "string")&lt;br /&gt;{&lt;br /&gt;   status.setCode(status.STATUS_BAD_REQUEST, params);&lt;br /&gt;   return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Resolve path if available&lt;br /&gt;var path = url.templateArgs.path;&lt;br /&gt;// Path might be null for the root folder&lt;br /&gt;if (!path)&lt;br /&gt;{&lt;br /&gt;   path = "";&lt;br /&gt;}&lt;br /&gt;// Remove any leading or trailing "/" from the path&lt;br /&gt;// Fix-up parent path to have no leading or trailing slashes&lt;br /&gt;if (path.length &amp;gt; 0)&lt;br /&gt;{&lt;br /&gt;   var aPaths = path.split("/");&lt;br /&gt;   while (aPaths[0] === "")&lt;br /&gt;   {&lt;br /&gt;      aPaths.shift();&lt;br /&gt;   }&lt;br /&gt;   while (aPaths[aPaths.length-1] === "")&lt;br /&gt;   {&lt;br /&gt;      aPaths.pop();&lt;br /&gt;   }&lt;br /&gt;   path = aPaths.join("/");&lt;br /&gt;}&lt;br /&gt;params.path = path;&lt;br /&gt;&lt;br /&gt;// Multiple input files in the JSON body?&lt;br /&gt;files = getMultipleInputValues("nodeRefs");&lt;br /&gt;if (typeof files != "string")&lt;br /&gt;{&lt;br /&gt;   params.files = files;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Check runAction function is provided the action's webscript&lt;br /&gt;if (typeof runAction != "function")&lt;br /&gt;{&lt;br /&gt;   status.setCode(status.STATUS_BAD_REQUEST, "Action webscript must provide runAction() function.");&lt;br /&gt;   return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Actually run the action&lt;br /&gt;var results = runAction(params);&lt;br /&gt;if ((results !== null) &amp;amp;&amp;amp; (results !== undefined))&lt;br /&gt;{&lt;br /&gt;   if (typeof results == "string")&lt;br /&gt;   {&lt;br /&gt;      status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, results);&lt;br /&gt;   }&lt;br /&gt;   else if (typeof results.status == "object")&lt;br /&gt;   {&lt;br /&gt;      // Status fields have been manually set&lt;br /&gt;      status.redirect = true;&lt;br /&gt;      for (var s in results.status)&lt;br /&gt;      {&lt;br /&gt;         status[s] = results.status[s];&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   else&lt;br /&gt;   {&lt;br /&gt;      /**&lt;br /&gt;       * NOTE: Webscripts run within one transaction only.&lt;br /&gt;       * If a single operation fails, the transaction is marked for rollback and all&lt;br /&gt;       * previous (successful) operations are also therefore rolled back.&lt;br /&gt;       * We therefore need to scan the results for a failed operation and mark the entire&lt;br /&gt;       * set of operations as failed.&lt;br /&gt;       */&lt;br /&gt;      var overallSuccess = true;&lt;br /&gt;      var successCount = 0;&lt;br /&gt;      var failureCount = 0;&lt;br /&gt;      for (var i = 0, j = results.length; i &amp;lt; j; i++)&lt;br /&gt;      {&lt;br /&gt;         overallSuccess = overallSuccess &amp;amp;&amp;amp; results[i].success;&lt;br /&gt;         results[i].success ? ++successCount : ++failureCount;&lt;br /&gt;      }&lt;br /&gt;      model.overallSuccess = overallSuccess;&lt;br /&gt;      model.successCount = successCount;&lt;br /&gt;      model.failureCount = failureCount;&lt;br /&gt;      model.results = results;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Get and check existence of mandatory input parameters (Site-based)&lt;br /&gt;*&lt;br /&gt;* @method getSiteInputParams&lt;br /&gt;* @return {object|string} object literal containing parameters value or string error&lt;br /&gt;*/&lt;br /&gt;function getSiteInputParams()&lt;br /&gt;{&lt;br /&gt;var params = {};&lt;br /&gt;var error = null;&lt;br /&gt;var template = url.template;&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;   var siteId, containerId, sideNode, rootNode;&lt;br /&gt;&lt;br /&gt;   // Try to get the parameters from the URI&lt;br /&gt;   siteId = url.templateArgs.site;&lt;br /&gt;   containerId = url.templateArgs.container;&lt;br /&gt;&lt;br /&gt;   // SiteId&lt;br /&gt;   if (template.indexOf("{site}") != -1)&lt;br /&gt;   {&lt;br /&gt;       if ((siteId === null) || (siteId.length === 0))&lt;br /&gt;       {&lt;br /&gt;           return "'site' parameter is missing.";&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;      // Find the site&lt;br /&gt;      siteNode = siteService.getSite(siteId);&lt;br /&gt;      if (siteNode === null)&lt;br /&gt;      {&lt;br /&gt;           return "Site '" + siteId + "' not found.";&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // ContainerId&lt;br /&gt;      if (template.indexOf("{container}") != -1)&lt;br /&gt;      {&lt;br /&gt;          if ((containerId === null) || (containerId.length === 0))&lt;br /&gt;          {&lt;br /&gt;              return "'container' parameter is missing.";&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;         // Find the component container&lt;br /&gt;         var rootNode = siteNode.getContainer(containerId);&lt;br /&gt;         if (rootNode === null)&lt;br /&gt;         {&lt;br /&gt;           rootNode = siteNode.createContainer(containerId);&lt;br /&gt;           if (rootNode === null)&lt;br /&gt;           {&lt;br /&gt;                  return "Component container '" + containerId + "' not found in '" + siteId + "'.";&lt;br /&gt;              }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // Populate the return object&lt;br /&gt;      params =&lt;br /&gt;      {&lt;br /&gt;          usingNodeRef: false,&lt;br /&gt;          siteId: siteId,&lt;br /&gt;          containerId: containerId,&lt;br /&gt;          siteNode: siteNode,&lt;br /&gt;          rootNode: rootNode&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;catch(e)&lt;br /&gt;{&lt;br /&gt;   error = e.toString();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt; // Return the params object, or the error string if it was set&lt;br /&gt; return (error !== null ? error : params);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Get and check existence of mandatory input parameters (nodeRef-based)&lt;br /&gt;*&lt;br /&gt;* @method getNodeRefInputParams&lt;br /&gt;* @return {object|string} object literal containing parameters value or string error&lt;br /&gt;*/&lt;br /&gt;function getNodeRefInputParams()&lt;br /&gt;{&lt;br /&gt;var params = {};&lt;br /&gt;var error = null;&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;   // First try to get the parameters from the URI&lt;br /&gt;   var storeType = url.templateArgs.store_type;&lt;br /&gt;   var storeId = url.templateArgs.store_id;&lt;br /&gt;   var id = url.templateArgs.id;&lt;br /&gt;&lt;br /&gt;   var nodeRef = storeType + "://" + storeId + "/" + id;&lt;br /&gt;   var rootNode = null;&lt;br /&gt;&lt;br /&gt;   if (nodeRef == "alfresco://company/home")&lt;br /&gt;   {&lt;br /&gt;      rootNode = companyhome;&lt;br /&gt;   }&lt;br /&gt;   else if (nodeRef == "alfresco://user/home")&lt;br /&gt;   {&lt;br /&gt;      rootNode = userhome;&lt;br /&gt;   }&lt;br /&gt;   else&lt;br /&gt;   {&lt;br /&gt;      rootNode = search.findNode(nodeRef);&lt;br /&gt;&lt;br /&gt;       if (rootNode === null)&lt;br /&gt;       {&lt;br /&gt;           return "'" + nodeRef  + "' is not a valid nodeRef.";&lt;br /&gt;       }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;   // Populate the return object&lt;br /&gt;   params =&lt;br /&gt;   {&lt;br /&gt;      usingNodeRef: true,&lt;br /&gt;      nodeRef: nodeRef,&lt;br /&gt;      rootNode: rootNode&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;catch(e)&lt;br /&gt;{&lt;br /&gt;   error = e.toString();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt; // Return the params object, or the error string if it was set&lt;br /&gt; return (error !== null ? error : params);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Get multiple input values&lt;br /&gt;*&lt;br /&gt;* @method getMultipleInputValues&lt;br /&gt;* @return {array|string} Array containing multiple values, or string error&lt;br /&gt;*/&lt;br /&gt;function getMultipleInputValues(param)&lt;br /&gt;{&lt;br /&gt;var values = [];&lt;br /&gt;var error = null;&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;   // Was a JSON parameter list supplied?&lt;br /&gt;   if (typeof json == "object")&lt;br /&gt;   {&lt;br /&gt;      if (!json.isNull(param))&lt;br /&gt;      {&lt;br /&gt;         var jsonValues = json.get(param);&lt;br /&gt;         // Convert from JSONArray to JavaScript array&lt;br /&gt;         for (var i = 0, j = jsonValues.length(); i &amp;lt; j; i++)&lt;br /&gt;         {&lt;br /&gt;            values.push(jsonValues.get(i));&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;catch(e)&lt;br /&gt;{&lt;br /&gt;   error = e.toString();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt; // Return the values array, or the error string if it was set&lt;br /&gt; return (error !== null ? error : values);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Obtain the asset node for the given rootNode and filepath&lt;br /&gt;*&lt;br /&gt;* @method getAssetNode&lt;br /&gt;* @param p_rootNode {object} valid repository node&lt;br /&gt;* @param p_assetPath {string} rootNode-relative path to asset&lt;br /&gt;* @return {object|string} valid repository node or string error&lt;br /&gt;*/&lt;br /&gt;function getAssetNode(p_rootNode, p_assetPath)&lt;br /&gt;{&lt;br /&gt;var assetNode = p_rootNode;&lt;br /&gt;var error = null;&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;   if (p_assetPath &amp;amp;&amp;amp; (p_assetPath.length &amp;gt; 0))&lt;br /&gt;   {&lt;br /&gt;      assetNode = assetNode.childByNamePath(p_assetPath);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   if (assetNode === null)&lt;br /&gt;   {&lt;br /&gt;      return "Asset '" + p_assetPath + " not found.";&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;catch(e)&lt;br /&gt;{&lt;br /&gt;     error = e.toString();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt; // Return the node object, or the error string if it was set&lt;br /&gt; return (error !== null ? error : assetNode);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Create file action&lt;br /&gt;* @method POST&lt;br /&gt;* @param uri {string} /{siteId}/{containerId}/{filepath}&lt;br /&gt;* @param json.name {string} New file name&lt;br /&gt;* @param json.title {string} Title metadata&lt;br /&gt;* @param json.description {string} Description metadata&lt;br /&gt;* @param json.content {string} Content of file&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Entrypoint required by action.lib.js&lt;br /&gt;*&lt;br /&gt;* @method runAction&lt;br /&gt;* @param p_params {object} common parameters&lt;br /&gt;* @return {object|null} object representation of action result&lt;br /&gt;*/&lt;br /&gt;function runAction(p_params)&lt;br /&gt;{&lt;br /&gt;var results;&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;// Mandatory: json.name&lt;br /&gt;if (json.isNull("name"))&lt;br /&gt;{&lt;br /&gt; status.setCode(status.STATUS_BAD_REQUEST, "File name is a mandatory parameter.");&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;var fileName = json.get("name");&lt;br /&gt;&lt;br /&gt;var parentPath = p_params.path;&lt;br /&gt;var filePath = parentPath + "/" + fileName;&lt;br /&gt;&lt;br /&gt;// Check file doesn't already exist&lt;br /&gt;var existsNode = getAssetNode(p_params.rootNode, filePath);&lt;br /&gt;if (typeof existsNode == "object")&lt;br /&gt;{&lt;br /&gt; status.setCode(status.STATUS_BAD_REQUEST, "File '" + filePath + "' already exists.");&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Check parent exists&lt;br /&gt;var parentNode = getAssetNode(p_params.rootNode, parentPath);&lt;br /&gt;if (typeof parentNode == "string")&lt;br /&gt;{&lt;br /&gt; status.setCode(status.STATUS_NOT_FOUND, "Parent folder '" + parentPath + "' not found.");&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Title and description&lt;br /&gt;var fileTitle = "";&lt;br /&gt;var fileDescription = "";&lt;br /&gt;if (!json.isNull("title"))&lt;br /&gt;{&lt;br /&gt; fileTitle = json.get("title");&lt;br /&gt;}&lt;br /&gt;if (!json.isNull("description"))&lt;br /&gt;{&lt;br /&gt; fileDescription = json.get("description");&lt;br /&gt;}&lt;br /&gt;if (!json.isNull("content"))&lt;br /&gt;{&lt;br /&gt; content = json.get("content");&lt;br /&gt;}&lt;br /&gt;// Create the folder and apply metadata&lt;br /&gt;var fileNode = parentNode.createFile(fileName);&lt;br /&gt;// Always add title &amp;amp; description, default icon&lt;br /&gt;fileNode.properties["cm:title"] = fileTitle;&lt;br /&gt;fileNode.properties["cm:description"] = fileDescription.substr(0, 100);&lt;br /&gt;fileNode.properties["app:icon"] = "space-icon-default";&lt;br /&gt;fileNode.save();&lt;br /&gt;// Add uifacets aspect for the web client&lt;br /&gt;fileNode.content = content;&lt;br /&gt;fileNode.addAspect("app:uifacets");&lt;br /&gt;&lt;br /&gt;// Construct the result object&lt;br /&gt;results = [&lt;br /&gt;{&lt;br /&gt; id: filePath,&lt;br /&gt; name: fileName,&lt;br /&gt; parentPath: parentPath,&lt;br /&gt; nodeRef: fileNode.nodeRef.toString(),&lt;br /&gt; action: "createFile",&lt;br /&gt; success: true&lt;br /&gt;}];&lt;br /&gt;}&lt;br /&gt;catch(e)&lt;br /&gt;{&lt;br /&gt;status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, e.toString());&lt;br /&gt;return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return results;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Bootstrap action script */&lt;br /&gt;main();&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This service uses the action.lib.js and action.lib.ftl libraries to simplify coding of similar functions, including: checkin, checkout, cancel-checkout, copy-to, move-to, file or folder delete and others. The action.lib.js is included in the folder.post.json.js script and provides a main() entry point to do common setup, clean up and host shared functions. The main entry point calls the runAction() function defined in the specific action script 'folder.post.json.js', effectively implementing a strategy pattern.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Step 7 - upload, build and test&lt;/span&gt;&lt;br /&gt;Log into the alfresco server as admin. Navigate to Company Home &gt; Data Dictionary &gt; Web Scripts &gt; org &gt; alfresco&lt;span style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Create a new directory 'doclib' and copy the three files in to this directory: 'file.post.desc.xml', 'file.post.json.ftl', and 'file.post.json.js'.&lt;br /&gt;Navigate to &lt;a href="http://localhost:8080/alfresco/service/index"&gt;http://localhost:8080/alfresco/service/index&lt;/a&gt; and select 'refresh webscripts' button.&lt;br /&gt;&lt;br /&gt;To view the new service, use the url &lt;a href="http://localhost:8081/alfresco/service/index/uri/slingshot/doclib/action/file/site/%7Bsite%7D/%7Bcontainer%7D"&gt;http://localhost:8080/alfresco/service/index/uri/slingshot/doclib/action/file/site/%7Bsite%7D/%7Bcontainer%7D&lt;/a&gt; which should show the service correctly added.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Step 8 - alter 'New Content' button action to invoke new service&lt;/span&gt;&lt;br /&gt;Now we have to use this new service we have created when we press the 'new content' button orbitz-toolbar.js onNewContent action line to read:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;         var actionUrl = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "slingshot/doclib/action/file/site/{site}/{container}/{path}",&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;this will call our new slingshot service to create a file, which in turn will call the new remote api service we added to alfresco.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Step 9 - deploy and test&lt;/span&gt;&lt;br /&gt;Now, you should be able to press 'New Content' in share Document Library and create a new content item.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-7366489627418091298?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/7366489627418091298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=7366489627418091298' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/7366489627418091298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/7366489627418091298'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/12/extending-share-2-adding-new-content.html' title='Extending Share 2 - Adding a New Content button to Document Library'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-3074507116851840399</id><published>2008-12-04T18:08:00.001-08:00</published><updated>2008-12-08T14:20:43.832-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><category scheme='http://www.blogger.com/atom/ns#' term='extending share'/><title type='text'>Extending Share 1 - Creating a Share extension project</title><content type='html'>&lt;div&gt;This post builds on the &lt;a href="http://edlovesjava.blogspot.com/2008/12/learning-surf-6-creating-webscript.html"&gt;Learning Surf 1-6 blog entries&lt;/a&gt; (titled Learning Surf 1-6) to build a project to extend Alfresco's Share with custom capabilities. My previous blog posts walked through the Surf framework by creating a new button 'New Content' added to the 'Document Library' section of Share which allows content to be created and edited in-line in a popup form.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;To recap the steps in the 'Learning Surf' posts:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Created a new ui webscript '/components/documentlibrary/create-content' that renders a form to capture the new content's name, title, description and contents&lt;/li&gt;&lt;li&gt;Augmented the document library's toolbar component with a 'New Content' button which opens the new create-content form component in a light box / modal dialog using the SimpleDialog library mechanism (similar to the 'New Folder' button)&lt;/li&gt;&lt;li&gt;Added a webscript service (POST /slingshot/actions/file) to the remote API to save the new content in the content repository by creating a new content item and adding it to the curernt path. &lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;The code we wrote  previously extended the Share (Slingshot project) and Alfresco (via the Remote API project) by directly coding in the code base of those projects. This is not an acceptable way to extend these products if not intending to become part of the main build. What is needed are two projects that are independent from the main code base and can add the desired functionality to the Share web client and the remote API on the content repository. The new webscript service previously added in the Remote API project will be created as an &lt;a href="http://wiki.alfresco.com/wiki/AMP_Files"&gt;AMP module based project&lt;/a&gt; following the SDK Basic AMP project standard. I will describe this process in the next blog post. In this post, I will describe the steps to create a Share extension project. The approach and structure structure is my own. I am not sure this is the best approach to extend Share, but it does work. I am hoping to improve on this approach in the future (with your help of course).&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;NOTE: the complete sourceocde for this project can be downloaded from &lt;a href="http://www.wentsoft.com/deals-share-extension.tar.gz"&gt;here.&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:130%;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step 1 - Create a basic project structure&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;This project is created with Eclipse 'new java project' wizard, named 'deals-share-extension'. I created the following source folders (via File&gt;New&gt;Source Folder):&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;source/java&lt;/span&gt; - containing any java code (so far, none)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;config/orbitz/site-webscripts&lt;/span&gt; - containing custom components (i.e. '/components/documentlibrary/create-content')&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;config/orbitz/templates&lt;/span&gt; - containing custom templates (so far, none)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;config/alfresco/site-webscripts&lt;/span&gt; - containing override webscripts extending or replacing existing Share webscripts&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;config/alfresco/web-extension&lt;/span&gt; - contains extension spring bean and surf configurations to extend share (i.e. 'custom-slingshot-application-context.xml')&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;source/web&lt;/span&gt; containing any custom javascript, images and css&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Also, the following was added to the project:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;lib&lt;/span&gt; folder containing junit.jar for anticipated unit tests (more on these in the future)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;build.xml&lt;/span&gt; ant build script used to build the project (described in the next step)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;build.properties&lt;/span&gt; file containing configurable parameters for the build script (also described in the next step)&lt;/li&gt;&lt;/ul&gt;Created during the project build are the 'build/classes' folder containing java source and config files and the 'dist' folder containing the packaged jar file.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QVQz3EsVFfA/ST1jaeD6QTI/AAAAAAAAABo/Qzzrz6P-Oko/s1600-h/deals-share-ex-cap01.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 289px;" src="http://3.bp.blogspot.com/_QVQz3EsVFfA/ST1jaeD6QTI/AAAAAAAAABo/Qzzrz6P-Oko/s320/deals-share-ex-cap01.png" alt="" id="BLOGGER_PHOTO_ID_5277483644745302322" border="0" /&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-weight: bold;font-size:130%;" &gt;&lt;span class="Apple-style-span"&gt;Step 2 - Create an Ant build.xml&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;The build script (see next step) will create a jar (named 'deals-share-ext.jar') containing any java code and any webscripts in the config/orbitz path, and deploy it to the WEB-INF/lib directory of the expanded Share war. In addition, the build script will copy the code in config/alfresco to the WEB-INF/classes/alfresco directory of the expanded Share war adding to or overwriting any existing Share components. Finally, source/web is copied to the Share root to add the custom Javascript, css and images used by the new components.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The build.xml ant script contains the following targets:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;init &lt;/span&gt;- initializes build properties&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;incremental &lt;/span&gt;- incrementally builds the project (depends on package)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;build &lt;/span&gt;- (default) cleans and builds the project (depends on clean and incremental)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;clean &lt;/span&gt;- removes the 'build' and 'dist' directories and files created during compile and package&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;compile &lt;/span&gt;- compiles java code to build/classes and copies files required for the classpath into compiled classes folder and copies the deployable web assets to the build folder&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;package &lt;/span&gt;- creates a jar file in the dist folder from files in build/classes&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;deploy &lt;/span&gt;- copies jar to expanded share project war WEB-INF/lib, config files in build/classes 'alfresco' to WEB-INF/classes and web assets in source/web to the share root&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt; test &lt;/span&gt;- runs unit tests&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Here is the complete source for build.xml&lt;/div&gt;&lt;div&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;project name="deals-share-extension"&lt;br /&gt; default="build" &amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="init" description="initialize build parameters"&amp;gt;&lt;br /&gt;&amp;lt;property file="${basedir}/build.properties" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;path id="classpath.unit.test"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;pathelement location="${dir.name.classes}" /&amp;gt;&lt;br /&gt;    &amp;lt;pathelement location="${dir.junit.lib}/junit.jar"/&amp;gt;&lt;br /&gt;&amp;lt;/path&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="incremental" description="incremental build, no clean"&lt;br /&gt;   depends="package" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="build" description="builds entire project from clean"&lt;br /&gt;   depends="clean, incremental" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="clean"&amp;gt;&lt;br /&gt;&amp;lt;delete dir="${dir.name.build}" verbose="true" includeemptydirs="true"/&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="compile"&lt;br /&gt;   depends="init"&amp;gt;&lt;br /&gt;&amp;lt;mkdir dir="${dir.name.build}/${dir.name.classes}" /&amp;gt;&lt;br /&gt;&amp;lt;javac destdir="${dir.name.build}/${dir.name.classes}" fork="true"&lt;br /&gt;   memoryMaximumSize="${mem.size.max}" deprecation="${javac.deprecation}"&lt;br /&gt;   debug="${javac.debug}"  target="${javac.target}" source="${javac.source}" encoding="${javac.encoding}"&lt;br /&gt;   excludes="@{compileExcludes}" &amp;gt;&lt;br /&gt;&amp;lt;src path="${dir.name.source}/${dir.name.java}" /&amp;gt;&lt;br /&gt;&amp;lt;classpath refid="classpath.compile" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/javac&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;copy todir="${dir.name.build}/${dir.name.classes}"&amp;gt;&lt;br /&gt;&amp;lt;fileset dir="${dir.name.source}/${dir.name.java}"&amp;gt;&lt;br /&gt;  &amp;lt;patternset&amp;gt;&lt;br /&gt;     &amp;lt;exclude name="**/*.java" /&amp;gt;&lt;br /&gt;     &amp;lt;exclude name="log4j.properties" /&amp;gt;&lt;br /&gt;  &amp;lt;/patternset&amp;gt;&lt;br /&gt;&amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/copy&amp;gt;&lt;br /&gt;&amp;lt;copy todir="${dir.name.build}/${dir.name.classes}"&amp;gt;&lt;br /&gt;&amp;lt;fileset dir="${dir.name.config}"&amp;gt;&lt;br /&gt;  &amp;lt;patternset&amp;gt;&lt;br /&gt;     &amp;lt;exclude name="**/*.java" /&amp;gt;&lt;br /&gt;     &amp;lt;exclude name="log4j.properties" /&amp;gt;&lt;br /&gt;  &amp;lt;/patternset&amp;gt;&lt;br /&gt;&amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/copy&amp;gt;&lt;br /&gt;&amp;lt;copy todir="${dir.name.build}"&amp;gt;&lt;br /&gt;&amp;lt;fileset dir="${dir.name.source}/${dir.name.web}"&amp;gt;&lt;br /&gt;  &amp;lt;patternset&amp;gt;&lt;br /&gt;     &amp;lt;exclude name="**/*.java" /&amp;gt;&lt;br /&gt;     &amp;lt;exclude name="log4j.properties" /&amp;gt;&lt;br /&gt;  &amp;lt;/patternset&amp;gt;&lt;br /&gt;&amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/copy&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="package" description="Creates jar file"&lt;br /&gt;   depends="compile"&amp;gt;&lt;br /&gt;&amp;lt;mkdir dir="${dir.name.dist}" /&amp;gt;&lt;br /&gt;&amp;lt;jar jarfile="${dir.name.dist}/${file.name.jar}"&lt;br /&gt;   basedir="${dir.name.build}/${dir.name.classes}" /&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="deploy" description="copy into share expanded share deployment"&lt;br /&gt;   depends="package"&amp;gt;&lt;br /&gt;&amp;lt;copy todir="${env.APP_TOMCAT_HOME}/webapps/share/WEB-INF/lib"&amp;gt;&lt;br /&gt;&amp;lt;fileset dir="${dir.name.dist}"&amp;gt;&lt;br /&gt;  &amp;lt;patternset&amp;gt;&lt;br /&gt;     &amp;lt;include name="**/*.jar" /&amp;gt;&lt;br /&gt;  &amp;lt;/patternset&amp;gt;&lt;br /&gt;&amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/copy&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;copy todir="${env.APP_TOMCAT_HOME}/webapps/share/WEB-INF/classes"&amp;gt;&lt;br /&gt;&amp;lt;fileset dir="${dir.name.config}"&amp;gt;&lt;br /&gt;  &amp;lt;patternset&amp;gt;&lt;br /&gt;       &amp;lt;include name="alfresco/**/*"/&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;/patternset&amp;gt;&lt;br /&gt;&amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/copy&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;copy todir="${env.APP_TOMCAT_HOME}/webapps/share"&amp;gt;&lt;br /&gt;&amp;lt;fileset dir="${dir.name.source}/${dir.name.web}"&amp;gt;&lt;br /&gt;  &amp;lt;patternset&amp;gt;&lt;br /&gt;      &amp;lt;include name="**/*.js"/&amp;gt;&lt;br /&gt;      &amp;lt;include name="**/*.css"/&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;/patternset&amp;gt;&lt;br /&gt;&amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/copy&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="test" description="run tests and generate results"&lt;br /&gt;   depends="compile"&amp;gt;&lt;br /&gt;&amp;lt;mkdir dir="${dir.name.build}/${dir.name.tes t.results}" /&amp;gt;&lt;br /&gt;&amp;lt;junit printsummary="yes" fork="yes" maxmemory="${mem.size.max}" haltonfailure="yes" dir="@{projectdir}"&amp;gt;&lt;br /&gt;&amp;lt;jvmarg value="-server"/&amp;gt;&lt;br /&gt;&amp;lt;classpath refid="classpath.unit.test" /&amp;gt;&lt;br /&gt;&amp;lt;formatter type="xml" /&amp;gt;&lt;br /&gt;&amp;lt;batchtest todir="${dir.name.build}/${dir.name.test.results}"&amp;gt;&lt;br /&gt;  &amp;lt;fileset dir="${dir.name.source}/${dir.name.java}"&amp;gt;&lt;br /&gt;     &amp;lt;patternset includes="**/*Tests.java" /&amp;gt;&lt;br /&gt;  &amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/batchtest&amp;gt;&lt;br /&gt;&amp;lt;/junit&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;Supporting the build.xml file is the build.properties file:&lt;div&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;#directory names&lt;br /&gt;&lt;br /&gt;dir.name.assemble=assemble&lt;br /&gt;dir.name.bin=bin&lt;br /&gt;dir.name.build=build&lt;br /&gt;dir.name.classes=classes&lt;br /&gt;dir.name.config=config&lt;br /&gt;dir.name.source=source&lt;br /&gt;dir.name.devenv=devenv&lt;br /&gt;dir.name.dist=dist&lt;br /&gt;dir.name.distro=distro&lt;br /&gt;dir.name.docs=docs&lt;br /&gt;dir.name.generated=generated&lt;br /&gt;dir.name.java=java&lt;br /&gt;dir.name.lib=lib&lt;br /&gt;dir.name.test.results=&lt;br /&gt;dir.name.test.results=test-results&lt;br /&gt;dir.name.test.resources=test-resources&lt;br /&gt;dir.name.web=web&lt;br /&gt;&lt;br /&gt;file.name.jar=deals-share-ext.jar&lt;br /&gt;&lt;br /&gt;dir.junit.lib=lib&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;Step 3 - Create an extension spring bean configuration&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Within the slingshot project in /config/alfresco there is a spring context file 'slingshot-application-context.xml' which among other things defines search paths for web scripts and surf model objects. These spring beans are referred to from the 'web-framework-config-application.xml' defining the beans for finding the model types in surf. What is needed is to add a search path to identify the custom webscripts and model objects we will extend in share. One mechanism to do this is to create a new file under /config/alfresco/web-extension called 'custom-slingshot-application-context.xml' with search paths to find custom components, templates and web scripts.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;beans&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="webframework.searchpath" class="org.alfresco.web.scripts.SearchPath"&amp;gt;&lt;br /&gt;&amp;lt;property name="searchPath"&amp;gt;&lt;br /&gt;&amp;lt;list&amp;gt;&lt;br /&gt;&amp;lt;ref bean="dealscontent.store.webscripts" /&amp;gt;&lt;br /&gt;&amp;lt;ref bean="webframework.remotestore.webscripts" /&amp;gt;&lt;br /&gt;&amp;lt;ref bean="webframework.store.webscripts.custom" /&amp;gt;&lt;br /&gt;&amp;lt;ref bean="webframework.store.webscripts" /&amp;gt;&lt;br /&gt;&amp;lt;ref bean="webscripts.store" /&amp;gt;&lt;br /&gt;&amp;lt;/list&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="dealscontent.store.webscripts" class="org.alfresco.web.scripts.ClassPathStore"&amp;gt;&lt;br /&gt;&amp;lt;property name="mustExist"&amp;gt;&amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;property name="classPath"&amp;gt;&amp;lt;value&amp;gt;orbitz/site-webscripts&amp;lt;/value&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;the 'webframework.searchpath' bean overrides a bean defined in the webscript project used to define search paths for webscript processors. Added to the search path list is a reference to a custom 'dealscontent.store.webscripts' bean which defines the specific folder to search in the classpath for our new webscripts as 'orbitz/site-webscripts'.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;In the next blog entry, we will write code to add a 'new content' button to the document library's toolbar similar to the code written in the 'learning surf' blog entries.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-3074507116851840399?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/3074507116851840399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=3074507116851840399' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/3074507116851840399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/3074507116851840399'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/12/extending-share-1-creating-share.html' title='Extending Share 1 - Creating a Share extension project'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QVQz3EsVFfA/ST1jaeD6QTI/AAAAAAAAABo/Qzzrz6P-Oko/s72-c/deals-share-ex-cap01.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-2647611773581179855</id><published>2008-12-01T12:54:00.000-08:00</published><updated>2009-01-14T12:17:16.289-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='learning surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><title type='text'>Learning Surf 6 - Creating a webscript service</title><content type='html'>In the &lt;a href="http://edlovesjava.blogspot.com/2008/10/learning-surf-5-opening-content-editor.html"&gt;previous blog&lt;/a&gt;, we created a simple dialog to open a content creation form from Share's Document Library page toolbar when we click on our added 'New Content' button. This form invokes the POST for 'slingshot/doclib/action/folder/site/{site}/{container}/{path}' service implemented as part of the RESTful Remote API of Afresco 3.0. As we left it, the 'New Content' button simply creates a folder doing the same job as the 'New Folder' button.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Step 1 - create a new service&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we need to create a webscript service to use instead of the slingshot/doclib/action/folder service. for this blog, I will extend the action services to implement the following url pattern:&lt;br /&gt;&lt;br /&gt;POST slingshot/doclib/action/file/site/{site}/{container}/{path}&lt;br /&gt;&lt;br /&gt;To do this, we will add a new webscript service to the remote api project. Later, we can separate this to our own amp module. As a starting point, we can copy the folder.post.* files to create file.post.* files in Remote API/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/action directory. This creates the following files:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;file.post.desc.xml&lt;/li&gt;&lt;li&gt;file.post.json.ftl&lt;/li&gt;&lt;li&gt;file.post.json.js&lt;/li&gt;&lt;/ul&gt;Now we can modify these files to do the work of creating a file instead of a folder. for 'file.post.desc.xml' we modify the url pattern to the following:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;webscript&amp;gt;&lt;br /&gt;&amp;lt;shortname&amp;gt;folder&amp;lt;/shortname&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;Document List Action - Create folder&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/slingshot/doclib/action/file/site/{site}/{container}&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/slingshot/doclib/action/file/site/{site}/{container}/{path}&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;format default="json"&amp;gt;argument&amp;lt;/format&amp;gt;&lt;br /&gt;&amp;lt;authentication&amp;gt;user&amp;lt;/authentication&amp;gt;&lt;br /&gt;&amp;lt;transaction&amp;gt;required&amp;lt;/transaction&amp;gt;&lt;br /&gt;&amp;lt;/webscript&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;file.post.json.ftl file does not need to be changed, it imports the action.lib.ftl to create a standard results response json format.&lt;br /&gt;file.post.json.js needs to be modified to handle a file instead of a folder.&lt;br /&gt;&lt;br /&gt;The main changes I will make to this script:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;get a 'content' field from the json request object from the create-content form that we added previously.&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt; if (!json.isNull("content"))&lt;br /&gt;{&lt;br /&gt;  content = json.get("content");&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Rename variables folderName, folderDescription, folderTitle, folderPath to fileName, fileDescription, fileTitle, fileDescription and filePath respectively.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create a file node instead of a folder node&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;var fileNode = parentNode.createFile(fileName);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;set the content on the newly created fileNode variable arfter the fileNode.save(); method&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;      fileNode.save();&lt;br /&gt; // Add uifacets aspect for the web client&lt;br /&gt; fileNode.content = content;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Change messaging to reflect saving a file, not a folder.&lt;/li&gt;&lt;/ol&gt;The completed file.post.json.js looks like this:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;import resource="classpath:/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/action/action.lib.js"&amp;gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Create file action&lt;br /&gt;* @method POST&lt;br /&gt;* @param uri {string} /{siteId}/{containerId}/{filepath}&lt;br /&gt;* @param json.name {string} New file name&lt;br /&gt;* @param json.title {string} Title metadata&lt;br /&gt;* @param json.description {string} Description metadata&lt;br /&gt;* @param json.content {string} Content of file&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Entrypoint required by action.lib.js&lt;br /&gt;*&lt;br /&gt;* @method runAction&lt;br /&gt;* @param p_params {object} common parameters&lt;br /&gt;* @return {object|null} object representation of action result&lt;br /&gt;*/&lt;br /&gt;function runAction(p_params)&lt;br /&gt;{&lt;br /&gt;var results;&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt; // Mandatory: json.name&lt;br /&gt; if (json.isNull("name"))&lt;br /&gt; {&lt;br /&gt;    status.setCode(status.STATUS_BAD_REQUEST, "File name is a mandatory parameter.");&lt;br /&gt;    return;&lt;br /&gt; }&lt;br /&gt; var fileName = json.get("name");&lt;br /&gt;&lt;br /&gt; var parentPath = p_params.path;&lt;br /&gt; var filePath = parentPath + "/" + fileName;&lt;br /&gt;&lt;br /&gt; // Check file doesn't already exist&lt;br /&gt; var existsNode = getAssetNode(p_params.rootNode, filePath);&lt;br /&gt; if (typeof existsNode == "object")&lt;br /&gt; {&lt;br /&gt;    status.setCode(status.STATUS_BAD_REQUEST, "File '" + filePath + "' already exists.");&lt;br /&gt;    return;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // Check parent exists&lt;br /&gt; var parentNode = getAssetNode(p_params.rootNode, parentPath);&lt;br /&gt; if (typeof parentNode == "string")&lt;br /&gt; {&lt;br /&gt;    status.setCode(status.STATUS_NOT_FOUND, "Parent folder '" + parentPath + "' not found.");&lt;br /&gt;    return;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // Title and description&lt;br /&gt; var fileTitle = "";&lt;br /&gt; var fileDescription = "";&lt;br /&gt; if (!json.isNull("title"))&lt;br /&gt; {&lt;br /&gt;    fileTitle = json.get("title");&lt;br /&gt; }&lt;br /&gt; if (!json.isNull("description"))&lt;br /&gt; {&lt;br /&gt;    fileDescription = json.get("description");&lt;br /&gt; }&lt;br /&gt; if (!json.isNull("content"))&lt;br /&gt; {&lt;br /&gt;    content = json.get("content");&lt;br /&gt; }&lt;br /&gt; // Create the folder and apply metadata&lt;br /&gt; var fileNode = parentNode.createFile(fileName);&lt;br /&gt; // Always add title &amp;amp; description, default icon&lt;br /&gt; fileNode.properties["cm:title"] = fileTitle;&lt;br /&gt; fileNode.properties["cm:description"] = fileDescription.substr(0, 100);&lt;br /&gt; fileNode.properties["app:icon"] = "space-icon-default";&lt;br /&gt; fileNode.save();&lt;br /&gt; // Add uifacets aspect for the web client&lt;br /&gt; fileNode.content = content;&lt;br /&gt; fileNode.addAspect("app:uifacets");&lt;br /&gt;&lt;br /&gt; // Construct the result object&lt;br /&gt; results = [&lt;br /&gt; {&lt;br /&gt;    id: filePath,&lt;br /&gt;    name: fileName,&lt;br /&gt;    parentPath: parentPath,&lt;br /&gt;    nodeRef: fileNode.nodeRef.toString(),&lt;br /&gt;    action: "createFile",&lt;br /&gt;    success: true&lt;br /&gt; }];&lt;br /&gt;}&lt;br /&gt;catch(e)&lt;br /&gt;{&lt;br /&gt;   status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, e.toString());&lt;br /&gt;   return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return results;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Bootstrap action script */&lt;br /&gt;main();&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This service uses the action.lib.js and action.lib.ftl libraries to simplify coding of similar functions, including: checkin, checkout, cancel-checkout, copy-to, move-to, file or folder delete and others. The action.lib.js is included in the folder.post.json.js script and provides a main() entry point to do common setup, clean up and host shared functions. The main entry point calls the runAction() function defined in the specific action script 'folder.post.json.js', effectively implementing a strategy pattern.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Step 3 - build and test&lt;/span&gt;&lt;br /&gt;Since we have changed the Remote API source code, we must build alfresco.war and deploy to tomcat. I use the default ant task:&lt;br /&gt;&lt;blockquote&gt;ant build-tomcat &lt;/blockquote&gt;&lt;br /&gt;to make sure all my changes are built. This will deploy share.war and alfresco.war.&lt;br /&gt;Start up tomcat.&lt;br /&gt;To view the new service, use the url &lt;a href="http://localhost:8081/alfresco/service/index/uri/slingshot/doclib/action/file/site/%7Bsite%7D/%7Bcontainer%7D"&gt;http://localhost:8081/alfresco/service/index/uri/slingshot/doclib/action/file/site/%7Bsite%7D/%7Bcontainer%7D&lt;/a&gt; which should show the service correctly added.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Step 4 - alter 'New Content' button action to invoke new service&lt;/span&gt;&lt;br /&gt;Now we have to use this new service we have created when we press the 'new content' button we added in the &lt;a href="http://edlovesjava.blogspot.com/2008/10/learning-surf-5-opening-content-editor.html"&gt;previous post&lt;/a&gt;. Change the toolbar.js onNewContent action line to read:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;         var actionUrl = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "slingshot/doclib/action/file/site/{site}/{container}/{path}",&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;this will call  our new slingshot service to create a file, which in turn will call the new remote api service we added to alfresco.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Step 5 - deploy and test&lt;/span&gt;&lt;br /&gt;Now, you should be able to press 'New Content' in share Document Library and create a new content item.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-2647611773581179855?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/2647611773581179855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=2647611773581179855' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/2647611773581179855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/2647611773581179855'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/12/learning-surf-6-creating-webscript.html' title='Learning Surf 6 - Creating a webscript service'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-7658543859095336220</id><published>2008-10-31T17:50:00.000-07:00</published><updated>2008-12-05T10:22:09.362-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='learning surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><title type='text'>Learning Surf 5 - Opening a content editor</title><content type='html'>In this blog entry, I will build on the tutorial in my &lt;a href="http://edlovesjava.blogspot.com/2008/10/surf-4-modifying-share-documentlibrary.html"&gt;last blog entry&lt;/a&gt; where I added a new button to the toolbar of the Document Library section of the Share application. When we click on this 'create' button, a dialog box should open (light box) with a form to create a new content item. When we press 'ok', a new content item should be created with the given name in the current folder.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step 1 - Create a form webscript&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My model example will be the document library 'create folder' web script in Share. This ui webscript contains a form to create a new folder. It is opened from clicking the 'New Folder' button on the Document Library section of Share. This function opens a form in a popup dialog like I want.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;To create the web script ui form template, I will start by copying the create-folder.get.*.* webscript files from $SLINGSHOT_SRC_DIR/config/alfresco/site-webscripts/org/alfresco/modules/documentlibrary to $SLINGSHOT_SRC_DIR/config/alfresco/site-webscripts/org/alfresco/components/documentlibrary and rename them to 'create-content.get.*.*'.  This creates three files:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;create-content.get.desc.xml,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;create-content.get.html.ftl&lt;br /&gt;&lt;/li&gt;&lt;li&gt;create-content.get.properties&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Inside of create-content.get.desc.xml, we need to change the URI of the webscript to /components/documentlibrary/create-content and its description. create-content.get.desc.xml should now read:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;webscript&amp;gt;&lt;br /&gt;&amp;lt;shortname&amp;gt;content-createform&amp;lt;/shortname&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;Displays a form to create html content&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;url&amp;gt;/components/documentlibrary/create-content&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;/webscript&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Now we have a new ui webscript component 'create-content' that we can call within a dialog that will render a form. The form contains labels for creating a folder  so we can modify the create-content.get.properties with custom messages for this dialog:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;## Titles&lt;br /&gt;title=Create Content&lt;br /&gt;header=New Content Details&lt;br /&gt;&lt;br /&gt;## Labels&lt;br /&gt;label.name=Name&lt;br /&gt;label.title=Title&lt;br /&gt;label.description=Description&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Step 2 - Registering the new Web Script&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Since we have created a new ui web script at /components/documentlibrary/create-content we need to register it. We simply go to '&lt;a href="http://localhost:8080/share/service/index"&gt;http://localhost:8080/share/service/index&lt;/a&gt;' and click the 'refresh web scripts' button. This will scan for new web scripts. See the &lt;a href="http://wiki.alfresco.com/wiki/Web_Scripts_Hello_World_Quick_Start"&gt;web scripts hello world quick start wiki &lt;/a&gt;page for more details. This page also shows a count of the total web scripts registered. We should see this increase by one. To verify the webscript is registered, we can click 'Browse by Web Script UI' and find our new component at  '/components/documentlibrary/create-content'. Clicking on our uri, we see a details page describing the component.  This information is taken from the 'create-content.get.desc.xml' file.&lt;br /&gt;&lt;br /&gt;To test our new component, we can enter its url: '&lt;a href="http://localhost:8080/share/service/components/documentlibrary/create-content"&gt;http://localhost:8080/share/service/components/documentlibrary/create-content&lt;/a&gt;'. This will error in the web script because it requires the htmlid parameter to exist. If we enter '&lt;a href="http://localhost:8080/share/service/components/documentlibrary/create-content?htmlid"&gt;http://localhost:8080/share/service/components/documentlibrary/create-content?htmlid&lt;/a&gt;' this will satisfy the requirement and the form should render.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 3 - Opening the form in a dialog&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In my &lt;a href="http://edlovesjava.blogspot.com/2008/10/surf-4-modifying-share-documentlibrary.html"&gt;previous blog entry&lt;/a&gt;, we added a button to the toolbar of the Document Library named 'Create' which currently opens a popup message saying feature is not implemented. We will modify the 'Create' button behavior on Document Library toolbar to open this new create-content form in a dialog. In the previous blog, we created the onFileCreate action handler function of $SLINGSHOT_SRC_DIR/source/web/components/documentlibrary/toolbar.js to open a simple popup indicating the feature was not created yet. We will change this behavior by looking at the 'onFolderCreate' function as an example of opening a template in a dialog.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We will copy the body of DLTB_onFolderCreate into the body of DLTB_onFileCreate and change the line&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "modules/documentlibrary/create-folder",&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;To read&lt;br /&gt;&lt;div&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "components/documentlibrary/create-content",&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Where the final function should read:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;  onFileCreate: function DLTB_onFileCreate(e, p_obj)&lt;br /&gt;{&lt;br /&gt;var actionUrl = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "slingshot/doclib/action/folder/site/{site}/{container}/{path}",&lt;br /&gt;{&lt;br /&gt;site: this.options.siteId,&lt;br /&gt;container: this.options.containerId,&lt;br /&gt;path: this.currentPath&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;var doSetupFormsValidation = function DLTB_oNF_doSetupFormsValidation(p_form)&lt;br /&gt;{&lt;br /&gt;// Validation&lt;br /&gt;// Name: mandatory value&lt;br /&gt;p_form.addValidation(this.id + "-createFolder-name", Alfresco.forms.validation.mandatory, null, "keyup");&lt;br /&gt;// Name: valid filename&lt;br /&gt;p_form.addValidation(this.id + "-createFolder-name", Alfresco.forms.validation.nodeName, null, "keyup");&lt;br /&gt;p_form.setShowSubmitStateDynamically(true, false);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;if (!this.modules.createFolder)&lt;br /&gt;{&lt;br /&gt;this.modules.createFolder = new Alfresco.module.SimpleDialog(this.id + "-createFolder").setOptions(&lt;br /&gt;{&lt;br /&gt;width: "30em",&lt;br /&gt;//               templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "modules/documentlibrary/create-folder",&lt;br /&gt;templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "components/documentlibrary/create-content",&lt;br /&gt;actionUrl: actionUrl,&lt;br /&gt;doSetupFormsValidation:&lt;br /&gt;{&lt;br /&gt;fn: doSetupFormsValidation,&lt;br /&gt;scope: this&lt;br /&gt;},&lt;br /&gt;firstFocus: this.id + "-createFolder-name",&lt;br /&gt;onSuccess:&lt;br /&gt;{&lt;br /&gt;fn: function DLTB_onNewFolder_callback(response)&lt;br /&gt;{&lt;br /&gt;var folder = response.json.results[0];&lt;br /&gt;YAHOO.Bubbling.fire("folderCreated",&lt;br /&gt;{&lt;br /&gt;name: folder.name,&lt;br /&gt;parentPath: folder.parentPath,&lt;br /&gt;nodeRef: folder.nodeRef&lt;br /&gt;});&lt;br /&gt;Alfresco.util.PopupManager.displayMessage(&lt;br /&gt;{&lt;br /&gt;text: this._msg("message.new-folder.success", folder.name)&lt;br /&gt;});&lt;br /&gt;},&lt;br /&gt;scope: this&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;this.modules.createFolder.setOptions(&lt;br /&gt;{&lt;br /&gt;actionUrl: actionUrl,&lt;br /&gt;clearForm: true&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;this.modules.createFolder.show();&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;A lot more needs to be done. But at this point we should test our code.&lt;br /&gt;&lt;div&gt;To build and deploy, I use ant 'incremental-slinghot-tomcat' which should create the share.war and deploy to $APP_TOMCAT_HOME.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Clicking on the 'Create' button of Document Library, this is what we should now see:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_QVQz3EsVFfA/SRsE8nAAdOI/AAAAAAAAAA8/intPPz27hjQ/s1600-h/create+content+popup+dialog+screenshot.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 186px;" src="http://4.bp.blogspot.com/_QVQz3EsVFfA/SRsE8nAAdOI/AAAAAAAAAA8/intPPz27hjQ/s320/create+content+popup+dialog+screenshot.jpg" alt="" id="BLOGGER_PHOTO_ID_5267809628447601890" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Currently, this web script dialog should create a folder, not a content item that we want. We will modify this in the next step.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Step 4 - Modifying the Create Content dialog to accept content&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the dialog we are creating, some things to notice about the construction of the Alfresco.SimpleDialog object in our 'onCreateContent action handler function:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The 'actionURI' defined at the beginning of the function will be used to invoke the RESTful service on the content repository. Currently this is pointing to the create folder function, but we will change this to create new content.&lt;/li&gt;&lt;li&gt;There are two validators added 'manditory' and 'nodeName' to the name field of the createContent form. We will keep this behavior.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;There is actually no 'content' entered for the new content. In creating a new folder, only the metadata 'name', 'title' and 'description' are needed. To create new content, we would also like to add the actual content. We will do this initially as plain text. Later, we will try to use a WYSIWYG editor.&lt;br /&gt;&lt;br /&gt;To add the 'content' section, we will modify 'create-content.get.html.ftl' and add the following section:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;         &amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;        &amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-content"&amp;gt;${msg("label.content")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;        &amp;lt;div class="yui-u"&amp;gt;&amp;lt;textarea id="${args.htmlid}-content" name="content" rows="3" cols="20" tabindex="3" &amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;     &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here we have added a new div section to contain a textarea html form element with the name '-content'. This text area will allow us to enter plain text to supply content to our new document. Later we will modify this to use the yui html editor. The complete 'create-content.get.html.ftl' template should look like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;div id="${args.htmlid}-dialog" class="create-folder"&amp;gt;&lt;br /&gt;&amp;lt;div class="hd"&amp;gt;${msg("title")}&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="bd"&amp;gt;&lt;br /&gt; &amp;lt;form id="${args.htmlid}-form" action="" method="post"&amp;gt;&lt;br /&gt;    &amp;lt;div class="yui-g"&amp;gt;&lt;br /&gt;       &amp;lt;h2&amp;gt;${msg("header")}:&amp;lt;/h2&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-name"&amp;gt;${msg("label.name")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-u"&amp;gt;&amp;lt;input id="${args.htmlid}-name" type="text" name="name" tabindex="1" /&amp;gt;&amp;amp;nbsp;*&amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-title"&amp;gt;${msg("label.title")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-u"&amp;gt;&amp;lt;input id="${args.htmlid}-title" type="text" name="title" tabindex="2" /&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-description"&amp;gt;${msg("label.description")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-u"&amp;gt;&amp;lt;textarea id="${args.htmlid}-description" name="description" rows="3" cols="20" tabindex="3" &amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;div class="yui-gd"&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-u first"&amp;gt;&amp;lt;label for="${args.htmlid}-content"&amp;gt;${msg("label.content")}:&amp;lt;/label&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;       &amp;lt;div class="yui-u"&amp;gt;&amp;lt;textarea id="${args.htmlid}-content" name="content" rows="3" cols="20" tabindex="3" &amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;div class="bdft"&amp;gt;&lt;br /&gt;       &amp;lt;input type="button" id="${args.htmlid}-ok" value="${msg("button.ok")}" tabindex="4" /&amp;gt;&lt;br /&gt;       &amp;lt;input type="button" id="${args.htmlid}-cancel" value="${msg("button.cancel")}" tabindex="5" /&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt; &amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;You may also have noticed that we added a new label 'content', so we will have to update our create-content.get.properties file to include it.&lt;br /&gt;&lt;blockquote&gt;label.content=content&lt;/blockquote&gt;Now that our form has the new '-content' field, we can extract content entered from it, and use it to pass to a remote webscript to create this content. To accomplish the creation of a new file, we need to create a new service. This will be the subject of my next blog entry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-7658543859095336220?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/7658543859095336220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=7658543859095336220' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/7658543859095336220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/7658543859095336220'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/10/learning-surf-5-opening-content-editor.html' title='Learning Surf 5 - Opening a content editor'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QVQz3EsVFfA/SRsE8nAAdOI/AAAAAAAAAA8/intPPz27hjQ/s72-c/create+content+popup+dialog+screenshot.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-4602028019782839761</id><published>2008-10-30T11:19:00.000-07:00</published><updated>2008-12-05T10:22:09.363-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='learning surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><title type='text'>Learning Surf 4 - Modifying Share documentLibrary with Create Content button</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;/div&gt;This and the next blog entries will walk through the process of adding a new button to the documentLibrary section of Share which will allow the creation of new content using an in-line WYSIWYG editor.&lt;br /&gt;&lt;br /&gt;This blog will add a 'Create' button to the toolbar of the Document Library module and open a popup when clicked showing a message 'feature not implemented yet'&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Step 1 - mapping the terrain&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As I have done in &lt;a href="http://edlovesjava.blogspot.com/2008/10/more-analysis-of-slingshot-share.html"&gt;previous blog entries&lt;/a&gt;, I will draw a picture of the dependent files (xml, freemarker and javascript) that renders the relevant portion of the document library, and indicate what needs to be modified.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_QVQz3EsVFfA/SQn78gUivHI/AAAAAAAAAAk/r6U61p0_L-A/s1600-h/documentLibrary+configuration.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 255px; height: 320px;" src="http://4.bp.blogspot.com/_QVQz3EsVFfA/SQn78gUivHI/AAAAAAAAAAk/r6U61p0_L-A/s320/documentLibrary+configuration.jpg" alt="" id="BLOGGER_PHOTO_ID_5263014656445955186" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As shown before, the key files are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;'site-data/pages/documentLibrary.xml' page references 'documentLibrary.xml' template-instance&lt;br /&gt;&lt;/li&gt;&lt;li&gt;'site-data/template-instances/documentLibrary.xml' contains reference to 'org/alfresco/documentLibrary' template type&lt;/li&gt;&lt;li&gt;'templates/org/alfresco/documentLibrary.ftl' contains the structure of the page with regions containing components including the 'toolbar' region&lt;br /&gt;&lt;/li&gt;&lt;li&gt;'site-data/components/template.toolbar.documentLibrary.xml' defines the component to fit in region 'toolbar' of template 'documentLibrary' refrencing a webscript ui component registered to the url '/components/documentlibrary/toolbar'&lt;/li&gt;&lt;li&gt;site-webscripts/org/alfresco/components/documentlibrary/toolbar.get.desc.xml' describes the ui webscript registered to the '/components/library/toolbar' url, it includes freemarker renderers 'toolbar.get.head.ftl' and 'toolbar.get.html.ftl'.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;'toolbar.get.head.ftl' references toolbar.js and toolbar.css found in 'web/components/documentlibrary/' source folder.&lt;/li&gt;&lt;/ul&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Step 2 - Add the button to the template&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The 'toolbar' component contains the space for the 'create' button I wish to add. Within the 'toolbar.get.html.ftl' I have added a couple of lines for the new button:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt; &amp;lt;div class="new-folder hideable DocListTree"&amp;gt;&amp;lt;button id="${args.htmlid}-newFolder-button" name="newFolder"&amp;gt;${msg("button.new-folder")}&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Added by EEW 20081030 --&amp;gt;&lt;br /&gt;&amp;lt;div class="separator hideable DocListTree"&amp;gt;&amp;amp;nbsp;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="file-create hideable DocListTree"&amp;gt;&amp;lt;button id="${args.htmlid}-fileCreate-button" name="fileCreate"&amp;gt;${msg("button.create")}&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;!-- End Added --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div class="separator hideable DocListTree"&amp;gt;&amp;amp;nbsp;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class="file-upload hideable DocListTree"&amp;gt;&amp;lt;button id="${args.htmlid}-fileUpload-button" name="fileUpload"&amp;gt;${msg("button.upload")}&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Step 3 - Add Messages for the button&lt;/span&gt;&lt;div&gt;&lt;br /&gt;This code also changes the 'toolbar.get.properties' file adding the key/value 'button.create=Create',&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Step 4 - Add CSS Entries and Images for the button&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; and the toolbar.css used to render the button:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;/* added by EEW 20081030 */&lt;br /&gt;&lt;br /&gt;.toolbar .file-create button&lt;br /&gt;{&lt;br /&gt;background: transparent url(images/create-16.png) no-repeat 12px 4px;&lt;br /&gt;padding-left: 32px;&lt;br /&gt;}&lt;br /&gt;.toolbar .file-create .yui-button-disabled button&lt;br /&gt;{&lt;br /&gt;background-image: url(images/create-disabled-16.png);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* done added */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As implied by the css above, I have also created two new images to appear with the button: create-16.png and create-disabled-16.png. For testing purposes, I simply copied edit-blog-16.png.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Step 5 - Add the Button as a YUI Button&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;In 'toolbar.js', I have added a line to instantiate the YUI button named in the toolbar template in the 'onReady' YUI event listener&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;   &lt;br /&gt;   // added by EEW 20081030&lt;br /&gt;&lt;br /&gt;   // File Create button: user needs  "create" access&lt;br /&gt;   this.widgets.fileCreate = Alfresco.util.createYUIButton(this, "fileCreate-button", this.onFileCreate,&lt;br /&gt;   {&lt;br /&gt;      disabled: true,&lt;br /&gt;      value: "create"&lt;br /&gt;   });&lt;br /&gt;   // done added&lt;br /&gt;&lt;br /&gt;   // File Upload button: user needs  "create" access&lt;br /&gt;   this.widgets.fileUpload = Alfresco.util.createYUIButton(this, "fileUpload-button", this.onFileUpload,&lt;br /&gt;   {&lt;br /&gt;      disabled: true,&lt;br /&gt;      value: "create"&lt;br /&gt;   });&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In this code, we see that the YUI button ties the name  'fileCreate-button' (which is the id in the button tag defined in 'toolbar.get.html.ftl'), and the event name 'onFileCreate', which will fire when the button is clicked. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Step 6 - Add the Event Code&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The event is also defined in toolbar.js:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;      /**&lt;br /&gt; * File Create click handler&lt;br /&gt; *&lt;br /&gt; * @method onFileCreate&lt;br /&gt; * @param e {object} DomEvent&lt;br /&gt; * @param p_obj {object} Object passed back from addListener method&lt;br /&gt; */&lt;br /&gt;onFileCreate: function DLTB_onFileCreate(e, p_obj)&lt;br /&gt;{&lt;br /&gt;/*&lt;br /&gt;   var url = YAHOO.lang.substitute(Alfresco.constants.URL_CONTEXT + "page/site/{site}/blog-postedit?container={container}",&lt;br /&gt;   {&lt;br /&gt;      site: this.options.siteId,&lt;br /&gt;      container: this.options.containerId&lt;br /&gt;   });&lt;br /&gt;   window.location = url;&lt;br /&gt;   Event.preventDefault(e);&lt;br /&gt;*/&lt;br /&gt;   var notimpTitle = this._msg("title.notimp");&lt;br /&gt;   var notimpMsg = this._msg("message.notimp", "Create Content");&lt;br /&gt;&lt;br /&gt;   Alfresco.util.PopupManager.displayPrompt(&lt;br /&gt;   {&lt;br /&gt;      title: notimpTitle,&lt;br /&gt;      text: Alfresco.util.decodeHTML(notimpMsg),&lt;br /&gt;      noEscape: true,&lt;br /&gt;      modal: true,&lt;br /&gt;      buttons: [&lt;br /&gt;      {&lt;br /&gt;         text: this._msg("button.cancel"),&lt;br /&gt;         handler: function DLTB_onActionDelete_cancel()&lt;br /&gt;         {&lt;br /&gt;            this.destroy();&lt;br /&gt;         }&lt;br /&gt;      }]&lt;br /&gt;   });&lt;br /&gt;&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This event handler will open a popup message for now showing that this feature is not yet implemented.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Step 7 - Add The Messages for the Popup Message Box&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;At this point I am only defining a placeholder for this event. In order to support the above popup, I have included the message keys to 'toolbar.get.properties':&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;## Added by EEW 20081031&lt;br /&gt;&lt;br /&gt;button.create=Create&lt;br /&gt;title.notimp=Not Implemented&lt;br /&gt;message.notimp = Feature {0} is not implemented yet.&lt;br /&gt;&lt;br /&gt;## Done Added&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Step 8 - Build, Deploy and Test&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;To test, I use ant task 'incremental-slingshot-tomcat' to build and deploy my changes to tomat. As a remider, the ant task requires environment variables TOMCAT_HOME and APP_TOMCAT_HOME to be defined to the installed tomcat.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And you should see this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QVQz3EsVFfA/SQuXSftgqQI/AAAAAAAAAAs/16w6YkSH-Es/s1600-h/ScreenHunter_03+Oct.+31+18.42.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 210px;" src="http://3.bp.blogspot.com/_QVQz3EsVFfA/SQuXSftgqQI/AAAAAAAAAAs/16w6YkSH-Es/s320/ScreenHunter_03+Oct.+31+18.42.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5263466933518379266" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QVQz3EsVFfA/SQuYBAjgEFI/AAAAAAAAAA0/I10WiOw73AA/s1600-h/ScreenHunter_06+Oct.+31+18.46.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 210px;" src="http://2.bp.blogspot.com/_QVQz3EsVFfA/SQuYBAjgEFI/AAAAAAAAAA0/I10WiOw73AA/s320/ScreenHunter_06+Oct.+31+18.46.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5263467732608749650" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-4602028019782839761?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/4602028019782839761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=4602028019782839761' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4602028019782839761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4602028019782839761'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/10/surf-4-modifying-share-documentlibrary.html' title='Learning Surf 4 - Modifying Share documentLibrary with Create Content button'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QVQz3EsVFfA/SQn78gUivHI/AAAAAAAAAAk/r6U61p0_L-A/s72-c/documentLibrary+configuration.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-4916219019266426303</id><published>2008-10-29T11:16:00.000-07:00</published><updated>2008-12-05T10:22:09.364-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='learning surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><title type='text'>Learning Surf 3 - More analysis of Slingshot (Share) - looking at Blog List</title><content type='html'>Please see my &lt;a href="http://edlovesjava.blogspot.com/2008/10/examining-slingshot-configuration.html"&gt;previous blog entry&lt;/a&gt; for more detail on general concepts of Slingshot's configuration as a Surf platform application.&lt;br /&gt;&lt;br /&gt;In the next blogs, I will attempt enhancing Share to add a 'create' button along side of the 'upload' button in the 'document Library' section which will open an in-place WYSIWYG editor to create html based content. In preparation for this, I will look at similar code implemented to post a blog entry.&lt;br /&gt;&lt;br /&gt;In Share (Slingshot), creating or selecting a site from the dashboard 'sites' dashlet opens the site dashboard. The top navigation provides buttons to select 'Blog' to view and enter blog entries. Selecting 'blog' creates the URL:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;http://localhost:8080/share/page/site/mc/blog-postlist&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;One of the difficulties in getting your head around working with Surf based web applications is understanding how everything is connected together.  I will attempt to show how the bloglist page is rendered.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QVQz3EsVFfA/SQiqXVEGiaI/AAAAAAAAAAc/nkij5nzqjUU/s1600-h/bloglist+configuration.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 170px;" src="http://2.bp.blogspot.com/_QVQz3EsVFfA/SQiqXVEGiaI/AAAAAAAAAAc/nkij5nzqjUU/s320/bloglist+configuration.jpg" alt="" id="BLOGGER_PHOTO_ID_5262643482350487970" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This diagram shows my map of the dependencies of the various xml, javascript and freemarker files that assemble the bloglist page.&lt;br /&gt;&lt;br /&gt;Decomposing the url, we see the pattern /page/* which maps to the pageRendererServlet. Using the 'config/alfresco/web-framework-config-application.xml' which defines url patterns to find the /site/{site}/blog-postlist from the object model defined in xml files, found according to the search path for the types of components it is looking for (see previous blog).&lt;br /&gt;&lt;br /&gt;'site-data/pages/blog-postlist.xml' defines a page model object for the page. It refers to a template instance blog-postlist.xml.&lt;br /&gt;&lt;br /&gt;'site-data/template-instances/blog-postlist.xml' defines a template-instance model object which refers to the template-type found using org/alfresco/blog-postlist&lt;br /&gt;&lt;br /&gt;'templates/org/alfresco/blog-postlist.ftl' is found as the search for template types assumes a freemarker template at the path defined if not explicitly defined &lt;a href="http://wiki.alfresco.com/wiki/Surf_Platform_-_Developers_Guide#Template_Instance"&gt;see surf developer documentation&lt;/a&gt;. This template works in conjunction with component definitions to associate components with regions defined in the source template.&lt;br /&gt;&lt;br /&gt;'site-data/components/template.postlist.blog-postlist.xml' provides component mapping to region 'postlist' in source id 'blog-postlist', mapping to a component found by url '/components/blog/postlist'&lt;br /&gt;&lt;br /&gt;'site-webscripts/org/alfresco/components/blog/postlist.get.desc.xml' ui webscript is registered to the url pattern defined for the template and uses 'postlist.get.head.ftl' and 'postlist.get.html.ftl' as renderers.&lt;br /&gt;&lt;br /&gt;'site-webscripts/org/alfresco/components/blog/postlist.get.head.ftl' links to the 'postlist.js' javascript.&lt;br /&gt;&lt;br /&gt;'source/web/components/blog/postlist.js' among other things defines a yui button to create a blog post (createPost-button), which when pressed will call the onCreatePost action handler.&lt;br /&gt;&lt;br /&gt;'site-webscripts/org/alfresco/components/blog/postlist.get.html.ftl' renders the Blog post list page, including the 'createPost-button' yui button. Clicking on this button calls the onCreatePost action handler defined in postlist.js' which will in tern compose the url&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;http://localhost:8080/share/page/site/mc/blog-postedit?container=blog&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;This page renders a WYSIWYG editor configured to allow creation of blog entries.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-4916219019266426303?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/4916219019266426303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=4916219019266426303' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4916219019266426303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4916219019266426303'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/10/more-analysis-of-slingshot-share.html' title='Learning Surf 3 - More analysis of Slingshot (Share) - looking at Blog List'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QVQz3EsVFfA/SQiqXVEGiaI/AAAAAAAAAAc/nkij5nzqjUU/s72-c/bloglist+configuration.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-8054167689476995636</id><published>2008-10-27T12:46:00.001-07:00</published><updated>2008-12-05T10:22:09.365-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='learning surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><title type='text'>Learning Surf 2 - Examining slingshot configuration</title><content type='html'>&lt;span style="font-size:180%;"&gt;Examining slingshot configuration&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can see my p&lt;a href="http://edlovesjava.blogspot.com/2008/10/learning-surf-1-building-from-source.html"&gt;revious blog entry&lt;/a&gt; for a background in getting started with surf.&lt;br /&gt;&lt;br /&gt;The Surf platform is a web script based framework for developing web 2.0 based applications that can use the &lt;a href="http://wiki.alfresco.com/wiki/Content_Repository"&gt;alfresco content repository&lt;/a&gt;. It relies on the technologies of xml, &lt;a href="http://freemarker.org/"&gt;freemarker &lt;/a&gt;and javascript. It heavily leverages &lt;a href="http://wiki.alfresco.com/wiki/Surf_Platform_-_Freemarker_Template_and_JavaScript_API"&gt;alfresco's freemarker templates and the javascript api&lt;/a&gt;, and the &lt;a href="http://wiki.alfresco.com/wiki/Web_Scripts"&gt;alfresco's web script technologies&lt;/a&gt; that define ui components or RESTful services.&lt;br /&gt;&lt;br /&gt;Surf based applications can be developed without an Alfresco content repository access, but ones that use the content repository are developed and deployed as two war files, one for the web application built on surf (i.e. share.war), and one for the content repository it accesses (alfresco.war). These war files can be deployed within the same application container (i.e. tomcat)  or different application containers on the same machine or different machines. The web application communicates with the content repository over RESTful services (essentially over http).&lt;br /&gt;&lt;br /&gt;&lt;div&gt;The share application is a surf framework application. The source tree stores share in a project called 'slingshot'. Slighshot depends on other projects in the source tree, including:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;3rd Party&lt;/li&gt;&lt;li&gt;Core&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Web Framework&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Webscript Framework&lt;/li&gt;&lt;/ul&gt;Configurations of a surf application are contained in the following types of configurations:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;war configuration files (web.xml)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;alfresco configuration files (i.e. web-framework-config.xml and LOTS more)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;spring bean configurations (i.e. slingshot-application-context.xml)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;resource bundles (i.e. slingshot.properties)&lt;/li&gt;&lt;/ul&gt;This blog will look at the first three to understand how a surf application is configured.&lt;br /&gt;&lt;br /&gt;To trace the configuration, we start with the war. Whithin the Slingshot application is a source folder which includes web/WEB-INF that contains the web.xml for the share.war.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;looking at web.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;A context-param section is included to define the contextConfigurationLocation for spring to find all of the spring beans that are needed to configure the surf application. These include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;classpath:alfresco/webscript-framework-application-context.xml&lt;br /&gt;&lt;/li&gt;&lt;li&gt;classpath:alfresco/web-framework-application-context.xml&lt;br /&gt;&lt;/li&gt;&lt;li&gt;classpath:alfresco/web-framework-model-context.xml&lt;br /&gt;&lt;/li&gt;&lt;li&gt;classpath:alfresco/slingshot-application-context.xml&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;This ties slingshot to depend on the Webscript Framework and the Web Framework projects.&lt;br /&gt;&lt;br /&gt;A listener is defined with a springframework web context loader listener wihich loads the spring context form the class paths defined in the 'contextConfigurationLocation' context parameter.&lt;br /&gt;&lt;br /&gt;Several servlets are defined&lt;br /&gt;&lt;br /&gt;&lt;table class="zeroBorder"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;url-pattern&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;servlet name&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;servlet class&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/logout&lt;/td&gt;&lt;td&gt;logoutServlet&lt;/td&gt;&lt;td&gt;org.alfresco.web.site.servlet.LogoutServlet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/login/*&lt;/td&gt;&lt;td&gt;loginServlet&lt;/td&gt;&lt;td&gt;org.alfresco.web.site.servlet.LoginServlet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/service/*&lt;/td&gt;&lt;td&gt;apiServlet&lt;/td&gt;&lt;td&gt;org.alfresco.web.scripts.servlet.WebScriptServlet(container=webframework.webscripts.container)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/proxy/*&lt;/td&gt;&lt;td&gt;proxyServlet&lt;/td&gt;&lt;td&gt;org.alfresco.web.scripts.servlet.EndPointProxyServlet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/page/*, p/*&lt;/td&gt;&lt;td&gt;pageRendererServlet&lt;/td&gt;&lt;td&gt;org.alfresco.web.site.servlet.DispatcherServlet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/s/*&lt;/td&gt;&lt;td&gt;uriTemplateServlet&lt;/td&gt;&lt;td&gt;org.alfresco.web.uri.UriTemplateServlet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/control/*&lt;/td&gt;&lt;td&gt;frameworkControlServlet&lt;/td&gt;&lt;td&gt;org.alfresco.web.site.servlet.FrameworkControlServlet&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Finally, weblome file list includes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;index.jsp&lt;br /&gt;&lt;/li&gt;&lt;li&gt;index.html&lt;/li&gt;&lt;/ul&gt;&lt;column#&gt;&lt;row#&gt;&lt;span style="font-size:130%;"&gt;&lt;span class="Apple-style-span"&gt;looking at the web-framework-config alfresco configuration file&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The configuration file defines&lt;/row#&gt;&lt;/column#&gt;&lt;ul&gt;&lt;li&gt;page-mapper&lt;/li&gt;&lt;li&gt;link-builder&lt;/li&gt;&lt;li&gt;file-system&lt;/li&gt;&lt;li&gt;format default&lt;/li&gt;&lt;li&gt;format print&lt;/li&gt;&lt;li&gt;format wap&lt;/li&gt;&lt;li&gt;persisters&lt;/li&gt;&lt;li&gt;model-type (object model) definitions&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;each model-type defines id, name, class, search path and default store for the following model types:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;chrome&lt;/li&gt;&lt;li&gt;component&lt;/li&gt;&lt;li&gt;component-type&lt;/li&gt;&lt;li&gt;configuration&lt;/li&gt;&lt;li&gt;content-association&lt;/li&gt;&lt;li&gt;page&lt;/li&gt;&lt;li&gt;page-type&lt;/li&gt;&lt;li&gt;page-association&lt;/li&gt;&lt;li&gt;template-instance&lt;/li&gt;&lt;li&gt;template-type&lt;/li&gt;&lt;li&gt;theme&lt;/li&gt;&lt;/ul&gt;These model-type definitions define where to look for marshaled configurations for model objects of each type, whether to look on the remote store, local path or in the class path.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;looking at spring bean application context files&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Using spring explorer in Eclipse (Ganymede) allowed me to view spring bean configuration dependencies.&lt;br /&gt;&lt;br /&gt;The slingshot-application-context.xml references beans defined in web-framework-application-context.xml and web-framework-model-context.xml.&lt;br /&gt;&lt;br /&gt;The web framework beans reference beans defined in webscript-framework-application-context.xml.&lt;br /&gt;&lt;br /&gt;slingshot-application-context.xml contains the following beans:&lt;br /&gt;&lt;br /&gt;&lt;div id="ol5l" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 700px; height: 495px;" src="http://docs.google.com/File?id=dd28czzp_1g4mcgzgr_b" /&gt;&lt;/div&gt;The 'webscript.resource' bean list resource bundles that contain messages to use. The other beans (i.e.'webframework.searchpath.chrome') tell surf where to look (i.e. search paths) for definitions of the different model components that surf needs to run. For instance, to know how 'chrome' is configured.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;web-framework-application-context.xml contains the following beans:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QVQz3EsVFfA/SQcR0qL-m9I/AAAAAAAAAAU/qr33fXCc4NI/s1600-h/web+framework+app+beans.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 234px;" src="http://2.bp.blogspot.com/_QVQz3EsVFfA/SQcR0qL-m9I/AAAAAAAAAAU/qr33fXCc4NI/s320/web+framework+app+beans.jpg" alt="" id="BLOGGER_PHOTO_ID_5262194285981113298" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:130%;"&gt;Tracing through rendering the dashboard&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To demonstrate the configuration, lets look at the beginning, rendering the dashboard. The share.war defines the welcome page 'index.jsp'. This jsp redirects to '/page/site-index'. As defined in web.xml, /page/* url pattern runs the 'pageRendererServlet'. This servlet looks for a model object named 'site-index'. The name 'site-index' is defined as a page model object found in the default remote store (as defined in web-framework-config.xml for the page model-type) in './site-data/pages'.&lt;/div&gt;&lt;div&gt;'site-index.xml' defines a page model object named 'site-index' which defines:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;title = welcome&lt;/li&gt;&lt;li&gt;descrition = Landing page for users - will create user site dashboard&lt;/li&gt;&lt;li&gt;template-instances = site-index&lt;/li&gt;&lt;li&gt;authentication = user&lt;/li&gt;&lt;/ul&gt;The site-index page model object references a template instance named 'site-index' found also in the default store ( ./site-data/template-instance):&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The template-instance refers to a template-type 'site-index' found in (site-data/template-types) &lt;/div&gt;&lt;div&gt;'site-index.xml' is a template-type model object and defines:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;title = site index landing page template type&lt;/li&gt;&lt;li&gt;description = Site index landing page JSP Template Type&lt;/li&gt;&lt;li&gt;renderer = /site-index.jsp&lt;/li&gt;&lt;li&gt;renderer-type = jsp&lt;/li&gt;&lt;/ul&gt;Looking at '/site-index.jsp' as a jsp template renderer, we see scriptlet logic that follows:&lt;br /&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;If not already created the user dashboard, create the user's dashboard using the definition in presets (found in ./site-data/presets/presets.xml) for 'user-dashboard'.  &lt;/div&gt;&lt;div&gt;Render the user dashboard.&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;In 'user-dashboard' preset, the 'components' section creates components and assigns to regions according to the template insance (dashboard-3-columns) defined in the 'pages' section. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The 'dashboard-3-columns.xml' template-instance definition defines &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;template-type = org/alfresco/dashboard.ftl.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;'dashboard.ftl' imports alfresco-template.ftl and alfresco-layout.ftl and creates regions named 'component-&lt;column#&gt;&lt;column#&gt;-&lt;row#&gt;&lt;row#&gt;' where the preset components are added.&lt;br /&gt;&lt;br /&gt;The preset creates and places the following components into the dashboard template:&lt;br /&gt;define title from (site-webscripts/org/alfresco/components/title/user-dashboard-title*)&lt;br /&gt;define list of page components (dashlets) positioned at {column#}-{row#):&lt;br /&gt;&lt;/row#&gt;&lt;/row#&gt;&lt;/column#&gt;&lt;/column#&gt;&lt;ul&gt;&lt;li&gt;user-welcome at 1-1&lt;/li&gt;&lt;li&gt;user-calendar at 1-2&lt;/li&gt;&lt;li&gt;rssfeed at 2-1&lt;/li&gt;&lt;li&gt;alfresco-network at 2-2&lt;/li&gt;&lt;li&gt;my-activities at 2-3&lt;/li&gt;&lt;li&gt;cmisfeed at 3-4&lt;/li&gt;&lt;li&gt;my-profile at 3-1&lt;/li&gt;&lt;li&gt;my-sites at 3-2&lt;/li&gt;&lt;li&gt;my-tasks at 3-3&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Each dashlet is defined by a ui web-script found in site-webscripts/orgb/alfrsco/components/dashlets/. See a description of alfresco's &lt;a href="http://wiki.alfresco.com/wiki/Web_Scripts"&gt;web-scripts technology&lt;/a&gt; for details on ui web scripts.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-8054167689476995636?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/8054167689476995636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=8054167689476995636' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/8054167689476995636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/8054167689476995636'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/10/examining-slingshot-configuration.html' title='Learning Surf 2 - Examining slingshot configuration'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QVQz3EsVFfA/SQcR0qL-m9I/AAAAAAAAAAU/qr33fXCc4NI/s72-c/web+framework+app+beans.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-6008033924059718121</id><published>2008-10-20T10:19:00.001-07:00</published><updated>2008-12-05T10:22:09.366-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='learning surf'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><title type='text'>Learning Surf 1 - building from source</title><content type='html'>My goal was to build the latest Alfresco from source, and begin to develop and extend it using Eclipse. I followed the instructions on: &lt;a href="http://wiki.alfresco.com/wiki/Alfresco_SVN_Development_Environment"&gt;Alfresco's developer wiki&lt;/a&gt; . I followed the guidance of the Eclipse section to import all alfresco projects.&lt;br /&gt;&lt;br /&gt;Unfortunately, between the first time I did this (early September) and the latest time (October 15), there was significant changes to the codebase that affected the Eclipse projects I imported earlier. I went through the pain of refreshing projects and rebuilding everything until I finally got everything to pass. It was probably better that i deleted these older projects and started with fresh imports. This is a large code base (over 500 meg compressed) so I warn you that this will take some time. Once the code base is built from source, I can follow along refreshing as needed.&lt;br /&gt;&lt;br /&gt;Note, since I am developing on a Windows laptop (dont ask why), I used &lt;a href="http://tortoisesvn.tigris.org/"&gt;tortoise svn&lt;/a&gt;. This worked fairly well for me. I also got the &lt;a href="http://subclipse.tigris.org/"&gt;subversion plug in for Eclipse&lt;/a&gt;. These two seem to work well with each other well for now.&lt;br /&gt;&lt;br /&gt;My first step was to build the alfresco war. I had already created an alfresco database in MySQL as the wiki suggested. I also had tomcat 5.5 installed and Ant so the build was fairly painless.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ant build-tomcat&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This created the alfresco.war and deployed it to TOMCAT_HOME. Make sure to set up the environment variables as described. TOMCAT_HOME will be where the alfresco.war will be deployed. APP_TOMCAT_HOME will be where share.war and alfwf.war will be deployed. These can be different or the same. Alfresco 3.0 is now truly service oriented and webapps can be developed (i.e. share.war) and deployed independently of the repository (alfresco.war). For development purposes, I set these to the same tomcat instance.&lt;br /&gt;&lt;br /&gt;One problem my team ran into was that share.war refused to authenticate admin/admin. We later determined this was due to the fact that we were running tomcat on a different port than 8080 and there were several configuration files that needed to be changed to reflect this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/administration-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/dictionary-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/content-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/authoring-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/access-control-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/action-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/authentication-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/repository-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/alfresco/wsdl/classification-service.wsdl&lt;br /&gt;$ALF_HOME/tomcat/webapps/share/WEB-INF/urlrewrite.xml&lt;br /&gt;$ALF_HOME/tomcat/webapps/share/WEB-INF/classes/alfresco/pagerenderer-config.xml&lt;br /&gt;$ALF_HOME/tomcat/webapps/share/WEB-INF/classes/alfresco/webscript-framework-config-test.xml&lt;br /&gt;$ALF_HOME/tomcat/webapps/share/WEB-INF/classes/alfresco/webscript-framework-config.xml&lt;br /&gt;$ALF_HOME/tomcat/webapps/share/WEB-INF/classes/alfresco/webscripts/org/alfresco/indexall.get.mediawiki.ftl&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After building and deploying alfresco.war and share.war, and testing, I switched to the instructions for &lt;a href="http://wiki.alfresco.com/wiki/Surf_Platform_-_Guided_Examples"&gt;building and deploying the surf platform&lt;/a&gt;. In these instructions, the alfwf.war is built and deployed (alfwf.war) to APP_TOMCAT_HOME. This is a minimal implementation of the webframework that only brings up a test page:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;http://localhost:8080/alfwf/page?p=welcome&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;which runs some tests and dumps some configurations.&lt;br /&gt;&lt;br /&gt;Alfresco Surf applications are created leveraging the following technologies and we should be familiar with all of them:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://wiki.alfresco.com/wiki/JavaScript_API"&gt;JavaScript&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.alfresco.com/wiki/Template_Guide"&gt;FreeMarker&lt;/a&gt;&lt;/li&gt;&lt;li&gt;JSP (if desired)&lt;/li&gt;&lt;li&gt;HTML&lt;/li&gt;&lt;li&gt;XML&lt;/li&gt;&lt;li&gt;Json&lt;/li&gt;&lt;/ul&gt;At this point, the fun begins - creating templates and components to the new surf platform.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-6008033924059718121?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/6008033924059718121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=6008033924059718121' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6008033924059718121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6008033924059718121'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/10/learning-surf-1-building-from-source.html' title='Learning Surf 1 - building from source'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-2902553380137124927</id><published>2008-10-12T09:23:00.000-07:00</published><updated>2008-12-01T14:25:04.449-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Surf'/><category scheme='http://www.blogger.com/atom/ns#' term='CMIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Alfresco'/><title type='text'>Alfresco Community Conference in DC</title><content type='html'>Last week, I attended the &lt;a href="http://www.alfresco.com/media/releases/2008/10/community-conference-dc/"&gt;Alfresco Community Conference in DC&lt;/a&gt; where, among other things, Alfresco's Surf platform was discussed. Alfresco is moving in a bold new technical direction: towards a Web 2.0 framework developed from the ground up, completely overtaking its current Enterprise web framework based on JSF. This is bold because most vendors incrementaly develop over thier legacy frameworks. Alfresco has chosen to radically rewrite theirs. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One of Alfresco's key competitive advantages is that it had the clarity of heindsight. Alfresco could look back at the experience of the past: including Documentum, where it's CTO John Newton was co-founder, and former engineers of Vingette, Interwoven and others. This experience has allowed them to develop a better architecture from the ground up, solving the pain of the past, in a culture steeped in risk taking and innovation. Further, its committment to the community and to open principles has allowed it to continue to lead in innovation, rather than falling behind.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sometimes openness and innovation leads to chaos. Several potential Alfresco users have hedged thier commitment to alfresco to see what Alfresco 3.0 is all about. Its radical rearchitecture has risked alienating customer customization of its previous JSF based frameworks. It is unclear what existing customers will do with this new technology, but Alfresco has committed to continue to support its legacy JSF applications for a time. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For those of us who are just starting to develop on Alfresco, the future is wide open. My company has decided to participate as Beta customers to Alfresco Enterprise 3.0. This leads us to figuring out how we can capitalize on this new platform architecture, and how to avoid the inevitable barbs of its newness.  Among other blog tracks, I will update my experiences with Alfresco Surf platform with how-to's and findings. I hope this proves useful to some.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;From a Technical perspective, Alfresco has rearchitected its front end web client and services relying on Web 2.0 components from Yahoo User Interface framework. The web client talks to services via RESTful JSON enabled services typically created using Alfresco's webscript framework. Surf introduces a new component model with page and component dispatching frameworks. Web client things like Templates, Pages and Components are defined declaratively leveraging lightweight XML, like the webscript framework for declaring RESTful services on alfresco. Like services, client component behavior is developed in JavaScript and benefit from a client side alfresco object model to interact with predefined components and/or alfresco remote services.&lt;br /&gt;&lt;br /&gt;As I learn this new framework, I will blog on each step I take. I hope this will be helpful to others also learning Surf.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-2902553380137124927?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/2902553380137124927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=2902553380137124927' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/2902553380137124927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/2902553380137124927'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/10/alfresco-community-conference-in-dc.html' title='Alfresco Community Conference in DC'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-1681879275270447892</id><published>2008-09-22T05:36:00.000-07:00</published><updated>2008-09-22T07:06:43.646-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Enterprise 2.0'/><title type='text'>Enterprise 2.0</title><content type='html'>I recently attended a workshop sponsored by the &lt;a href="http://www.aiimchicago.org/"&gt;Chicago chapter of AIIM&lt;/a&gt; about Enterprise 2.0. The audience was a typical spread of IT professionals interested in document management, Image scanning and management, records management and of course consultants looking to make contacts. My team, we numbered 4, were first time attendees and were interested in getting ideas relating to our web content management applications.&lt;br /&gt;&lt;br /&gt;Two presentations were given: &lt;a href="http://www.linkedin.com/in/jimvaselopulos"&gt;Jim Vaselopulos&lt;/a&gt; (VP and Partner of &lt;a href="http://www.psclistens.com/"&gt;PSC Group&lt;/a&gt;) focused on the human perspective in collaboration, a key aspect of Enterprise 2.0, and &lt;a href="http://www.linkedin.com/in/apmacmillan"&gt;Andrew MacMillan&lt;/a&gt; (VP of Product Mgmt at &lt;a href="http://www.oracle.com/products/middleware/content-management/index.html"&gt;Oracle ECM&lt;/a&gt; (formally Stellent)) was focused on its technology aspects. Both presentations were compelling: Jim's presentation brought the point home that Enterprise 2.0 technologies were focused on enabling collaboration among content stakeholders, Andrew's presentation talked about the evolving nature of technology through web 1.0 to web 1.5 and web 2.0 like technologies. After the presentations, they were joined by others in a panel discussion.&lt;br /&gt;&lt;br /&gt;The first question on the tips of participants was 'what was Enterprise 2.0?' This was answered variously as Web 2.0 technologies applied to the enterprise, and enablement of more ad-hoc collaboration to manage content (the 'adhocracy' as Jim put it). Web 2.0 brings to the table technologies like blogs, wiki's, messaging and tagging ('tagonomy' and 'folksonomy' were entered into the lexicon). Other capabilities of Web 2.0 like 'mashups' were also mentioned. These Web 2.0 technologies are user directed evolve in an ad-hoc manner. This differs from older technology enablers that are more directed, such as workflows and taxonomies that are defined by business analysts and direct collaboration.&lt;br /&gt;&lt;br /&gt;My take... So what is E20? E20 is Web 2.0 for the Enterprise. This soundbite will help explain it to curious management.  To technologists, it is using Web 2.0 technologies like wiki's, blogs and mashups evolving in the Internet to web based business applications behind the firewall. For ECM, E20 is the addition of pure web based services and collaboration tools to enable user directed, ad-hoc collaboration and use.&lt;br /&gt;&lt;br /&gt;The next obvious question of the group was 'what does E20 mean to me?' The group varied in their sophistication and technical backgrounds, but a rift became obvious. This rift was pointed out very succinctly by Jim Vaselopulos in his talk. As he defined it, there are 'digital immigrants' and 'digital natives'. Jim looked at the generation gap between those who were born with digital technologies and those who were introduced to it much later. Their sensibilities were different. The 'digital native's' acceptance (and demand) for truly self controlled digital collaboration far exceeded the 'digital immigrant's' desire and tolerance for the same. From a generation's perspective, baby boomer types look at technology as an addition to traditional communication and formality, necessarily organized in hierarchies. From the perspective of the 'millenniums' (born 1980 - present), technology enables 'flat' and immediate collaboration and informality.&lt;br /&gt;&lt;br /&gt;So, from the above distinctions, users may adapt to E20 differently. A pure 'adhocracy' where users have complete freedom to structure information and collaboration may be perceived as a threat to formality of policy and hierarchical organizations. A wiki for instance is controlled by no one. Everyone is a contributor and a consumer. There is no formal structure, there is no formal control. It is subject to the whims of the users. To digital natives (typified by the 20 somethings) this isn't a problem, this is essential. To digital immigrants (the gray hairs), this is an out of control mess. How can you manage important business information this way and expect the information and its structure to just 'evolve?' Playing off of the generation gap isn't fair or accurate, but it does represent the problem in some way.&lt;br /&gt;&lt;br /&gt;The room tended towards the 'gray hairs.' Most in the room came from IT where information management policies were more formal, and information organization existed in well structured taxonomies. For instance, introducing a wiki to manage important business information was looked at suspiciously. 'How do we control it? How do we organize it?' they would ask. Our contingent tended toward the other perspective. To a digital native, this is the very point of a wiki: 'no one controls or manages it and  everyone controls and manages it.' To the digital immigrant, this can only lead to a mess. To the digital native, control and formal organization limit usefulness and frustrate collaboration. To the digital immigrant, this ad-hoc nature would limit usefulness and frustrate collaboration. Clearly, different users have different perspectives.&lt;br /&gt;&lt;br /&gt;In my company, we are wiki happy. Everything goes on the wiki. There are no controls. There is no formal organization. Its organization evolves. The integrity of the information is the responsibility of all. Occasionally, some refactoring has taken place. There is an element of security. Groups of wiki pages are organized into departments. Users within a department are free to contribute. Others may be restricted to viewing. Personal pages remain in control of the author but anyone can read. Inappropriate content would cause some to complain to our tools team. Although this has rarely happened. Organizational structure as evolved. It is still hard to find what you are looking for. Index pages are created occasionally to organize information into loose taxonomies but not as a formal exercise--someone gets tired of hunting for things and creates a page that organizes it.&lt;br /&gt;&lt;br /&gt;For our company, this has worked for most people. But we have also recognized that others are not that comfortable. They have tasked to our internal tools team to reconstitute a more formal intranet. This intranet will be controlled and organized formally. Information will be authored by our tech writers at the direction of the management hierarchy. The very thought of this had caused a furor amongst some in our workforce. Some were vehemently apposed to this 'throwback' to the old. Some who were baffled and dismayed by the by the wild west of the wiki were relieved and fought vigorously for its return.  It was an interesting example of the digital generation divide pointed out so deftly by Jim Vaselopulos. We should use this as an example that there are more viewpoints to serve. Perhaps the lessons learned are that Web 2.0 is not for everyone. Perhaps E20 adds elements of control and formality that businesses need. Perhaps we should take away from this effort that sometimes the wild west needs a sheriff.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-1681879275270447892?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/1681879275270447892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=1681879275270447892' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/1681879275270447892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/1681879275270447892'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/09/enterprise-20.html' title='Enterprise 2.0'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-4061795373630519938</id><published>2008-09-16T06:04:00.000-07:00</published><updated>2008-12-12T17:51:38.200-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ECM SOA'/><category scheme='http://www.blogger.com/atom/ns#' term='ESB'/><category scheme='http://www.blogger.com/atom/ns#' term='ECB'/><category scheme='http://www.blogger.com/atom/ns#' term='Servicemix'/><title type='text'>Enchancing ECM-SOA with Enterprise Content Bus</title><content type='html'>Other capabilities we are looking for in our SOA approach is to leverage an Event Driven Architecture (EDA) focusing on Document Oriented Messages (actually Content Oriented Messages) and the ability to choreograph many content oriented services. This is the job of a message broker, but more specifically an &lt;a href="http://en.wikipedia.org/wiki/Enterprise_service_bus"&gt;Enterprise Service Bus&lt;/a&gt; (ESB).&lt;br /&gt;&lt;br /&gt;We wish to build configurations oriented to choreographing processes for:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Acquisition - acquire content from many sources and many modes (push, pull, scheduled)&lt;/li&gt;&lt;li&gt;Processing - transform, aggregate, index, repurpose, replicate content&lt;/li&gt;&lt;li&gt;Delivery - syndicate or publish in multiple formats over multiple channels&lt;/li&gt;&lt;li&gt;Integration - integrate with other information sources to enrich content&lt;/li&gt;&lt;/ul&gt;We believe to fully allow us to integrate with the rest of the enterprise, we will need the flexibility that an ESB brings to a SOA. It may be helpful to begin by trying to explain what an ESB is (at least from my perspective). To truly leverage a multitude of services distributed throughout the enterprise, we need to choreograph multiple services together in a process flow. These services may need to be accessed differently using REST, SOAP, JMS or FTP.  An ESB centralizes integration and choreography of services and provides many capabilities to talk over multiple channels, route and process messages in many different ways, all mostly through configuration rather than code. Also an ESB can be considered as a container for services &lt;span style="font-style: italic;"&gt;oriented toward integration&lt;/span&gt; such as routing and transformation. An ESB brings shared capabilities like security, transformations, routing, security, transactionality and high-availability so these cross cutting concerns can be applied uniformly and and not have to be custom developed. An ESB is a specialist in integration and choreography. It allows integration logic to move out of each client, service or service container and reside in a &lt;a href="http://servicemix.apache.org/2008/07/03/service-oriented-integration-talk-from-javapolis-2007-posted.html"&gt;Service Oriented Integration&lt;/a&gt; container.&lt;br /&gt;&lt;br /&gt;An example may help. A process flow in this case can be a pathway for content to travel from acquisition, to management, processing, to delivery. Each one of these stages in the content's life-cycle might require integrating with many distributed services. Suppose I am automating the process of acquiring word documents to index and post on an intranet.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;For acquisition, i may want to poll an external ftp drive to see if new content has arrived&lt;/li&gt;&lt;li&gt;For processing, I may want to enrich this content with computed metadata and store it in the content repository for retension&lt;/li&gt;&lt;li&gt;I also I may want to transform this content into a different representation (i.e. word to PDF)&lt;/li&gt;&lt;li&gt;For delivery I may want to deliver this pdf to a website&lt;/li&gt;&lt;li&gt;Further, I want to update an index page to this document&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;One approach is to build this as a customization of a content manager. Most content managers offer a way to ftp content to their content repository. But to 'poll' an ftp site would require custom coding. Once the content is in the repository, a workflow or rules can be triggered that integrates automated actions and human tasks. The first step would be to create a PDF copy. Once a PDF copy is created, a job can be scheduled to index the PDFs as a web page index, and then publish the index and latest PDF files to the site.&lt;br /&gt;&lt;br /&gt;Another approach would be to leverage an ESB. Leveraging an ESB may improve agility of developing these processes. For instance &lt;a href="http://servicemix.apache.org/"&gt;servicemix&lt;/a&gt; has pre-developed and configurable ways to 'poll' and 'send' messages via an ftp channel. One a file is found on the &lt;a href="http://servicemix.apache.org/servicemix-ftp.html"&gt;ftp via polling&lt;/a&gt;, Further using servicemix a route can be configured by using various &lt;a href="http://www.eaipatterns.com/"&gt;Enterprise Integration Pattern&lt;/a&gt; implementations. In this case, a 'pipeline' can be configured to choreograph services: &lt;ol&gt;&lt;li&gt;Store acquired word doc via content service&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Transform word to pdf via transformation service&lt;/li&gt;&lt;li&gt;Store pdf via content service&lt;/li&gt;&lt;li&gt;Generate index invoking a template service&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Finally, the pdf and the index page can be stored to the site's file system via the &lt;a href="http://servicemix.apache.org/servicemix-file.html"&gt;file sender&lt;/a&gt; (another configuration).&lt;br /&gt;&lt;br /&gt;Further benefits exist leveraging an ESB. Each step in this process is made via a &lt;a href="http://www.eecs.harvard.edu/%7Emdw/proj/seda/"&gt;SEDA &lt;/a&gt;architecture  using durable queues. That means that if any of the choreographed services break, take longer than expected or otherwise behave unexpectedly, the process continues unabated. The ESB route can be configured to handle error cases such as a service returning an error result. The processing routes can be  transactional, and roll back all changes if one step changes. The ESB can be clustered to support High Availability, and can be configured to route based on the type of processing. Further, the services choreographed can be accessed over numerous channels: REST (http), ftp, file, jms, jabber,SOAP (http). And modifying the process in many cases requires reconfiguring, not recoding. And the process configurations are not distributed in many services or clients, but centralized on the ESB.&lt;br /&gt;&lt;br /&gt;While there are many ways to choreograph services, an ESB approach may improve agility by leveraging a set of configurable components specialized in integration, orchestration and choreography and that can speak many languages to different distributed systems. The purpose of the ESB is not to take over services from the content manager or other systems but to leverage them. Moving choreography of services to a specialist like an ESB removes the need to create a lot of custom scripting in a content manager which may not be as good at these tasks.&lt;br /&gt;&lt;br /&gt;But existing ESB implementations are focused on choreographing messages, not content. Existing ESBs don't have configurable components around processing of content, and may not do well passing around large content. An ESB needs to be customized to manage content and provide configurable components to enhance content processing. Thus, we are constructing an ECB (Enterprise Content Bus) that builds these content centric capabilities on top of an Enterprise Service Bus.&lt;br /&gt;&lt;br /&gt;Although not mentioned in the example, choreography using enterprise integration patterns provides a lot of flexibility in combining many services, but the addition of &lt;a href="http://en.wikipedia.org/wiki/Business_Process_Management"&gt;Business Process Management&lt;/a&gt; allows these services to be orchestrated according to configurable business processes, and is a great addition to the ESB. Simple processes from acquisition to management to deployment can be implemented via piplelines and wiretaps and content switches. But processing content often requires a business process that integrates invocation of services, integration of systems and human tasks, and provides the visibility into the content processing pipeline. (See following posts on our approach to integrating BPM to our ECB.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The details to follow in the next post...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-4061795373630519938?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/4061795373630519938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=4061795373630519938' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4061795373630519938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4061795373630519938'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/09/enchancing-ecm-soa-with-enterprise.html' title='Enchancing ECM-SOA with Enterprise Content Bus'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-3416794881171588251</id><published>2008-09-16T05:21:00.000-07:00</published><updated>2008-09-21T15:17:38.454-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CMIS'/><category scheme='http://www.blogger.com/atom/ns#' term='ECM SOA'/><title type='text'>ECM SOA standards with CMIS</title><content type='html'>Selecting the 'content services' layer -&lt;br /&gt;&lt;br /&gt;One of the chief complaints has been the lack (or multitude) of multi-vendor standards for ECM that can fit into a SOA architecture. Recently, EMC, IBM and Microsoft have announced a new standard: &lt;a href="https://community.emc.com/community/labs/cmis"&gt;CMIS&lt;/a&gt; that intends to address this. This standard will be submitted to &lt;a href="http://xml.coverpages.org/ni2008-09-10-a.html"&gt;OASIS&lt;/a&gt; for further work. In the mean time, several vendors such as &lt;a href="http://www.alfresco.com/"&gt;Alfresco&lt;/a&gt; Oracle and others are developing implementations of this standard.&lt;br /&gt;&lt;br /&gt;In my &lt;a href="http://edlovesjava.blogspot.com/2008/09/ecm-soa-with-agile-attitude.html"&gt;previous post&lt;/a&gt;, I described the components I thought were needed to support a fully functional SOA approach to ECM. Included was an item 'content services'. I believe that this standard fits well into this category. Other 'standards' also exist that we have used:&lt;br /&gt;* &lt;a href="http://www.webdav.org/"&gt;WebDAV&lt;/a&gt; offers simple access to content and metadata over http.&lt;br /&gt;* &lt;a href="http://jcp.org/en/jsr/detail?id=170"&gt;JSR 170&lt;/a&gt; offers more sophisticated content model access for Java based clients.&lt;br /&gt;&lt;br /&gt;Typically writing content aware applications involves customizing a proprietary content manager application using proprietary APIs and possibly scripting languages. If one is brave enough to attempt to develop an independent application that needs to integrate to a content repository (as we have been), only proprietary API's exist that lock the application into that vendor's content manager.  Alternatively, most vendors support some level of WebDAV. So it is possible to develop a content aware application leveraging WebDAV, but different vendors support WebDAV to different levels of compliance. Also since there is no typing model, enforcing a content model standard is difficult. To overcome this in the past, we have developed a WebDAV client that adds typing capability. This effort drove us to look seriously at using JCR (JSR 170). Using JSR 170 means implementing a session based approach and, of course, locks you into Java.  But it does offer rich content model semantics. However, its session based, its Java centric nature and its lack of support RESTful or SOAP channels makes it a poor choice for a SOA.&lt;br /&gt;&lt;br /&gt;Since CMIS offers a stronger type model and can be developed in SOA friendly SOAP or RESTful manner, it seems it has the right stuff for a standard 'content services' layer to access the Content Repository. However, we need to leverage what exists now in our approach. Since we are a Java shop and will be leveraging one content vendor, JSR 170 still seems the best approach. For RESTful access strongly suggested at our organization, WebDAV may provide a stop gap. We will likely follow CMIS closely and prototype with it.&lt;br /&gt;&lt;br /&gt;Next post, a discussion of the Enterprise Content Bus...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-3416794881171588251?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/3416794881171588251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=3416794881171588251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/3416794881171588251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/3416794881171588251'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/09/ecm-soa-standards-with-cmis.html' title='ECM SOA standards with CMIS'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-2722701958738142967</id><published>2008-09-08T06:13:00.000-07:00</published><updated>2008-09-21T15:18:08.245-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ECM SOA'/><title type='text'>ECM-SOA with an Agile Attitude</title><content type='html'>In this entry, I will identify the attitudes and concepts that define our ECM-SOA vision. Next entries, I will dive into the technical selections and customizations.&lt;br /&gt;&lt;br /&gt;The first challenge is to think of our tooling as not a custom application, but more as a set of adaptable services, applications and integrations. This requires a change of thought. Our previous efforts were to drop a monolithic application called a Content Manager into the middle of things, and then propose to change the business process around this application, ostensibly obsoleting the existing applications and ad-hoc processing to customizations within this new application.&lt;br /&gt;&lt;br /&gt;During our previous attempt, we underwent a lengthy analysis phase and generated a 500 page requirements document detailing taxonomies, content types, work flows and templates that would solve our content management (web content management) needs. We then spent lots of time and treasure implementing these requirements. In the end, we built some of the requirements taking far longer and far more resources than anticipated, and we found that most the requirements and subsequently most of the customizations we built were wrong.   The heroic content managers and brand managers made it work anyway, developing more ad-hoc, complicated and time consuming steps around yet another application that was supposed to help them. This story is not unique.&lt;br /&gt;&lt;br /&gt;We must shift our processes as much as our technology. We are focusing on smaller efforts, more agility and more feedback and move away from 500 page requirements documents. To do this successfully, our architecture also needs to be agile and amenable to change. Our architecture must be a framework to grow on: to grow useful services, and to grow and integrate with useful applications. It must follow user demand that learns from using and refining our processes and tools.&lt;br /&gt;&lt;br /&gt;At the core of our architecture is the Content Repository. This tool will store content through various stages of use. It must have versioning capability, search capability, auditing capability, it must provide a flexible capability to organize content into collections, and it must provide flexible meta data structures that can apply both simple and hierarchical views of content cross cutting storage structure.&lt;br /&gt;&lt;br /&gt;On this repository, we must define a content model that is flexible and extensible. But the cost of changing and refining storage and meta-data structure must be tolerable. Our definitions must be incremental, careful not to lock ourselves into bad organization and not to anticipate too far in the future. Changes to the content model are always the must costly and must be considered with greater care. The analogy is to a database. Many applications can use the database, and it can store and retrieve a lot of information, but defining and changing its structure must be done with care. Eventually, all content must be converted and stored in the repository in order to maximally leverage the content throughout the organization.&lt;br /&gt;&lt;br /&gt;On top of the Content Repository are a set of content services. These services allow applications to be quickly developed and adopted that leverage content and content features. These content services should be developed by leveraging standards including JSR 170 and WebDAV to make them accessible to existing and future application needs. Typically, a Content Manager user interface comes with the content repository that provides a clear view and access to the content. This application can be customized and with enough effort it can host all application needs, but we are weary of this monolithic approach. Current applications exist that may be more suited to business needs. They must be adapted at least to leverage a common repository by using these content services. But they will continue to supply unique views and functions. Later, application integration through the use of portalization may help to alleviate the chaos of multiple applications and views.&lt;br /&gt;&lt;br /&gt;Accepting that content exists in many places and is required by many applications, we look to the concept of an Enterprise Service Bus. We will have many integrations to other applications, and content must be acquired, processed, and delivered in unique ways. An ESB allows the centralization of this integration and processing, reducing coupling to the rest of the organization and potentially increasing agility by being more adaptable to change. However, the concept of the ESB focuses on messaging, not content. We will adapt this to provide content processing capabilities and tag it as an Enterprise Content Bus (ECB). This ECB concept will evolve over time and will be detailed here over many posts.&lt;br /&gt;&lt;br /&gt;Finally, choreographing acquisition, processing and delivery of content becomes a challenge. Both automated and manual steps must be organized into business processes that adapt and grow over time. Over engineering the business process can be just as damaging as not managing it at all. The content architecture must support a Business Process Management (BPM) applicaiton capable of orchestrating both manual and automated steps. It must be integrated well with the content management application and repository, and the Enterprise Content Bus (ECB). The use of configurable Business Rules Engine (BRE) will help define controls through the steps, enforcing standards, validating processing and ensuring high quality. This capability will allow content management to grow in a managed way over time, in a fully exposed and auditable way.&lt;br /&gt;&lt;br /&gt;This architecture is a suite of application cababilities, each highly adaptable and customizable.&lt;br /&gt;&lt;br /&gt;To sum up:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;span style="font-weight: bold;"&gt;Content Repository&lt;/span&gt; stores all content applying standard features&lt;/li&gt;&lt;li&gt;The &lt;span style="font-weight: bold;"&gt;Content Model&lt;/span&gt; enforces standards and increases usefulness across usages&lt;/li&gt;&lt;li&gt;The &lt;span style="font-weight: bold;"&gt;Content Service&lt;/span&gt;s allows access to the content reposisotry by manay applications&lt;/li&gt;&lt;li&gt;The &lt;span style="font-weight: bold;"&gt;Content Manager&lt;/span&gt; provides a user interface to manage content&lt;/li&gt;&lt;li&gt;The &lt;span style="font-weight: bold;"&gt;Enterprise Content Bus (ECB) &lt;/span&gt;allows content to be acquired, processed and delivered&lt;/li&gt;&lt;li&gt;The &lt;span style="font-weight: bold;"&gt;Business Process Management (BPM)&lt;/span&gt; frawork allows processing to be orchestrated&lt;/li&gt;&lt;li&gt;The &lt;span style="font-weight: bold;"&gt;Business Rules Engine (BRE)&lt;/span&gt; inforces consistency and quality throughout processing&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt; This is our ECM-SOA vision. How do we implement it? The next posts will tell..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-2722701958738142967?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/2722701958738142967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=2722701958738142967' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/2722701958738142967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/2722701958738142967'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/09/ecm-soa-with-agile-attitude.html' title='ECM-SOA with an Agile Attitude'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-4875437504167559821</id><published>2008-09-04T20:06:00.001-07:00</published><updated>2008-09-21T15:18:49.991-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ECM SOA'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Enterprise 2.0'/><title type='text'>The answer is ECM-SOA</title><content type='html'>Of course the answer (to the &lt;a href="http://edlovesjava.blogspot.com/2008/09/ecm-soa-strategy.html"&gt;previous post's concerns&lt;/a&gt;) is to try and leverage a Service Oriented Architecture as part of the ECM strategy. So that starts me on my way.&lt;br /&gt;&lt;br /&gt;In order to understand my approach, let me share with you some articles and books that have guided me.&lt;br /&gt;&lt;br /&gt;Some articles of interest focusing on ECM-SOA:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.aiim.org/Edoc/ArticleView.aspx?ID=34791"&gt;ECM SOA Article in AIIM&lt;/a&gt; talks about SOA for ECM in context of Web 2.0 (or Enterprise 2.0 if you will), but still useful&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.aiim.org/Edoc/ArticleView.aspx?ID=34791"&gt;Integrated Solutions Magazine's ECM SOA&lt;/a&gt; article has some data to help support the business case&lt;/li&gt;&lt;li&gt;Since ECM SOA is discussed in context with Web 2.0 (or Enterprise 2.0) I downloaded a &lt;a href="http://www.aiim.org/ResourceCenter/Research/MarketIQ/Article.aspx?ID=34464"&gt;good overview of Enterprise 2.0&lt;/a&gt; to keep up with the buzz&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;But more specifically, my guidance has been more general SOA/Web Services books and guides. is on what SOA is/isn't has been influenced by these books:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Understanding-Services-Independent-Technology-Guides/dp/0321180860/ref=sr_1_20?ie=UTF8&amp;amp;s=books&amp;amp;qid=1220614755&amp;amp;sr=1-20"&gt;Eric Newcommer's classic Understanding SOA with Web Services&lt;/a&gt; is not only informative, but a good read&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823/ref=pd_bbs_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1220614946&amp;amp;sr=1-1"&gt;Thomas Erl's SOA Principles of Service Design&lt;/a&gt; is the classic, but I didn't get as much out of it as I would have liked&lt;/li&gt;&lt;li&gt;Specifically, I've been interested in Web Services, REST, Enterprise Service Bus and BPM aspects&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823/ref=pd_bbs_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1220614946&amp;amp;sr=1-1"&gt;RESTFul Web Services&lt;/a&gt; from O'reilly is very good&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Enterprise-Service-Bus-David-Chappell/dp/0596006756/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1220615202&amp;amp;sr=1-1"&gt;Enterprise Service Bus by Chapell&lt;/a&gt; was our bible for a while in 2004-2006 and may be a bit dated now&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Enterprise-Integration-Patterns-Designing-Addison-Wesley/dp/0321200683/ref=pd_bbs_sr_2_s9_rk?ie=UTF8&amp;amp;s=books&amp;amp;s9r=8a02b541179b7cc00117ae53e53f0394&amp;amp;itemPosition=2&amp;amp;qid=1220615202&amp;amp;sr=1-2"&gt;Enterprise Integration Patterns from Martin Fowler's series&lt;/a&gt; is exceptional and essential to our work&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Essential-Business-Process-Modeling-Michael/dp/0596008430/ref=sr_1_13?ie=UTF8&amp;amp;s=books&amp;amp;qid=1220615477&amp;amp;sr=1-13"&gt;I found Essential Business Process Modeling&lt;/a&gt; very informative theory oriented. For practical use, i just gleaned from implementation approaches on the web (i.e. &lt;a href="http://www.jboss.com/products/jbpm"&gt;JBoss' jBPM&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;So what is the scope of our work?&lt;br /&gt;&lt;br /&gt;The part of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;ECM&lt;/span&gt; we are building now is focused on Web Content Management. We have a common platform on which we can configure, skin and run many travel sites. We are a global company, and our sites must support many languages. The platform must host many brands so each site must be able to be skinned, configured and customized as if it was purpose built.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A key challenge for this is managing web content in multiple languages and for multiple brands. Each type of content we publish to the site needs to be translated to local languages and adapted to fit the brands. Each type of content is currently managed in unique applications, processed with a &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;cadre&lt;/span&gt; of custom code and delivered in unique formats. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With all of this custom code, storage and formats, it is difficult to create functions that extend to many types of content, such as those to handle translation and branding. Our challenge is to unify content management and extend our capabilities to efficiently stand up new brands and languages without sinking the content managers and brand managers in a mire of complex, ad-hoc tools, technologies and practices. So our rally cry is "Stand up a new site in 1 day! (any language, any brand)." At least the tools shouldn't be a bottleneck!&lt;br /&gt;&lt;br /&gt;Next, our vision...&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-4875437504167559821?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/4875437504167559821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=4875437504167559821' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4875437504167559821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/4875437504167559821'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/09/answer-is-ecm-soa.html' title='The answer is ECM-SOA'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7203181491808683266.post-6560737166210756597</id><published>2008-09-03T06:01:00.000-07:00</published><updated>2008-09-21T15:19:12.740-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ECM SOA'/><title type='text'>ECM SOA Strategy</title><content type='html'>I am attempting to build a ECM-SOA strategy at my company. This blog will identify key issues we have run across and the solutions we are attempting. I will get very technical since I am the primary technologist for content technologies at my company, but I will also maintain a higher level focus on the business aspects of this initiative, since the two are inextricably tied together.&lt;br /&gt;&lt;br /&gt;At my company, we have many applications that manipulate content, both for site management and for document management. Each application was built as a silo, unique technology to suit a unique job -- no sharing, no reuse. This is typical for many companies, whether content management applications or other types of applications. Service oriented architectures (SOA) try to address this issue by placing a service layer between applications that consume services and service provider applications, allowing many applications to leverage shared services. Implementing this forces the organization to think about standards and common facilities.&lt;br /&gt;&lt;br /&gt;Enterprise Content Management (ECM) is a term referring to a strategy to manage content across the enterprise in a common way, leveraging common facilities. ECM covers types of content applications including Web Content Management (WCM), Document Management (DM), Records Management (DM), Digital Asset Management (DAM) and others. Companies like mine typically have all of these needs. And we have applications that address these needs, but, like many companies, they are composed of unique purpose built applications with no overarching strategy or technology. Also vast holes exist in this application web that necessitate ad-hoc approaches and manual intervention, costing in labor and quality. This silo approach is costly and limiting.&lt;br /&gt;&lt;br /&gt;Vendors attempt to address this need by selling monolithic systems that replace these many purpose built applications with customizations and tailoring of their product. Aggressive implementations of these systems force the organization to change and adapt in order to be successful. Failure typically happens because the organization is unable or unwilling to make these changes, and the customization efforts of these products is vastly underestimated. Much is promised by these solutions, but little is delivered. Sometimes millions of dollars of 'shelfware' or hobbled and cobbled systems limp along adding little and causing frustration and empathy. This is nothing unique to ECM: try CRM, ERP and others. Consultants love them. Companies hate them. We can do better.&lt;br /&gt;&lt;br /&gt;My approach is to be more evolutionary. We cannot rip out the many processes and programs that make up a web of content management. They work (more or less), and they focus on solving specific problems. There is a lot of knowledge embedded in each application. There is a lot invested in them: both mindshare and monentary. But change is forcing us to change. We have to improve our efficiency at the same time we expand to a global presence. We have to adapt our management systems to serve our new global platforms. In particular, site content management (Web Content Management and Digital Asset Management) must improve or we will sink under the weight of all the content management needs. In short, we have to change everything to realize our vision. But how can we be evolutionary and still change everything?&lt;br /&gt;&lt;br /&gt;I'll leave with this cliff hanger for now...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7203181491808683266-6560737166210756597?l=edlovesjava.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://edlovesjava.blogspot.com/feeds/6560737166210756597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7203181491808683266&amp;postID=6560737166210756597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6560737166210756597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7203181491808683266/posts/default/6560737166210756597'/><link rel='alternate' type='text/html' href='http://edlovesjava.blogspot.com/2008/09/ecm-soa-strategy.html' title='ECM SOA Strategy'/><author><name>edlovesjava</name><uri>http://www.blogger.com/profile/07515369822547982127</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://1.bp.blogspot.com/_QVQz3EsVFfA/STmoCSG0w7I/AAAAAAAAABQ/ed95jf-7V1w/S220/Picture+18.jpg'/></author><thr:total>0</thr:total></entry></feed>
