<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Nuxeo Developers Blog</title>
	<atom:link href="http://dev.blogs.nuxeo.com/feed" rel="self" type="application/rss+xml" />
	<link>http://dev.blogs.nuxeo.com</link>
	<description>News from the Open Source ECM trenches</description>
	<lastBuildDate>Mon, 21 May 2012 12:56:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>[Monday Dev Heaven] Add a Forgotten Password Functionality to Nuxeo, Part 2/2</title>
		<link>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-22.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-22.html#comments</comments>
		<pubDate>Mon, 21 May 2012 12:20:43 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Marketplace]]></category>
		<category><![CDATA[Monday Dev Heaven]]></category>
		<category><![CDATA[Nuxeo]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4495</guid>
		<description><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/05/localPackage.png"><img class="alignright size-medium wp-image-4496" src="http://dev.blogs.nuxeo.com/files/2012/05/localPackage-300x66.png" alt="A Local package description" width="300" height="66" /></a></p>
<p>Last week I wrote the first part of a two blog post series on <a title="[Monday Dev Heaven] Add a Forgotten Password Functionality to Nuxeo, Part 1/2" href="http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-12.html">how to add a Forgotten Password Functionality to Nuxeo</a>. So make sure you read the first one and here comes the second part :-)</p>
<h2>Reset the password</h2>
<p>The link we send to the user (see first blog post) will be manage by the <em>enterNewPassword</em> method. The key is part of the URL so it&#8217;s easy to retrieve using JAX-RS annotations. Once I have the key, I use the <em>SearchRegistrationByResetPassKeyUnrestricted</em> runner to verify that it&#8217;s still a valid key. If it is, I can render the <em>submitNewPassword</em> template. If not, I render the <em>wrongResetKey</em> template.</p>
<pre class="brush: java; title: ; notranslate">
    @GET
    @Path(&#34;enterNewPassword/{key}&#34;)
    @Produces(&#34;text/html&#34;)
    public Object enterNewPassword(@PathParam(&#34;key&#34;) String key)
            throws ClientException {
        SearchRegistrationByResetPassKeyUnrestricted runner = new SearchRegistrationByResetPassKeyUnrestricted(
                getDefaultRepositoryName(), key);
        runner.runUnrestricted();

        String errorMessage = runner.getErrorMessage();
        if (errorMessage != null) {
            return getView(&#34;wrongResetKey&#34;);
        } else {
            Map&#60;String, String&#62; data = new HashMap&#60;String, String&#62;();
            return &#8230; <a href="http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-22.html" class="read_more">Read more</a></pre>]]></description>
			<content:encoded><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/05/localPackage.png"><img class="alignright size-medium wp-image-4496" src="http://dev.blogs.nuxeo.com/files/2012/05/localPackage-300x66.png" alt="A Local package description" width="300" height="66" /></a></p>
<p>Last week I wrote the first part of a two blog post series on <a title="[Monday Dev Heaven] Add a Forgotten Password Functionality to Nuxeo, Part 1/2" href="http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-12.html">how to add a Forgotten Password Functionality to Nuxeo</a>. So make sure you read the first one and here comes the second part :-)</p>
<h2>Reset the password</h2>
<p>The link we send to the user (see first blog post) will be manage by the <em>enterNewPassword</em> method. The key is part of the URL so it&#8217;s easy to retrieve using JAX-RS annotations. Once I have the key, I use the <em>SearchRegistrationByResetPassKeyUnrestricted</em> runner to verify that it&#8217;s still a valid key. If it is, I can render the <em>submitNewPassword</em> template. If not, I render the <em>wrongResetKey</em> template.</p>
<pre class="brush: java; title: ; notranslate">
    @GET
    @Path(&quot;enterNewPassword/{key}&quot;)
    @Produces(&quot;text/html&quot;)
    public Object enterNewPassword(@PathParam(&quot;key&quot;) String key)
            throws ClientException {
        SearchRegistrationByResetPassKeyUnrestricted runner = new SearchRegistrationByResetPassKeyUnrestricted(
                getDefaultRepositoryName(), key);
        runner.runUnrestricted();

        String errorMessage = runner.getErrorMessage();
        if (errorMessage != null) {
            return getView(&quot;wrongResetKey&quot;);
        } else {
            Map&lt;String, String&gt; data = new HashMap&lt;String, String&gt;();
            return getView(&quot;submitNewPassword&quot;).arg(&quot;key&quot;, key).arg(&quot;data&quot;,
                    data);
        }
    }

    @POST
    @Path(&quot;submitNewPassword&quot;)
    @Produces(&quot;text/html&quot;)
    public Object submitNewPassword() throws ClientException,
            URISyntaxException {
        FormData formData = getContext().getForm();
        String passwordKey = formData.getString(&quot;PasswordKey&quot;);
        String password = formData.getString(&quot;Password&quot;);
        String passwordConfirmation = formData.getString(&quot;PasswordConfirmation&quot;);
        if (password == null || &quot;&quot;.equals(password.trim())) {
            return redisplayFormWithErrorMessage(&quot;submitNewPassword&quot;,
                    ctx.getMessage(&quot;label.registerForm.validation.password&quot;),
                    formData);
        }
        if (passwordConfirmation == null
                || &quot;&quot;.equals(passwordConfirmation.trim())) {
            return redisplayFormWithErrorMessage(
                    &quot;submitNewPassword&quot;,
                    ctx.getMessage(&quot;label.registerForm.validation.passwordconfirmation&quot;),
                    formData);
        }
        password = password.trim();
        passwordConfirmation = passwordConfirmation.trim();
        if (!password.equals(passwordConfirmation)) {
            return redisplayFormWithErrorMessage(
                    &quot;submitNewPassword&quot;,
                    ctx.getMessage(&quot;label.registerForm.validation.passwordvalidation&quot;),
                    formData);
        }

        SetNewPasswordUnrestricted runner = new SetNewPasswordUnrestricted(
                getDefaultRepositoryName(), password, passwordKey);
        runner.runUnrestricted();
        Response response = runner.getResponse();
        if (response != null) {
            return response;
        }
        String errorMessage = runner.getErrorMessage();
        if (errorMessage != null) {
            return redisplayFormWithErrorMessage(&quot;submitNewPassword&quot;,
                    ctx.getMessage(errorMessage), formData).arg(&quot;key&quot;,
                    passwordKey);
        } else {
            return redisplayFormWithInfoMessage(&quot;submitNewPassword&quot;,
                    ctx.getMessage(&quot;label.submitNewPassword.saved&quot;), formData).arg(
                    &quot;key&quot;, passwordKey);
        }
    }
</pre>
<p>The form submitted from <em>submitNewPassword</em> is handled by the <em>submitNewPassword</em> method of my WebEngine module. As we did previously for the email, the form validation is run on the server side. I&#8217;m just ensuring that the passwords are not empty and identical. If the password is OK, we can jump to the <em>SetNewPasswordUnrestricted</em> runner. The goal of this runner is to check again if the key is still valid, and if true, change the password using the UserManager.</p>
<p>And that&#8217;s it, now we have a working forgotten password module. There is, of course, still room for improvements, but I feel like I can use it. So I&#8217;m going to show you how to package it for the Nuxeo Marketplace.</p>
<h2>Create the Marketplace package</h2>
<p>My final package is a simple zip containing only three files.<br />
- /install/bundles/nuxeo-userpassword-reset-5.5.jar, that contains the code of my module.<br />
- /install.xml, containing the installation instructions<br />
- /package.xml, containing my package metadata.</p>
<p>Our install file will be really simple, since all we have to do is copy the jar in the nxserver/bundles folder. The following code copies the content of the folder install/bundles of my package into the bundles folder of the server. You can read more about those scripting commands in <a href="http://doc.nuxeo.com/x/OIGe" title="Scripting commands">our wiki</a>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;install&gt;
  &lt;update file=&quot;${package.root}/install/bundles&quot; todir=&quot;${env.bundles}&quot; /&gt;
&lt;/install&gt;
</pre>
<p>The package file has a lot more tags since it contains all its metadata. Most of them will be displayed in the update center. I let you read them, they&#8217;re self-explanatory. And you can read all the details in our <a href="http://doc.nuxeo.com/x/N4Ge" title="Creating Packages for the Marketplace">documentation</a>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;package type=&quot;addon&quot; name=&quot;nuxeo-userpassword-reset&quot; version=&quot;5.5&quot;&gt;
  &lt;title&gt;Nuxeo Platform User Password Reset&lt;/title&gt;
  &lt;description&gt;
    &lt;p&gt;Nuxeo Platform User Password Reset adds a forgotten password link to Nuxeo's home page. The user clicks on the link and fill in his email address. He will receive an email shortly after with a one-day valid link. This link gets him to a simple form to reset his forgotten password.&lt;/p&gt;
  &lt;/description&gt;
  &lt;home-page&gt;https://github.com/ldoguin/nuxeo-userpassword-reset&lt;/home-page&gt;
  &lt;vendor&gt;Nuxeo&lt;/vendor&gt;
  &lt;installer restart=&quot;true&quot; /&gt;
  &lt;uninstaller restart=&quot;true&quot; /&gt;
  &lt;hotreload-support&gt;false&lt;/hotreload-support&gt;
  &lt;nuxeo-validation&gt;nuxeo_certified&lt;/nuxeo-validation&gt;
  &lt;production-state&gt;testing&lt;/production-state&gt;
  &lt;supported&gt;true&lt;/supported&gt;
  &lt;platforms&gt;
    &lt;platform&gt;cap-5.5&lt;/platform&gt;
  &lt;/platforms&gt;
  &lt;license&gt;LGPL&lt;/license&gt;
  &lt;license-url&gt;http://www.gnu.org/licenses/lgpl.html&lt;/license-url&gt;
&lt;/package&gt;
</pre>
<p>We can build this zip file easily using Maven and nuxeo-distribution assembly. All we have to do is zip three files so it should be easy :) This is basically a set of ant tasks. You can read the comments to understand what each task does:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;project name=&quot;nuxeo-assembly&quot;
         default=&quot;build&quot;
         xmlns:nx=&quot;urn:nuxeo-build&quot;
         xmlns:artifact=&quot;urn:nuxeo-artifact&quot;&gt;
  &lt;taskdef resource=&quot;org/nuxeo/build/antlib.xml&quot; uri=&quot;urn:nuxeo-build&quot; /&gt;
  &lt;taskdef resource=&quot;org/nuxeo/build/artifact/antlib.xml&quot;
           uri=&quot;urn:nuxeo-artifact&quot; /&gt;

  &lt;target name=&quot;build&quot; description=&quot;Build Nuxeo Platform User Password Reset Marketplace package&quot;&gt;
    &lt;tstamp /&gt;
    &lt;!-- delete previous working directory --&gt;
    &lt;delete failonerror=&quot;false&quot;
            dir=&quot;${maven.project.build.directory}/marketplace&quot; /&gt;
    &lt;!-- create working directory --&gt;
    &lt;mkdir dir=&quot;${maven.project.build.directory}/marketplace&quot; /&gt;
    &lt;!-- copy install.xml and package.xml --&gt;
    &lt;copy todir=&quot;${maven.project.build.directory}/marketplace&quot;&gt;
      &lt;fileset dir=&quot;src/main/resources&quot; /&gt;
      &lt;filterset&gt;
        &lt;filter token=&quot;VERSION&quot; value=&quot;${maven.project.version}&quot; /&gt;
      &lt;/filterset&gt;
    &lt;/copy&gt;
     &lt;!-- copy nuxeo-userpassword-reset jar in /install/bundles folder.--&gt;
    &lt;copy todir=&quot;${maven.project.build.directory}/marketplace/install/bundles&quot;&gt;
      &lt;artifact:resolveFile key=&quot;org.nuxeo.ecm.platform:nuxeo-userpassword-reset::jar&quot; /&gt;
    &lt;/copy&gt;
    &lt;!-- zip the working directory to ${maven.project.artifactId}-${maven.project.version}.zip --&gt;
    &lt;zip destfile=&quot;${maven.project.build.directory}/${maven.project.artifactId}-${maven.project.version}.zip&quot;
         basedir=&quot;${maven.project.build.directory}/marketplace&quot; /&gt;
    &lt;artifact:attach file=&quot;${maven.project.build.directory}/${maven.project.artifactId}-${maven.project.version}.zip&quot;
                     target=&quot;${maven.project.groupId}:${maven.project.artifactId}&quot;
                     type=&quot;zip&quot; /&gt;
  &lt;/target&gt;

&lt;/project&gt;
</pre>
<p>This assembly file is processed by a <em>nuxeo-distribution-tools</em> Maven plugin. You can find the related documentation <a href="http://doc.nuxeo.com/x/BIAO" title="Creating your own distribution">here</a>.</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;build&gt;
    &lt;plugins&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.nuxeo.build&lt;/groupId&gt;
        &lt;artifactId&gt;nuxeo-distribution-tools&lt;/artifactId&gt;
        &lt;configuration&gt;
          &lt;buildFiles&gt;
            &lt;buildFile&gt;${basedir}/src/main/assemble/assembly.xml&lt;/buildFile&gt;
          &lt;/buildFiles&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
    &lt;/plugins&gt;
  &lt;/build&gt;
</pre>
<p>So if you type <em>mvn install</em>, you will have your Marketplace package in the target folder. As you can see, creating a simple marketplace package doesn&#8217;t require too much efforts :-)</p>
<p>I&#8217;ve added the source code on <a title="nuxeo-userpassword-reset on Github" href="https://github.com/ldoguin/nuxeo-userpassword-reset">Github</a>. Let me know if you have any questions through the comments or on <a title="Nuxeo Answers" href="http://answers.nuxeo.com">answers.nuxeo.com</a>. See ya&#8217; on Friday!</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-22.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Q&amp;A Friday] How do I import a document in Nuxeo with version 12 as initial version?</title>
		<link>http://dev.blogs.nuxeo.com/2012/05/qa-friday-import-document-put-nuxeo-version-12-initial-version.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/05/qa-friday-import-document-put-nuxeo-version-12-initial-version.html#comments</comments>
		<pubDate>Fri, 18 May 2012 11:31:36 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Friday Q&A]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4497</guid>
		<description><![CDATA[<div id="attachment_4385" class="wp-caption alignright" style="width: 167px"><a href="http://dev.blogs.nuxeo.com/files/2012/02/question.png"><img class="size-full wp-image-4385" src="http://dev.blogs.nuxeo.com/files/2012/02/question.png" alt="How to import a document and put it in Nuxeo in version 12 as initial version?" width="157" height="123" /></a><p class="wp-caption-text">How do I import a document in Nuxeo with version 12 as initial version?</p></div>
<p>Today we have a question from <a title="Maxr on Nuxeo Answers" href="http://answers.nuxeo.com/users/330/maxr/">maxr</a> who asks <a title="How to import a document and put it in Nuxeo in version 12 as initial version?" href="http://answers.nuxeo.com/questions/2654/how-to-import-a-document-and-put-it-in-nuxeo-in-version-12-as-initial-version">how to import a document and put it in Nuxeo with version 12 as the initial version</a>.</p>
<p>There are different options for this. The easiest one is to setup a custom <a title="Versioning rule on Nuxeo Explorer" href="http://explorer.nuxeo.org/nuxeo/site/distribution/Nuxeo%20DM-5.5/viewExtensionPoint/org.nuxeo.ecm.core.versioning.VersioningService--versioningRules"><em>versioning rule</em></a> during the import.</p>
<p>Every document created at that time will be in version 12.0. Just remove the import-versioning-contrib.xml once the import is done. This will only work if you do a one-shot import and nobody creates new documents during the import.</p>
<p>All you need to do is deploy an import-versioning-contrib.xml file containing for instance the following code:</p>
<pre class="brush: xml; title: ; notranslate">
  &#60;?xml version=&#34;1.0&#34;?&#62;
   &#60;component name=&#34;org.nuxeo.ecm.platform.versionoverride&#34; version=&#34;1.0&#34;&#62;
     &#60;extension target=&#34;org.nuxeo.ecm.core.versioning.VersioningService&#34; point=&#34;versioningRules&#34;&#62;
       &#60;defaultVersioningRule&#62;
         &#60;initialState major=&#34;12&#34; minor=&#34;0&#34; /&#62;
        &#60;/defaultVersioningRule&#62;
      &#60;/extension&#62;
   &#60;/component&#62;
</pre>
<p>Now let&#8217;s say my import is done continuously. Every five minutes, the importer looks into a specific folder on a &#8230; <a href="http://dev.blogs.nuxeo.com/2012/05/qa-friday-import-document-put-nuxeo-version-12-initial-version.html" class="read_more">Read more</a></p>]]></description>
			<content:encoded><![CDATA[<div id="attachment_4385" class="wp-caption alignright" style="width: 167px"><a href="http://dev.blogs.nuxeo.com/files/2012/02/question.png"><img class="size-full wp-image-4385" src="http://dev.blogs.nuxeo.com/files/2012/02/question.png" alt="How to import a document and put it in Nuxeo in version 12 as initial version?" width="157" height="123" /></a><p class="wp-caption-text">How do I import a document in Nuxeo with version 12 as initial version?</p></div>
<p>Today we have a question from <a title="Maxr on Nuxeo Answers" href="http://answers.nuxeo.com/users/330/maxr/">maxr</a> who asks <a title="How to import a document and put it in Nuxeo in version 12 as initial version?" href="http://answers.nuxeo.com/questions/2654/how-to-import-a-document-and-put-it-in-nuxeo-in-version-12-as-initial-version">how to import a document and put it in Nuxeo with version 12 as the initial version</a>.</p>
<p>There are different options for this. The easiest one is to setup a custom <a title="Versioning rule on Nuxeo Explorer" href="http://explorer.nuxeo.org/nuxeo/site/distribution/Nuxeo%20DM-5.5/viewExtensionPoint/org.nuxeo.ecm.core.versioning.VersioningService--versioningRules"><em>versioning rule</em></a> during the import.</p>
<p>Every document created at that time will be in version 12.0. Just remove the import-versioning-contrib.xml once the import is done. This will only work if you do a one-shot import and nobody creates new documents during the import.</p>
<p>All you need to do is deploy an import-versioning-contrib.xml file containing for instance the following code:</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;?xml version=&quot;1.0&quot;?&gt;
   &lt;component name=&quot;org.nuxeo.ecm.platform.versionoverride&quot; version=&quot;1.0&quot;&gt;
     &lt;extension target=&quot;org.nuxeo.ecm.core.versioning.VersioningService&quot; point=&quot;versioningRules&quot;&gt;
       &lt;defaultVersioningRule&gt;
         &lt;initialState major=&quot;12&quot; minor=&quot;0&quot; /&gt;
        &lt;/defaultVersioningRule&gt;
      &lt;/extension&gt;
   &lt;/component&gt;
</pre>
<p>Now let&#8217;s say my import is done continuously. Every five minutes, the importer looks into a specific folder on a server and if it finds a file, it imports it. Our previous solution won&#8217;t work. We have to override the <em><a title="VersioningService Javadoc" href="http://community.nuxeo.com/api/nuxeo/5.5/javadoc/index.html?org/nuxeo/ecm/core/versioning/VersioningService.html">VersioningService</a></em>. Don&#8217;t worry, it doesn&#8217;t hurt. I did a small project to showcase this. </p>
<p>Starting with a simple unit test to make sure we&#8217;re on the right track:</p>
<pre class="brush: java; title: ; notranslate">
public class TestImportDocCreation extends SQLRepositoryTestCase {

	@Override
	public void setUp() throws Exception {
		super.setUp();
		deployBundle(&quot;custom-versioningservice&quot;);
		openSession();
	}

	public void testDocumentCreation() throws Exception {
		DocumentModel doc = session.createDocumentModel(&quot;/&quot;, &quot;test&quot;, &quot;File&quot;);
		doc.putContextData(&quot;comesFromImport&quot;, true);
		doc = session.createDocument(doc);
		assertEquals(&quot;12.0+&quot;, doc.getVersionLabel());
		doc = session.createDocumentModel(&quot;/&quot;, &quot;test2&quot;, &quot;File&quot;);
		doc = session.createDocument(doc);
		assertEquals(&quot;0.0&quot;, doc.getVersionLabel());
	}

	@Override
	public void tearDown() throws Exception {
		super.tearDown();
		closeSession();
	}
}
</pre>
<p>As you can see we have to put the <em>comesFromImport</em> boolean in the contextMap. This means we&#8217;ll have to do this in the code of your importer. </p>
<p>The first thing to do as usual is to run the Nuxeo Plugin project wizard in Nuxeo IDE. We need to contribute a new <em>VersioningService</em> so we need a new class. Here&#8217;s the code:</p>
<pre class="brush: java; title: ; notranslate">
package org.nuxeo.sample.versioning;

import java.io.Serializable;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.core.api.DocumentException;
import org.nuxeo.ecm.core.model.Document;
import org.nuxeo.ecm.core.versioning.StandardVersioningService;

public class CustomVersioningService extends StandardVersioningService {

    private static final Log log = LogFactory.getLog(CustomVersioningService.class);

	@Override
	public void doPostCreate(Document doc, Map&lt;String, Serializable&gt; options) {
		if (doc.isVersion() || doc.isProxy()) {
			return;
		}
		try {
			Boolean comesFromImport = (Boolean) options.get(&quot;comesFromImport&quot;);
			if (comesFromImport != null &amp;&amp; comesFromImport) {
				setVersion(doc, 12, 0);
			} else {
				setInitialVersion(doc);
			}
		} catch (DocumentException e) {
			// ignore, should not happen
			log.warn(&quot;Issue while setting the initial document version&quot;, e);
		}
	}
}
</pre>
<p>It simply extends the default <em>VersioningService</em> and overrides the <em>doPostCreate</em> method. This method has access to the document context map. So we look for a Boolean <em>comeFromImport</em> in this map. If it&#8217;s true, we know we come from the importer and we can set the version to 12.0. If not we just keep with the usual implementation.</p>
<p>Now we need the contribution to the right extension point so that Nuxeo knows the <em>VersioningService</em> to use is <em>CustomVersioningService</em>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;component name=&quot;org.nuxeo.sample.versioning.contrib&quot;&gt;
&lt;extension target=&quot;org.nuxeo.ecm.core.versioning.VersioningService&quot; point=&quot;versioningService&quot;&gt;
    &lt;service class=&quot;org.nuxeo.sample.versioning.CustomVersioningService&quot; /&gt;
&lt;/extension&gt;
&lt;/component&gt;
</pre>
<p>The source code of this project is on my <a title="nuxeo-custom-versioningservice on Github" href="https://github.com/ldoguin/nuxeo-custom-versioningservice">Github</a>. That&#8217;s it for today, see ya&#8217; next Monday :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/05/qa-friday-import-document-put-nuxeo-version-12-initial-version.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Monday Dev Heaven] Add a Forgotten Password Functionality to Nuxeo, Part 1/2</title>
		<link>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-12.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-12.html#comments</comments>
		<pubDate>Mon, 14 May 2012 20:05:54 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Monday Dev Heaven]]></category>
		<category><![CDATA[Nuxeo]]></category>
		<category><![CDATA[Nuxeo IDE]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4493</guid>
		<description><![CDATA[<div id="attachment_4494" class="wp-caption alignright" style="width: 310px"><a href="http://dev.blogs.nuxeo.com/files/2012/05/askReset.png"><img class="size-medium wp-image-4494" src="http://dev.blogs.nuxeo.com/files/2012/05/askReset-300x111.png" alt="Ask a password reset" width="300" height="111" /></a><p class="wp-caption-text">Password Reset</p></div>
<p>This question is sometimes asked on <a title="Nuxeo answers" href="http://answers.nuxeo.com/">answers</a> or in the <a title="Nuxeo Forum" href="http://forum.nuxeo.com/">forum</a>. It&#8217;s a method to handle password reset for users. So I&#8217;m going to show you how I would do it. This is going to be a two part blog. Today I&#8217;ll write mostly about the WebEngine module handling the password reset functionality. Next week I&#8217;ll show you how to package it for <a title="Nuxeo Marketplace" href="marketplace.nuxeo.com">Nuxeo&#8217;s Marketplace.</a></p>
<h2>How does it work?</h2>
<p>Starting with something simple, we&#8217;ll add a &#8216;forgotten password&#8217; link on Nuxeo&#8217;s home page. It will redirect the user to an open (i.e. no authentication needed) page asking for an email address. Once the user submits the form, we&#8217;ll look in the user directory to see if the email has a corresponding user. If there&#8217;s no user, we&#8217;ll simply render the page again with an error message saying there&#8217;s no user associated with that email address. If we &#8230; <a href="http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-12.html" class="read_more">Read more</a></p>]]></description>
			<content:encoded><![CDATA[<div id="attachment_4494" class="wp-caption alignright" style="width: 310px"><a href="http://dev.blogs.nuxeo.com/files/2012/05/askReset.png"><img class="size-medium wp-image-4494" src="http://dev.blogs.nuxeo.com/files/2012/05/askReset-300x111.png" alt="Ask a password reset" width="300" height="111" /></a><p class="wp-caption-text">Password Reset</p></div>
<p>This question is sometimes asked on <a title="Nuxeo answers" href="http://answers.nuxeo.com/">answers</a> or in the <a title="Nuxeo Forum" href="http://forum.nuxeo.com/">forum</a>. It&#8217;s a method to handle password reset for users. So I&#8217;m going to show you how I would do it. This is going to be a two part blog. Today I&#8217;ll write mostly about the WebEngine module handling the password reset functionality. Next week I&#8217;ll show you how to package it for <a title="Nuxeo Marketplace" href="marketplace.nuxeo.com">Nuxeo&#8217;s Marketplace.</a></p>
<h2>How does it work?</h2>
<p>Starting with something simple, we&#8217;ll add a &#8216;forgotten password&#8217; link on Nuxeo&#8217;s home page. It will redirect the user to an open (i.e. no authentication needed) page asking for an email address. Once the user submits the form, we&#8217;ll look in the user directory to see if the email has a corresponding user. If there&#8217;s no user, we&#8217;ll simply render the page again with an error message saying there&#8217;s no user associated with that email address. If we do find a user, we generate a temporary link and send it to the user by email. This link has to exist for only a short period of time, for security reasons. When the user clicks on the link, he ends up on a form asking for his new password.</p>
<p>That&#8217;s it for the simple, short user story. We&#8217;ll see the details along the way. Now let&#8217;s get to it :)</p>
<h3>Ask for the reset</h3>
<p>The first thing I did was to run the Nuxeo WebEngine project wizard with Nuxeo IDE. This gives me an empty project. I&#8217;m already able to code :) My next step is to create the form to retrieve the user email and make it available to an open URL.</p>
<p>This is my form:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;@extends src=&quot;./base.ftl&quot;&gt;
&lt;@block name=&quot;title&quot;&gt;
 ${Context.getMessage('label.askResetPassForm.title')}
&lt;/@block&gt;
&lt;@block name=&quot;content&quot;&gt;

&lt;div class=&quot;registrationForm&quot;&gt;
&lt;form action=&quot;${This.path}/sendPasswordMail&quot; method=&quot;post&quot; enctype=&quot;application/x-www-form-urlencoded&quot; name=&quot;submitNewPassword&quot;&gt;
 &lt;table&gt;
    &lt;tr&gt;
      &lt;td class=&quot;login_label&quot;&gt;
        &lt;span class=&quot;required&quot;&gt;${Context.getMessage('label.registerForm.email')}&lt;/span&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;input type=&quot;text&quot; id=&quot;EmailAddress&quot; value=&quot;${data['EmailAddress']}&quot; name=&quot;EmailAddress&quot; class=&quot;login_input&quot; isRequired=&quot;true&quot;/&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;/td&gt;
      &lt;td&gt;
        &lt;input class=&quot;login_button&quot; type=&quot;submit&quot; name=&quot;submit&quot;
          value=&quot;${Context.getMessage('label.registerForm.submit')}&quot; /&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;#if err??&gt;
    &lt;tr&gt;
      &lt;td colspan=&quot;2&quot;&gt;
        &lt;div class=&quot;errorMessage&quot;&gt;
          ${Context.getMessage(&quot;label.connect.trial.form.errvalidation&quot;)}
          ${err}
        &lt;/div&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/#if&gt;
  &lt;#if info??&gt;
    &lt;tr&gt;
      &lt;td colspan=&quot;2&quot;&gt;
        &lt;div class=&quot;infoMessage&quot;&gt;
          ${info}
        &lt;/div&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/#if&gt;
  &lt;/table&gt;
&lt;/form&gt;
&lt;/div&gt;
&lt;/@block&gt;
&lt;/@extends&gt;
</pre>
<p>One of the cool features that comes with WebEngine is its <a title="WebEngine Template model" href="http://doc.nuxeo.com/x/CYAO#WebEngine%28JAX-RS%29-TemplateModel">templating model</a>. It gives us the ability to extend an existing Freemarker template. This way you can override only the part of the template you need. For instance, here we&#8217;re extending the base.ftl template (that&#8217;s because of the <em>extends</em> markup). This template defines at least two <em>block</em>s named &#8216;title&#8217; and &#8216;content&#8217;. So we can redefine the content of these two using the <em>block</em> markup.</p>
<p>And this is the contribution to the <a title="OpenUrl extension point" href="http://explorer.nuxeo.org/nuxeo/site/distribution/current/viewExtensionPoint/org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService--openUrl">openUrl extension point</a>. It&#8217;s needed to make my form available without user authentication.</p>
<pre class="brush: xml; title: ; notranslate">

  &lt;extension
    target=&quot;org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService&quot;
    point=&quot;openUrl&quot;&gt;
    &lt;openUrl name=&quot;Forgotten_password&quot;&gt;
      &lt;grantPattern&gt;${org.nuxeo.ecm.contextPath}/site/resetPassword/&lt;/grantPattern&gt;
    &lt;/openUrl&gt;
    &lt;openUrl name=&quot;SendPasswordMail&quot;&gt;
      &lt;grantPattern&gt;${org.nuxeo.ecm.contextPath}/site/resetPassword/sendPasswordMail&lt;/grantPattern&gt;
    &lt;/openUrl&gt;
    &lt;openUrl name=&quot;EnterNewPassword&quot;&gt;
      &lt;grantPattern&gt;${org.nuxeo.ecm.contextPath}/site/resetPassword/enterNewPassword/.*&lt;/grantPattern&gt;
    &lt;/openUrl&gt;
    &lt;openUrl name=&quot;SubmitNewPassword&quot;&gt;
      &lt;grantPattern&gt;${org.nuxeo.ecm.contextPath}/site/resetPassword/submitNewPassword&lt;/grantPattern&gt;
    &lt;/openUrl&gt;
    &lt;openUrl name=&quot;Graphical_Resources&quot;&gt;
      &lt;grantPattern&gt;${org.nuxeo.ecm.contextPath}/site/skin/resetPassword/.*&lt;/grantPattern&gt;
    &lt;/openUrl&gt;
  &lt;/extension&gt;
</pre>
<p>Now let&#8217;s get to the Java part. The <em>doGet</em> method will render the page I&#8217;ve just defined, while the <em>sendPasswordMail</em> method will handle the form submit. In the latter, we will do the email validation, look if we have an existing user with the given address, and if this is the case, we&#8217;ll send him an email.</p>
<p>The validation is really simple here &#8212; we just check if the given parameter is not null nor empty. Then if we have an email address, we go through the <em><a title="CreatePasswordResetLinkUnrestricted on GitHub" href="https://github.com/ldoguin/nuxeo-userpassword-reset/blob/master/nuxeo-userpassword-reset/src/main/java/org/nuxeo/ecm/user/runner/CreatePasswordResetLinkUnrestricted.java">CreatePasswordResetLinkUnrestricted</a></em>. This is the class where we look for the user, build a reset password link if the user exists, or render our page with an error message. I&#8217;ve tried to internationalize the email a little, but you still have to fork the code to modify the templates and subjects&#8230; I&#8217;ll try to enhance that later.</p>
<pre class="brush: java; title: ; notranslate">
    @GET
    public Object doGet() {
        Map&lt;String, String&gt; data = new HashMap&lt;String, String&gt;();
        return getView(&quot;newPasswordRequest&quot;).arg(&quot;data&quot;, data);
    }

    @POST
    @Path(&quot;sendPasswordMail&quot;)
    @Produces(&quot;text/html&quot;)
    public Object sendPasswordMail() throws ClientException {
        FormData formData = getContext().getForm();
        String email = formData.getString(&quot;EmailAddress&quot;);
        if (email == null || &quot;&quot;.equals(email.trim())) {
            return redisplayFormWithErrorMessage(&quot;newPasswordRequest&quot;,
                    ctx.getMessage(&quot;label.registerForm.validation.email&quot;),
                    formData);
        }
        email = email.trim();
        CreatePasswordResetLinkUnrestricted runner = new CreatePasswordResetLinkUnrestricted(
                getDefaultRepositoryName(), email);
        runner.runUnrestricted();

        String errorMessage = runner.getErrorMessage();
        if (errorMessage != null) {
            return redisplayFormWithErrorMessage(&quot;newPasswordRequest&quot;,
                    ctx.getMessage(errorMessage), formData);
        } else {
            String passwordResetLink = runner.getPasswordResetLink();
            String subject;
            Template template;
            if (ctx.getLocale().equals(Locale.FRENCH)) {
                template = getView(&quot;mail/passwordForgotten_fr&quot;);
                subject = &quot;Nuxeo - Votre nouveau mot de passe&quot;;
            } else {
                template = getView(&quot;mail/passwordForgotten&quot;);
                subject = &quot;Nuxeo - Your new password&quot;;
            }
            String message = template.arg(&quot;passwordResetLink&quot;,
                    passwordResetLink).render();
            try {
                sendEmail(email, subject, message);
            } catch (MessagingException e) {
                // issue while sending the mail
                log.error(&quot;Sending Registration E-Mail Error&quot;, e);
                return Response.status(500).build();
            }
            return redisplayFormWithInfoMessage(&quot;newPasswordRequest&quot;,
                    ctx.getMessage(&quot;label.sendPasswordMail.emailSent&quot;),
                    formData);
        }
    }

    protected Template redisplayFormWithMessage(String messageType,
            String formName, String message, FormData data) {
        Map&lt;String, String&gt; savedData = new HashMap&lt;String, String&gt;();
        for (String key : data.getKeys()) {
            savedData.put(key, data.getString(key));
        }
        return getView(formName).arg(&quot;data&quot;, savedData).arg(messageType,
                message);
    }

    protected Template redisplayFormWithInfoMessage(String formName,
            String message, FormData data) {
        return redisplayFormWithMessage(&quot;info&quot;, formName, message, data);
    }

    protected Template redisplayFormWithErrorMessage(String formName,
            String message, FormData data) {
        return redisplayFormWithMessage(&quot;err&quot;, formName, message, data);
    }

    public void sendEmail(String email, String subject, String message)
            throws MessagingException {
        Composer cp = new Composer();
        Mailer mailer = cp.getMailer();
        Mailer.Message msg = mailer.newMessage();
        msg.setFrom(MAIL_FROM);
        msg.setSubject(subject);
        msg.setRecipient(RecipientType.TO, new InternetAddress(email));
        msg.setContent(message, &quot;text/html&quot;);
        msg.send();
    }
</pre>
<h3>Manage the keys</h3>
<p>Now we&#8217;re able to retrieve and email address, find the corresponding user and send the email. Under the hood, the <em>CreatePasswordResetLinkUnrestricted</em> generates a unique key, stored in a <a title="The directory contrib on GitHub" href="https://github.com/ldoguin/nuxeo-userpassword-reset/blob/master/nuxeo-userpassword-reset/src/main/resources/OSGI-INF/resetpassword-directory-contrib.xml">directory</a> along with the user email address and the current date. A directory is a good fit to store our temporary keys. I will delete every one-day-old key using Nuxeo&#8217;s event system.</p>
<p>Let&#8217;s add a contribution to the scheduler service. It will raise the <em>cleanResetPassKeys</em> event every day at 1am.</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;extension
    target=&quot;org.nuxeo.ecm.platform.scheduler.core.service.SchedulerRegistryService&quot;
    point=&quot;schedule&quot;&gt;
    &lt;schedule id=&quot;cleanResetPassKeys&quot;&gt;
      &lt;username&gt;Administrator&lt;/username&gt;
      &lt;eventId&gt;cleanResetPassKeys&lt;/eventId&gt;
      &lt;eventCategory&gt;default&lt;/eventCategory&gt;
      &lt;cronExpression&gt;0 0 1 * * ?&lt;/cronExpression&gt;
    &lt;/schedule&gt;
  &lt;/extension&gt;
</pre>
<p>So what we need to do now is add a <a title="The Listener contribution on GitHub" href="https://github.com/ldoguin/nuxeo-userpassword-reset/blob/master/nuxeo-userpassword-reset/src/main/resources/OSGI-INF/resetPassword-listener-contrib.xml">listener</a> for the <em>cleanResetPassKeys</em> event.</p>
<p>Here&#8217;s the code of my listener. It&#8217;s straightforward. The <em>simpleDate</em> String is the previous day&#8217;s date, formatted the same way we stored it in the directory. We use it as a directory filter. This way we can retrieve all keys created the day before and delete them. What I&#8217;d like to do in the future is make this configurable in the Admin Center. That way, the administrator could choose the time to live for the key.</p>
<pre class="brush: java; title: ; notranslate">
public class CleanForgottenPasswordKeysListener implements EventListener {

	public static final Log log = LogFactory
			.getLog(CleanForgottenPasswordKeysListener.class);

    @Override
    public void handleEvent(Event event) throws ClientException {
		SimpleDateFormat sdf = new SimpleDateFormat(&quot;yyMMdd&quot;);
		Calendar yesterday = Calendar.getInstance();
		yesterday.add(Calendar.DATE, -1);
		String simpleDate = sdf.format(yesterday.getTime());
		DirectoryService ds;
		try {
			ds = Framework.getService(DirectoryService.class);
		} catch (Exception e) {
			throw new RuntimeException(&quot;Could not find DirectoryService&quot;, e);
		}
		Session session = ds.open(&quot;resetPasswordKeys&quot;);
		Map&lt;String, Serializable&gt; filter = new HashMap&lt;String, Serializable&gt;();
		filter.put(&quot;creationDate&quot;, simpleDate);
		DocumentModelList keysToRemove = session.query(filter);
		for (DocumentModel key : keysToRemove) {
			session.deleteEntry(key);
		}
		session.close();
    }
}
</pre>
<p>That&#8217;s it for today. In the second part I&#8217;ll tell you how to actually reset the password. Or if you are curious you can already checkout <a title="nuxeo-userpassword-reset on GitHub" href="https://github.com/ldoguin/nuxeo-userpassword-reset">the source code on Github</a>. I will also show you how to make a Marketplace package of this. See ya&#8217; on Friday :)</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-add-forgotten-password-functionality-nuxeo-part-12.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[Q&amp;A Friday] How to Clear UI Selected Documents in Studio</title>
		<link>http://dev.blogs.nuxeo.com/2012/05/qa-friday-clear-ui-selected-documents-studio.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/05/qa-friday-clear-ui-selected-documents-studio.html#comments</comments>
		<pubDate>Fri, 11 May 2012 13:21:41 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Friday Q&A]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Nuxeo]]></category>
		<category><![CDATA[Nuxeo IDE]]></category>
		<category><![CDATA[Studio]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4488</guid>
		<description><![CDATA[<p>Today we have a question from <a title="Pibou on Nuxeo Answers" href="http://answers.nuxeo.com/users/319/pibou/">pibou</a>, who asks <a title="Problem refreshing UI after document deletion" href="http://answers.nuxeo.com/questions/2542/problem-refreshing-ui-after-document-deletion">how he can refresh the UI using content automation in Studio</a>.<br />
There is indeed a <a title="Refresh operation documentation" href="http://explorer.nuxeo.org/nuxeo/site/distribution/current/viewOperation/Seam.Refresh">Refresh UI</a> operation, but what it does is invalidate the different query caches. This will not empty the selected documents list, for instance. And that is just what pibou needs. Unfortunately we have no operation available for this by default on 5.5. So here&#8217;s a workaround, until the operation is available for 5.6.</p>
<h3>Clear selected documents list operation</h3>
<p>This part is simple. You need Nuxeo IDE with a SDK setup. Create a new project or use an existing one, and run the operation wizard.</p>
<p>Here&#8217;s what my wizard looks like:<br />
<a href="http://dev.blogs.nuxeo.com/files/2012/05/ClearSlectedDocuments.png"><img class="aligncenter size-medium wp-image-4489" src="http://dev.blogs.nuxeo.com/files/2012/05/ClearSlectedDocuments-e1336655866258-298x300.png" alt="Clear Selected Documents operation wizard" width="298" height="300" /></a></p>
<p>And here&#8217;s the code of my operation:</p>
<pre class="brush: java; title: ; notranslate">
@Operation(id = ClearSelectedDocuments.ID, category = Constants.CAT_UI, requires = Constants.SEAM_CONTEXT, label = &#34;Clear Selected Documents&#34;, description = &#34;Clear the default list of selected documents&#34;)
public class ClearSelectedDocuments {

	&#8230; <a href="http://dev.blogs.nuxeo.com/2012/05/qa-friday-clear-ui-selected-documents-studio.html" class="read_more">Read more</a></pre>]]></description>
			<content:encoded><![CDATA[<p>Today we have a question from <a title="Pibou on Nuxeo Answers" href="http://answers.nuxeo.com/users/319/pibou/">pibou</a>, who asks <a title="Problem refreshing UI after document deletion" href="http://answers.nuxeo.com/questions/2542/problem-refreshing-ui-after-document-deletion">how he can refresh the UI using content automation in Studio</a>.<br />
There is indeed a <a title="Refresh operation documentation" href="http://explorer.nuxeo.org/nuxeo/site/distribution/current/viewOperation/Seam.Refresh">Refresh UI</a> operation, but what it does is invalidate the different query caches. This will not empty the selected documents list, for instance. And that is just what pibou needs. Unfortunately we have no operation available for this by default on 5.5. So here&#8217;s a workaround, until the operation is available for 5.6.</p>
<h3>Clear selected documents list operation</h3>
<p>This part is simple. You need Nuxeo IDE with a SDK setup. Create a new project or use an existing one, and run the operation wizard.</p>
<p>Here&#8217;s what my wizard looks like:<br />
<a href="http://dev.blogs.nuxeo.com/files/2012/05/ClearSlectedDocuments.png"><img class="aligncenter size-medium wp-image-4489" src="http://dev.blogs.nuxeo.com/files/2012/05/ClearSlectedDocuments-e1336655866258-298x300.png" alt="Clear Selected Documents operation wizard" width="298" height="300" /></a></p>
<p>And here&#8217;s the code of my operation:</p>
<pre class="brush: java; title: ; notranslate">
@Operation(id = ClearSelectedDocuments.ID, category = Constants.CAT_UI, requires = Constants.SEAM_CONTEXT, label = &quot;Clear Selected Documents&quot;, description = &quot;Clear the default list of selected documents&quot;)
public class ClearSelectedDocuments {

	public static final String ID = &quot;Seam.ClearSelectedDocuments&quot;;

	@OperationMethod
	public void run() {
            OperationHelper.getDocumentListManager().resetWorkingList(
                DocumentsListsManager.CURRENT_DOCUMENT_SELECTION);
	}

}
</pre>
<p>The operationHelper can give you access to some useful Seam components. Here, it gives us the DocumentListManager, which handles the different selection lists like the clipboard, the working list or the selected documents.</p>
<p>Now we need to make Studio aware of that operation. If you use Nuxeo IDE and have configured your Studio account, it&#8217;s dead easy. When you&#8217;re on the Nuxeo Studio tab, there&#8217;s an &#8216;Export operations&#8217; button. It will first ask you to select which projects you want to scan. On the same screen, you can select the Studio project where you want to export the operations, if you have many. Click on next and you get the list of operations, it found. Select the one one you need and simply click on finish. That&#8217;s it, your operation is available in your Studio project.</p>
<p>What it does under the hood is simply generate a Json signature of the operation and paste it on the Studio operation registry:<br />
<a href="http://dev.blogs.nuxeo.com/files/2012/05/Studio-registry.png"><img class="aligncenter size-medium wp-image-4490" src="http://dev.blogs.nuxeo.com/files/2012/05/Studio-registry-300x168.png" alt="Studio operations registry" width="300" height="168" /></a></p>
<p>So if you have other questions about Studio and operations, ask them on <a title="Nuxeo Answers" href="http://answers.nuxeo.com/">answers.nuxeo.com</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/05/qa-friday-clear-ui-selected-documents-studio.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Monday Dev Heaven] Create Your Own Documents on File Drag and Drop</title>
		<link>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-fileimporter-plugin.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-fileimporter-plugin.html#comments</comments>
		<pubDate>Mon, 07 May 2012 20:33:49 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Monday Dev Heaven]]></category>
		<category><![CDATA[Nuxeo]]></category>
		<category><![CDATA[Nuxeo IDE]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4480</guid>
		<description><![CDATA[<p>If you follow this blog you&#8217;ll remember I&#8217;ve been writing a lot about file import recently. And I have a new trick for you on this matter. When I created <a title="[Monday Dev Heaven] Automatic document creation in Nuxeo, Part 2" href="http://dev.blogs.nuxeo.com/2012/04/monday-dev-heaven-automatic-document-creation-nuxeo-part2.html">the import factory</a>, I took an existing Nuxeo XML export as example. But this could also work with single files. In this case, the importer uses the <a title="FileManagerService Javadoc" href="http://community.nuxeo.com/api/nuxeo/5.5/javadoc/org/nuxeo/ecm/platform/filemanager/service/FileManagerService.html">FileMangerService</a> plugin. The role of this plugin is to create <em>Documents</em> in Nuxeo using a given file.</p>
<p>When the file is imported, Nuxeo goes through each plugin following their processes. If the mime type matches, then it tries to create the document. If it returns null instead of a <a title="DocumentModel Javadoc" href="http://community.nuxeo.com/api/nuxeo/5.5/javadoc/org/nuxeo/ecm/core/api/DocumentModel.html">DocumentModel</a>, the next plugin with a matching mime type is used, and so on. Here is a simple plugin contribution as an example:</p>
<pre class="brush: xml; title: ; notranslate">
  &#60;extension
    target=&#34;org.nuxeo.ecm.platform.filemanager.service.FileManagerService&#34;
    point=&#34;plugins&#34;&#62;

    &#60;plugin name=&#34;ExportedArchivePlugin&#34;
      class=&#34;org.nuxeo.ecm.platform.filemanager.service.extension.ExportedZipImporter&#34;
      order=&#34;10&#34;&#62;
      &#60;filter&#62;application/zip&#60;/filter&#62;
    &#60;/plugin&#62;

    &#60;plugin name=&#34;CSVArchivePlugin&#34;
      class=&#34;org.nuxeo.ecm.platform.filemanager.service.extension.CSVZipImporter&#34;
      order=&#34;11&#34;&#62;
      &#60;filter&#62;application/zip&#60;/filter&#62;
    &#60;/plugin&#62;

    &#60;plugin name=&#34;DefaultFileImporter&#34;
      class=&#34;org.nuxeo.ecm.platform.filemanager.service.extension.DefaultFileImporter&#34;
      order=&#34;100&#34;&#62;
      &#8230; <a href="http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-fileimporter-plugin.html" class="read_more">Read more</a></pre>]]></description>
			<content:encoded><![CDATA[<p>If you follow this blog you&#8217;ll remember I&#8217;ve been writing a lot about file import recently. And I have a new trick for you on this matter. When I created <a title="[Monday Dev Heaven] Automatic document creation in Nuxeo, Part 2" href="http://dev.blogs.nuxeo.com/2012/04/monday-dev-heaven-automatic-document-creation-nuxeo-part2.html">the import factory</a>, I took an existing Nuxeo XML export as example. But this could also work with single files. In this case, the importer uses the <a title="FileManagerService Javadoc" href="http://community.nuxeo.com/api/nuxeo/5.5/javadoc/org/nuxeo/ecm/platform/filemanager/service/FileManagerService.html">FileMangerService</a> plugin. The role of this plugin is to create <em>Documents</em> in Nuxeo using a given file.</p>
<p>When the file is imported, Nuxeo goes through each plugin following their processes. If the mime type matches, then it tries to create the document. If it returns null instead of a <a title="DocumentModel Javadoc" href="http://community.nuxeo.com/api/nuxeo/5.5/javadoc/org/nuxeo/ecm/core/api/DocumentModel.html">DocumentModel</a>, the next plugin with a matching mime type is used, and so on. Here is a simple plugin contribution as an example:</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;extension
    target=&quot;org.nuxeo.ecm.platform.filemanager.service.FileManagerService&quot;
    point=&quot;plugins&quot;&gt;

    &lt;plugin name=&quot;ExportedArchivePlugin&quot;
      class=&quot;org.nuxeo.ecm.platform.filemanager.service.extension.ExportedZipImporter&quot;
      order=&quot;10&quot;&gt;
      &lt;filter&gt;application/zip&lt;/filter&gt;
    &lt;/plugin&gt;

    &lt;plugin name=&quot;CSVArchivePlugin&quot;
      class=&quot;org.nuxeo.ecm.platform.filemanager.service.extension.CSVZipImporter&quot;
      order=&quot;11&quot;&gt;
      &lt;filter&gt;application/zip&lt;/filter&gt;
    &lt;/plugin&gt;

    &lt;plugin name=&quot;DefaultFileImporter&quot;
      class=&quot;org.nuxeo.ecm.platform.filemanager.service.extension.DefaultFileImporter&quot;
      order=&quot;100&quot;&gt;
      &lt;filter&gt;.*&lt;/filter&gt;
    &lt;/plugin&gt;
  &lt;/extension&gt;
</pre>
<p>Take a simple zip file as an example. The first plugin used will be the ExportedArchivePlugin. It will return null because the zip file is not a Nuxeo export; it doesn&#8217;t contain a .nuxeo-archive file. The next plugin will be the CSVArchivePlugin. Since the zip doesn&#8217;t contain a meta-data.csv file, the plugin returns null. The next one to be used will be the DefaultFileImporter, which will create a simple <em>File</em> document with the zip file as main attachment.</p>
<h2>When should you use plugins?</h2>
<p>Plugins are a good fit for two things. The first one is creating several documents from a single file. With the ExportedArchivePlugin, you can create as many documents as you want using the content of this archive. You could also have a big XML file or maybe a <a title="GEDCOM" href="http://en.wikipedia.org/wiki/GEDCOM">GEDCOM</a> file.</p>
<p>The other good fit is choosing the right <em>DocType</em> for a specific file. Maybe you have defined an <em>OfficeFile</em> document type that would be better then the usual <em>File</em> for all your office files.</p>
<p>Sure, you could use it to add business code like metadata extraction, specific property updates, file transformation, etc., but this would be better in a listener. This way, your code is called when you create a document from a creation form or from the import. And you can choose to do this synchronously or asynchronously, which is always good for big imports or file conversions.</p>
<h2>Creating a new plugin</h2>
<p>So now I&#8217;m going to write a plugin that creates people and links them together from a GEDCOM file. A GEDCOM file represents a genealogical tree. You can get information about individuals, and meta data linking them together. That&#8217;s a perfect example for a FileImporter plugin. Let&#8217;s get to it!</p>
<p>Here is my XML contribution. It&#8217;s really simple &#8212; you need to indicate the Java class implementing your import logic, give it an order, a name and a list of mime types. GEDCOM files are text, so you just need the &#8216;text/plain&#8217; mime type. I&#8217;ve chosen 9 as the order to be sure this plugin is the first to be used. If my GEDCOM parser does not recognize the file as a GEDCOM, my plugin will simply return null and the FileManagerService will give the file to the next plugin.</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;extension
      target=&quot;org.nuxeo.ecm.platform.filemanager.service.FileManagerService&quot;
      point=&quot;plugins&quot;&gt;
      &lt;plugin name=&quot;GEDCOMImporter&quot;
        class=&quot;org.nuxeo.genealogy.core.plugin.GEDCOMFileManagerPlugin&quot;
        order=&quot;9&quot;&gt;
      &lt;filter&gt;text/plain&lt;/filter&gt;
    &lt;/plugin&gt;

  &lt;/extension&gt;
</pre>
<p>This is my Java Class which extends the AbstractFileImporter (which itself implements the <a title="FileImporter JavaDoc" href="http://community.nuxeo.com/api/nuxeo/5.5/javadoc/org/nuxeo/ecm/platform/filemanager/service/extension/FileImporter.html">FileImporter</a> Interface). I&#8217;ve found a nice library to do the GEDCOM parsing. It&#8217;s called <a title="gedcom4j on google doc" href="http://code.google.com/p/gedcom4j/">gedcom4j</a> and is available on Google code. It&#8217;s open source and the project is still active.</p>
<p>This is a really simple and basic example. It creates a folder named as the original file, then creates documents of type Individual, adding some metadata and then linking those documents together with relations.</p>
<pre class="brush: java; title: ; notranslate">
public class GEDCOMFileManagerPlugin extends AbstractFileImporter {

	public static final String SPOUSE_OF_PREDICATE = &quot;http://purl.org/vocab/relationship/spouseOf&quot;;

	public static final String CHILD_OF_PREDICATE = &quot;http://purl.org/vocab/relationship/childOf&quot;;

	private static final long serialVersionUID = 1876876876L;

	private static final Log log = LogFactory
			.getLog(GEDCOMFileManagerPlugin.class);

	protected RelationManager relationManager;

	protected DocumentModel treeContainerDoc;

	public DocumentModel create(CoreSession session, Blob content, String path,
			boolean overwrite, String filename, TypeManager typeService)
			throws ClientException, IOException {

		GedcomParser parser = new GedcomParser();
		try {
			parser.load(content.getStream());
		} catch (GedcomParserException e) {
			log.warn(&quot;Not a gedcom file&quot;, e);
			return null;
		}
		Gedcom gedcom = parser.gedcom;

		// create tree container
		treeContainerDoc = session
				.createDocumentModel(path, filename, &quot;Folder&quot;);
		treeContainerDoc.setPropertyValue(&quot;dc:title&quot;, filename);
		session.createDocument(treeContainerDoc);

		// create every individual in the tree
		Collection&lt;Individual&gt; everybody = gedcom.individuals.values();
		for (Individual individual : everybody) {
			DocumentModel docInd = session.createDocumentModel(
					treeContainerDoc.getPathAsString(), individual.xref,
					&quot;Individual&quot;);
			docInd.setPropertyValue(&quot;dc:title&quot;, individual.formattedName());
			docInd.setPropertyValue(&quot;idv:xref&quot;, individual.xref);
			docInd.setPropertyValue(&quot;idv:name&quot;, individual.formattedName());
			docInd.setPropertyValue(&quot;idv:gender&quot;, individual.sex);
			session.createDocument(docInd);
		}
		// add spouseOf relations
		for (Individual individual : everybody) {
			for (FamilySpouse spouse : individual.familiesWhereSpouse) {
				if (spouse.family.husband == individual) {
					if (spouse.family.wife != null) {
						addIndividualsRelation(individual.xref,
								SPOUSE_OF_PREDICATE, spouse.family.wife.xref,
								session);
					}
				} else {
					if (spouse.family.husband != null) {
						addIndividualsRelation(individual.xref,
								SPOUSE_OF_PREDICATE,
								spouse.family.husband.xref, session);
					}
				}

			}
			// add childOf relations
			for (FamilyChild f : individual.familiesWhereChild) {

				if (f.family.wife != null) {
					addIndividualsRelation(individual.xref, CHILD_OF_PREDICATE,
							f.family.wife.xref, session);
				}
				if (f.family.husband != null) {
					addIndividualsRelation(individual.xref, CHILD_OF_PREDICATE,
							f.family.husband.xref, session);
				}
			}
		}

		return treeContainerDoc;
	}

	private RelationManager getRelationManager() {
		if (relationManager == null) {
			try {
				relationManager = Framework.getService(RelationManager.class);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		return relationManager;
	}

	private void addIndividualsRelation(String subjectXRef, String predicat,
			String objectXRef, CoreSession session) throws ClientException {
		Resource documentResource = getDocumentResource(getIndDoc(subjectXRef,
				treeContainerDoc.getRef(), session));
		Resource predicate = new ResourceImpl(predicat);

		Resource objectResource = getDocumentResource(getIndDoc(objectXRef,
				treeContainerDoc.getRef(), session));

		Statement stmt = new StatementImpl(documentResource, predicate,
				objectResource);
		Graph graph = getRelationManager().getGraphByName(
				RelationConstants.GRAPH_NAME);
		graph.add(stmt);
	}

	public DocumentModel getIndDoc(String xref, DocumentRef parentRef,
			CoreSession session) throws ClientException {
		return session.getChild(parentRef, xref);
	}

	public QNameResource getDocumentResource(DocumentModel document)
			throws ClientException {
		QNameResource documentResource = null;
		if (document != null) {
			documentResource = (QNameResource) getRelationManager()
					.getResource(RelationConstants.DOCUMENT_NAMESPACE,
							document, null);
		}
		return documentResource;
	}

}
</pre>
<p>That&#8217;s it for today &#8212; see you on Friday!</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/05/monday-dev-heaven-fileimporter-plugin.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Q&amp;A Friday] How does the Seam.PushDocument operation work?</title>
		<link>http://dev.blogs.nuxeo.com/2012/05/qa-friday-seampushdocument-operation-work.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/05/qa-friday-seampushdocument-operation-work.html#comments</comments>
		<pubDate>Fri, 04 May 2012 12:57:36 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Friday Q&A]]></category>
		<category><![CDATA[Nuxeo]]></category>
		<category><![CDATA[Studio]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4487</guid>
		<description><![CDATA[<div id="attachment_4385" class="wp-caption alignright" style="width: 167px"><a href="http://dev.blogs.nuxeo.com/files/2012/02/question.png"><img class="size-full wp-image-4385" src="http://dev.blogs.nuxeo.com/files/2012/02/question.png" alt="How does Seam.PushDocument work?" width="157" height="123" /></a><p class="wp-caption-text">How does Seam.PushDocument work?</p></div>
<p>A new question by <a title="Michael on Nuxeo Answers" href="http://answers.nuxeo.com/users/293/michael-bell/">Michael Bell</a>: <a title="How does Seam.PushDocument work?" href="http://answers.nuxeo.com/questions/2514/how-does-seampushdocument-work">How does Seam.PushDocument work?</a> Well, it does not navigate to a document, as <a title="Clément on Nuxeo Answers" href="http://answers.nuxeo.com/users/115/clement-lardeur/">Clément</a> said:</p>
<blockquote><p>If you just want to navigate to your newly created Document, you should use the Seam.NavigateTo operation.<br />
The Seam.PushDocument operation pushes just your Document in the Seam Context.</p></blockquote>
<p>For those of you who don&#8217;t know <a title="Seam Framework" href="http://seamframework.org/">Seam</a>, it&#8217;s the framework we use to write Nuxeo&#8217;s Web interface. It can be easily extended with Nuxeo Studio, hence the presence of Seam in Studio.</p>
<p><a title="Seam.PushDocument" href="http://doc.nuxeo.com/x/7gIz#OperationsIndex-PushtoSeamContext">Seam.PushDocument</a> adds a document to a <a title="Seam concepts" href="http://docs.jboss.com/seam/1.2.1.GA/reference/en/html/concepts.html">Seam context</a>: session, conversation, page or event. This can be useful if you think the user will click on different buttons, which is to say launch different operation chains, during his conversation or session. This way you can share documents between independent chains. So once you have stored your document, to retrieve it, you need &#8230; <a href="http://dev.blogs.nuxeo.com/2012/05/qa-friday-seampushdocument-operation-work.html" class="read_more">Read more</a></p>]]></description>
			<content:encoded><![CDATA[<div id="attachment_4385" class="wp-caption alignright" style="width: 167px"><a href="http://dev.blogs.nuxeo.com/files/2012/02/question.png"><img class="size-full wp-image-4385" src="http://dev.blogs.nuxeo.com/files/2012/02/question.png" alt="How does Seam.PushDocument work?" width="157" height="123" /></a><p class="wp-caption-text">How does Seam.PushDocument work?</p></div>
<p>A new question by <a title="Michael on Nuxeo Answers" href="http://answers.nuxeo.com/users/293/michael-bell/">Michael Bell</a>: <a title="How does Seam.PushDocument work?" href="http://answers.nuxeo.com/questions/2514/how-does-seampushdocument-work">How does Seam.PushDocument work?</a> Well, it does not navigate to a document, as <a title="Clément on Nuxeo Answers" href="http://answers.nuxeo.com/users/115/clement-lardeur/">Clément</a> said:</p>
<blockquote><p>If you just want to navigate to your newly created Document, you should use the Seam.NavigateTo operation.<br />
The Seam.PushDocument operation pushes just your Document in the Seam Context.</p></blockquote>
<p>For those of you who don&#8217;t know <a title="Seam Framework" href="http://seamframework.org/">Seam</a>, it&#8217;s the framework we use to write Nuxeo&#8217;s Web interface. It can be easily extended with Nuxeo Studio, hence the presence of Seam in Studio.</p>
<p><a title="Seam.PushDocument" href="http://doc.nuxeo.com/x/7gIz#OperationsIndex-PushtoSeamContext">Seam.PushDocument</a> adds a document to a <a title="Seam concepts" href="http://docs.jboss.com/seam/1.2.1.GA/reference/en/html/concepts.html">Seam context</a>: session, conversation, page or event. This can be useful if you think the user will click on different buttons, which is to say launch different operation chains, during his conversation or session. This way you can share documents between independent chains. So once you have stored your document, to retrieve it, you need the <a title="Seam.FetchDocument" href="doc.nuxeo.com/x/7gIz#OperationsIndex-UIDocumentFromSeam">Seam.FetchDocument</a> operation. It will restore the document as input for the next operation.</p>
<p>This can be useful if you manage your navigation with buttons. Let&#8217;s say I am currently viewing a Quality Report document. I&#8217;ve added a button called &#8220;Navigate to Incident Library.&#8221; What it does is push the current document into the Seam context and then navigates to the &#8220;Incident Library&#8221; document. When I&#8217;m inside such a document, I have a button called &#8220;Back to Report.&#8221; The only thing that button does is retrieve the document from the Seam context and then navigate to the document, using the <a title="Seam.NavigateTo" href="http://doc.nuxeo.com/x/7gIz#OperationsIndex-NavigatetoDocument">Seam.NavigateTo</a> operation.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/05/qa-friday-seampushdocument-operation-work.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Q&amp;A Friday] Will Nuxeo upgrade its technical Java Stack?</title>
		<link>http://dev.blogs.nuxeo.com/2012/04/qa-friday-cdi-tomcat7.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/04/qa-friday-cdi-tomcat7.html#comments</comments>
		<pubDate>Fri, 27 Apr 2012 15:46:57 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Friday Q&A]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Nuxeo]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4483</guid>
		<description><![CDATA[<div id="attachment_4385" class="wp-caption alignright" style="width: 167px"><a href="http://dev.blogs.nuxeo.com/files/2012/02/question.png"><img class="size-full wp-image-4385" src="http://dev.blogs.nuxeo.com/files/2012/02/question.png" alt="CDI? Tomcat7?" width="157" height="123" /></a><p class="wp-caption-text">CDI? Tomcat7?</p></div>
<p><a title="Nelson Silva on Nuxeo Answers" href="http://answers.nuxeo.com/users/31/nelson-silva/">Nelson Silva</a> asked us two questions: <a title="Planning Seam alternatives?" href="http://answers.nuxeo.com/questions/2424/planning-seam-alternatives">If we plan to replace Seam in the future</a> and <a title="Is Tomcat 7 support planned ?" href="http://answers.nuxeo.com/questions/2425/is-tomcat-7-support-planned">is Tomcat 7 support planned?</a></p>
<p>About Seam, we will use CDI instead, mostly because it&#8217;s close to Seam concepts and because it&#8217;s a JSR (<a title="JSR 299: Contexts and Dependency Injection for the JavaTM EE platform" href="http://jcp.org/en/jsr/detail?id=299">JSR-299</a>). We try to use standards as much as we can in Nuxeo.</p>
<p>We already have a code sample available on <a title="nuxeo-cdi-sample" href="https://github.com/tiry/nuxeo-cdi-sample">Github</a>. It builds a nuxeo-cdi-distribution, which is a coreserver distribution customized to run CDI/JSF2 components in nuxeo-cdi-sample.</p>
<p>About Tomcat 7, the answer here is not as straightforward as the previous one. We&#8217;d be happy to do it, but it&#8217;s not part of our priorities. So as <a title="Follow Florent on Github" href="https://github.com/efge">Florent</a> said, we&#8217;ll start the work when it is a higher priority, and there is more demand for it. This might be accelerated if we have customer requests, but this is not yet the case.</p>
<p>I&#8217;ve chosen these &#8230; <a href="http://dev.blogs.nuxeo.com/2012/04/qa-friday-cdi-tomcat7.html" class="read_more">Read more</a></p>]]></description>
			<content:encoded><![CDATA[<div id="attachment_4385" class="wp-caption alignright" style="width: 167px"><a href="http://dev.blogs.nuxeo.com/files/2012/02/question.png"><img class="size-full wp-image-4385" src="http://dev.blogs.nuxeo.com/files/2012/02/question.png" alt="CDI? Tomcat7?" width="157" height="123" /></a><p class="wp-caption-text">CDI? Tomcat7?</p></div>
<p><a title="Nelson Silva on Nuxeo Answers" href="http://answers.nuxeo.com/users/31/nelson-silva/">Nelson Silva</a> asked us two questions: <a title="Planning Seam alternatives?" href="http://answers.nuxeo.com/questions/2424/planning-seam-alternatives">If we plan to replace Seam in the future</a> and <a title="Is Tomcat 7 support planned ?" href="http://answers.nuxeo.com/questions/2425/is-tomcat-7-support-planned">is Tomcat 7 support planned?</a></p>
<p>About Seam, we will use CDI instead, mostly because it&#8217;s close to Seam concepts and because it&#8217;s a JSR (<a title="JSR 299: Contexts and Dependency Injection for the JavaTM EE platform" href="http://jcp.org/en/jsr/detail?id=299">JSR-299</a>). We try to use standards as much as we can in Nuxeo.</p>
<p>We already have a code sample available on <a title="nuxeo-cdi-sample" href="https://github.com/tiry/nuxeo-cdi-sample">Github</a>. It builds a nuxeo-cdi-distribution, which is a coreserver distribution customized to run CDI/JSF2 components in nuxeo-cdi-sample.</p>
<p>About Tomcat 7, the answer here is not as straightforward as the previous one. We&#8217;d be happy to do it, but it&#8217;s not part of our priorities. So as <a title="Follow Florent on Github" href="https://github.com/efge">Florent</a> said, we&#8217;ll start the work when it is a higher priority, and there is more demand for it. This might be accelerated if we have customer requests, but this is not yet the case.</p>
<p>I&#8217;ve chosen these two questions today because it&#8217;s the perfect opportunity to tell you about the upcoming webinar I&#8217;ll be doing with our CTO, <a title="Follow Thierry on Github" href="https://github.com/tiry/">Thierry Delprat</a>. Simply entitled <a title="An Hour with the CTO and the Community Liaison of Nuxeo" href="http://www.nuxeo.com/en/resource-center/webinar/nuxeo-cto-hour">&#8216;An Hour with the CTO and the Community Liaison of Nuxeo&#8217;</a>, we&#8217;ll talk about some of the features that will be in the Nuxeo Platform version 5.6, and tell you a bit more about the roadmap and where we&#8217;re heading technically. We want to make this as interactive as possible, so don&#8217;t hesitate to come and ask your questions. If you cannot attend the webinar, feel free to ask questions in the comment section of this blog or on <a title="Nuxeo Answers" href="http://answers.nuxeo.com">answers.nuxeo.com</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/04/qa-friday-cdi-tomcat7.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Next Nuxeo Code Sprint &#8211; June 21-22, 2012</title>
		<link>http://dev.blogs.nuxeo.com/2012/04/nuxeo-code-sprint-21-22-june-2012.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/04/nuxeo-code-sprint-21-22-june-2012.html#comments</comments>
		<pubDate>Thu, 26 Apr 2012 15:38:11 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4481</guid>
		<description><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/dev-sprint-nxw111.jpg"><img class="alignright size-medium wp-image-4482" src="http://dev.blogs.nuxeo.com/files/2012/04/dev-sprint-nxw111-300x200.jpg" alt="Dev sprint nxw11" width="300" height="200" /></a></p>
<p>Hi guys, I wanted to let you know that we have planned the next Nuxeo code sprint. It&#8217;s scheduled for June 21-22, 2012, and will be held at Nuxeo&#8217;s office in Paris. All the details are on our <a title="Next Sprint" href="http://doc.nuxeo.com/x/T4SE">wiki</a>.</p>
<p>You are all more than welcome to participate. The goal of this sprint, which will occur shortly after the Nuxeo Platform 5.6 code freeze, is to produce addons for the platform. There is no particular theme, as long as it&#8217;s related to Nuxeo, of course. I strongly encourage participants to discuss their subject on the wiki prior to the sprint. It&#8217;s always good to exchange information, especially on how you plan to implement it, so that we can give you suggestions.</p>
<p>And even if you don&#8217;t plan on coming, don&#8217;t hesitate to add your thoughts to the wiki page, and discuss features you&#8217;d like to see. You might inspire a team &#8230; <a href="http://dev.blogs.nuxeo.com/2012/04/nuxeo-code-sprint-21-22-june-2012.html" class="read_more">Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/dev-sprint-nxw111.jpg"><img class="alignright size-medium wp-image-4482" src="http://dev.blogs.nuxeo.com/files/2012/04/dev-sprint-nxw111-300x200.jpg" alt="Dev sprint nxw11" width="300" height="200" /></a></p>
<p>Hi guys, I wanted to let you know that we have planned the next Nuxeo code sprint. It&#8217;s scheduled for June 21-22, 2012, and will be held at Nuxeo&#8217;s office in Paris. All the details are on our <a title="Next Sprint" href="http://doc.nuxeo.com/x/T4SE">wiki</a>.</p>
<p>You are all more than welcome to participate. The goal of this sprint, which will occur shortly after the Nuxeo Platform 5.6 code freeze, is to produce addons for the platform. There is no particular theme, as long as it&#8217;s related to Nuxeo, of course. I strongly encourage participants to discuss their subject on the wiki prior to the sprint. It&#8217;s always good to exchange information, especially on how you plan to implement it, so that we can give you suggestions.</p>
<p>And even if you don&#8217;t plan on coming, don&#8217;t hesitate to add your thoughts to the wiki page, and discuss features you&#8217;d like to see. You might inspire a team that will take on this project :)</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/04/nuxeo-code-sprint-21-22-june-2012.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Monday Dev Heaven] Nuxeo @ First Devoxx France &#8211; 2012 Edition</title>
		<link>http://dev.blogs.nuxeo.com/2012/04/devoxx-france-2012-edition.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/04/devoxx-france-2012-edition.html#comments</comments>
		<pubDate>Mon, 23 Apr 2012 19:13:13 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Monday Dev Heaven]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4478</guid>
		<description><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/logo_devoxx_france_big.jpg"><img class="alignright size-medium wp-image-4479" src="http://dev.blogs.nuxeo.com/files/2012/04/logo_devoxx_france_big-300x154.jpg" alt="DevoxxFR" width="300" height="154" /></a></p>
<p>Part of the Nuxeo team attended <a href="http://www.devoxx.fr">Devoxx France</a> last week. If you don&#8217;t know about Devoxx, It&#8217;s an independent Java developer conference. This was the first French edition and I must say it went amazingly well for a first try, so kudos to the 20-person organizing team for pulling this off so smoothly.</p>
<p>We attended many, many different and interesting sessions. There&#8217;s a lot to say so I&#8217;ll try to be short. And all the sessions will be available on <a title="Parleys" href="http://www.parleys.com/">Parleys</a> anyway :)</p>
<p>I&#8217;ll start with a very inspiring talk given by Alexandre Bertails: <a title="Linked Data" href="http://www.w3.org/2012/Talks/bertails-devoxxfr/linked-data/">Linked Data &#8211; Big Data at Web scale</a>. The web of data is here, and vendors have to step up. Nuxeo is already engaged in it through the Apache <a title="Stanbol" href="http://incubator.apache.org/stanbol/index.html">Stanbol</a> project. This talk made me want to look more into RDFa, WebID and WebACLs.</p>
<p>There was a lot of interests in new languages. This is &#8230; <a href="http://dev.blogs.nuxeo.com/2012/04/devoxx-france-2012-edition.html" class="read_more">Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/logo_devoxx_france_big.jpg"><img class="alignright size-medium wp-image-4479" src="http://dev.blogs.nuxeo.com/files/2012/04/logo_devoxx_france_big-300x154.jpg" alt="DevoxxFR" width="300" height="154" /></a></p>
<p>Part of the Nuxeo team attended <a href="http://www.devoxx.fr">Devoxx France</a> last week. If you don&#8217;t know about Devoxx, It&#8217;s an independent Java developer conference. This was the first French edition and I must say it went amazingly well for a first try, so kudos to the 20-person organizing team for pulling this off so smoothly.</p>
<p>We attended many, many different and interesting sessions. There&#8217;s a lot to say so I&#8217;ll try to be short. And all the sessions will be available on <a title="Parleys" href="http://www.parleys.com/">Parleys</a> anyway :)</p>
<p>I&#8217;ll start with a very inspiring talk given by Alexandre Bertails: <a title="Linked Data" href="http://www.w3.org/2012/Talks/bertails-devoxxfr/linked-data/">Linked Data &#8211; Big Data at Web scale</a>. The web of data is here, and vendors have to step up. Nuxeo is already engaged in it through the Apache <a title="Stanbol" href="http://incubator.apache.org/stanbol/index.html">Stanbol</a> project. This talk made me want to look more into RDFa, WebID and WebACLs.</p>
<p>There was a lot of interests in new languages. This is not new and reflects what&#8217;s been going on for a while on the Internet. So I went to the <a title="Ceylon" href="http://ceylon-lang.org">Ceylon</a> and the <a title="Kotlin" href="http://blog.jetbrains.com/kotlin/">Kotlin</a> talks. It&#8217;s funny how those two, as well as many new languages, want to address the same issues, like Java verbosity and null pointer safety. Most Java developers write defensive code, with the sole purpose of handling null objects, making the code less clear than it should be. New languages also have to be compatible with Java. Kotlin does a great job at this. Seamless debugging with Java and Kotlin in intellij was quite impressive.</p>
<p>If I would have to choose, I think I&#8217;d go for Celyon. I like their approach, summed up by a simple tagline &#8216;say more, more clearly&#8217;. This is a very important factor for an enterprise language, and  a requirement for an open source software vendor, like Nuxeo. Our code has to be easy to read/understand.</p>
<p>You could really see an interest in Java7. There were talks about JVM bytecode and invokedynamic, which are in a sense linked to the new language trend, and also some talks about the new stuff in Java7, like project coin or NIO2. I really liked the one by <a title="Follow Jean-Michel on twitter" href="https://twitter.com/jmdoudoux">Jean-Michel Doudoux</a>, who did a small demo every time he introduced a new feature of NIO2. It was very instructive.</p>
<p>There were also some talks about client/server architecture. I saw the one from <a title="Follow James on Github" href="https://github.com/jamesward">James Ward</a>. He basically said that the client is now Javascript + HTML + CSS. It&#8217;s more than a trend, it&#8217;s already here. I&#8217;ll try to show you how it can be done with WebEngine in a future blog post. This will be the time to test <a title="Webjars" href="https://github.com/webjars/">Webjars</a>, a tool that he presented during his talk. It&#8217;s a Maven repo of web libraries wrapped into JAR files.</p>
<p>The last talk I saw was really unique &#8212; it was a live episode of <a title="Les Cast Codeurs" href="http://lescastcodeurs.com/">Les Cast Codeurs</a>, the French Java Posse. We had a lot of fun. You can listen to the episode <a title="Les Cast Codeurs Podcast – Episode 57 – En direct de Devoxx France 2012 " href="http://lescastcodeurs.com/2012/04/les-cast-codeurs-podcast-episode-57-en-direct-de-devoxx-france-2012/">here</a> to learn more about Devoxx France 2012. Thanks to <a title="Atlassian" href="http://www.atlassian.com/">Atlassian</a> for providing the beer :-D</p>
<p>So this was a really interesting week for me, because I attended both the <a title="Paris Jenkins User Conference 2012" href="http://dev.blogs.nuxeo.com/2012/04/jenkins-user-conference-paris-2012.html">Jenkins User Conference</a> and Devoxx France. I now have a list of things I need to try or look into. Here are some of them:</p>
<ul>
<li><a title="JaCoCo" href="www.eclemma.org/jacoco/">JaCoCo</a></li>
<li><a title="Ceylon" href="http://ceylon-lang.org/">Ceylon</a></li>
<li><a title="Byteman" href="http://www.jboss.org/byteman">JBoss Byteman</a></li>
<li>Java7 features (mostly NIO2)</li>
<li>Webjars</li>
<li>WebID, WebACLs</li>
</ul>
<p>Now I will go back to my usual blog posting pace ;-) See you on Friday!</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/04/devoxx-france-2012-edition.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Paris Jenkins User Conference 2012</title>
		<link>http://dev.blogs.nuxeo.com/2012/04/jenkins-user-conference-paris-2012.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/04/jenkins-user-conference-paris-2012.html#comments</comments>
		<pubDate>Wed, 18 Apr 2012 18:39:47 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[ECM]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[jenkins]]></category>
		<category><![CDATA[jenkwiz]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4470</guid>
		<description><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/headshot.png"><img class="alignright size-full wp-image-4474" src="http://dev.blogs.nuxeo.com/files/2012/04/headshot.png" alt="Jenkins" width="96" height="96" /></a></p>
<h4>Update:</h4>
<p> Julien&#8217;s video and slides are online on <a href="http://techtoc.tv/event/3742/conception-logicielle--design/editeurs-de-logiciels/jenkins-at-nuxeo" title="Jenkins at Nuxeo">techtoc.tv</a></p>
<p>Yesterday I was at the Paris Jenkins User Conference 2012 with <a title="Follow Julien on Github" href="https://github.com/jcarsique">Julien Carsique</a>. Julien was talking about how we use <a title="Jenkins CI" href="http://jenkins-ci.org/">Jenkins</a> at Nuxeo. For those of you who don&#8217;t know Jenkins, it&#8217;s a wonderful piece of software used to run and automate <a href="http://en.wikipedia.org/wiki/Continuous_integration" target="_blank">continuous integration</a> jobs. We previously wrote a <a title="[Monday Dev Heaven] Continuous Integration at Nuxeo" href="http://dev.blogs.nuxeo.com/2012/02/optimize-continuous-integration.html">blog</a> about this.</p>
<p>So about Julien&#8217;s presentation, you can check out the slides on <a href="http://www.nuxeo.com/en/resource-center/presentations/How-Nuxeo-uses-the-open-source-continuous-integration-server-Jenkins" target="_blank">nuxeo.com</a> or right here:</p>
<iframe src="http://www.slideshare.net/slideshow/embed_code/12585843" width="400" height="337" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br /><br />
<p>He explained how Nuxeo has been using Jenkins for continuous integration for the past five years. We started small and added more and more jobs. At first it was for default platform tests only, and it evolved to include tests on different OS, JDK or Databases, automatic release process, code coverage tools etc.. Then he went on the different issues we had because of the ever increasing number of jobs and how we &#8230; <a href="http://dev.blogs.nuxeo.com/2012/04/jenkins-user-conference-paris-2012.html" class="read_more">Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/headshot.png"><img class="alignright size-full wp-image-4474" src="http://dev.blogs.nuxeo.com/files/2012/04/headshot.png" alt="Jenkins" width="96" height="96" /></a></p>
<h4>Update:</h4>
<p> Julien&#8217;s video and slides are online on <a href="http://techtoc.tv/event/3742/conception-logicielle--design/editeurs-de-logiciels/jenkins-at-nuxeo" title="Jenkins at Nuxeo">techtoc.tv</a></p>
<p>Yesterday I was at the Paris Jenkins User Conference 2012 with <a title="Follow Julien on Github" href="https://github.com/jcarsique">Julien Carsique</a>. Julien was talking about how we use <a title="Jenkins CI" href="http://jenkins-ci.org/">Jenkins</a> at Nuxeo. For those of you who don&#8217;t know Jenkins, it&#8217;s a wonderful piece of software used to run and automate <a href="http://en.wikipedia.org/wiki/Continuous_integration" target="_blank">continuous integration</a> jobs. We previously wrote a <a title="[Monday Dev Heaven] Continuous Integration at Nuxeo" href="http://dev.blogs.nuxeo.com/2012/02/optimize-continuous-integration.html">blog</a> about this.</p>
<p>So about Julien&#8217;s presentation, you can check out the slides on <a href="http://www.nuxeo.com/en/resource-center/presentations/How-Nuxeo-uses-the-open-source-continuous-integration-server-Jenkins" target="_blank">nuxeo.com</a> or right here:</p>
<iframe src="http://www.slideshare.net/slideshow/embed_code/12585843" width="400" height="337" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br/><br/>
<p>He explained how Nuxeo has been using Jenkins for continuous integration for the past five years. We started small and added more and more jobs. At first it was for default platform tests only, and it evolved to include tests on different OS, JDK or Databases, automatic release process, code coverage tools etc.. Then he went on the different issues we had because of the ever increasing number of jobs and how we tried to solve them using for instance <a title="Crawl a jenkins build and report stats and graphs about the build flow" href="http://pypi.python.org/pypi/jenkviz/0.3.0">Jenkviz</a>. It&#8217;s a tool that crawls a jenkins build and reports stats and graphs about the build flow. It was pretty cool to get attention the attention of the creator of the Jenkins CI server on this subject , thanks <a href="http://kohsuke.org/" target="_blank">Kohsuke</a>!</p>
<blockquote><p>@kohsukekawa: I&#8217;m quite impressed at the degree of sophistication that Nuxeo setup is at. We need a super #JenkinsCI admin award for him!</p></blockquote>
<p>Looks like attendees were interested in what we had to say. Some also looked scared seeing our <a title="Jenkins - Nuxeo" href="http://qa.nuxeo.org/jenkins/">Jenkins dashboard</a> :-) . It&#8217;s true that it can look impressive but keep in mind that we started using Jenkins five years ago.</p>
<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/qa.nuxeo_.org_.png"><img src="http://dev.blogs.nuxeo.com/files/2012/04/qa.nuxeo_.org_-300x159.png" alt="Jenkins - Nuxeo Continuous Integration" title="Jenkins - Nuxeo Continuous Integration" width="300" height="159" class="aligncenter size-medium wp-image-4477" /></a></p>
<p>We also attended to some pretty cool talks, starting with a nice keynote from Kohsuke. Then we listened to <a title="Follow Nicolas on Github" href="https://github.com/ndeloof">Nicolas De Loof</a> and <a title="Follow Mathieu on Github" href="https://github.com/mathieuancelin">Mathieu Ancelin</a> who presented their <a title="Build Flow Plugin" href="https://wiki.jenkins-ci.org/x/bQ6MAw">Build-Flow Plugin</a>. It was really interesting. They showed us how to manage jobs pipeline using a groovy DSL. The syntax is simple and straightforward. It looks easy and efficient. Only drawback when using this system is that it replaces the existing triggers. So we won&#8217;t be able to use it with our current build setup.</p>
<p>Another talk got my attention. <a title="Follow Xavier on Github" href="https://github.com/xseignard">Xavier Seignard</a> from Pod Programming and <a title="Follow Mickael on Github" href="https://github.com/mickaelistria">Mickael Istria</a> from JBoss presented Tycho, Jenkins &amp; Sonar: The Eclipse Build Dream Team. It was nice to learn more about Tycho and to see that Eclipse (RCP/OSGI) apps works well with Jenkins and Sonar. And this was another good point about their presentation: they motivated us to test Sonar with <a title="Java Code Coverage Library" href="http://www.eclemma.org/jacoco/">JaCoCo</a>, a Java Code Coverage Library. It looked so simple to setup and use, we definitely must try it at Nuxeo! Then I had a small chat with them, it was nice meeting you guys :)</p>
<p>Overall we had a great time, it was cool to see that much people into Jenkins. Hope there will be even more attendees next year. Congrats to <a title="Cloudbees" href="http://www.cloudbees.com/">Cloudbees</a> for the organization! Next conference is <a href="http://www.devoxx.com/display/DV11/Home" target="_blank">Devoxx</a> France tomorrow and Friday, maybe we&#8217;ll see you there !</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/04/jenkins-user-conference-paris-2012.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

