<?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, 14 May 2012 20:05:54 +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 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>
		<item>
		<title>[Monday Dev Heaven] How to add an HTML preview for iWork Pages files</title>
		<link>http://dev.blogs.nuxeo.com/2012/04/monday-dev-heaven-add-html-preview-iworks-pages-files.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/04/monday-dev-heaven-add-html-preview-iworks-pages-files.html#comments</comments>
		<pubDate>Mon, 09 Apr 2012 22:11:52 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[ECM]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Monday Dev Heaven]]></category>
		<category><![CDATA[Nuxeo]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4467</guid>
		<description><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/iwork-logo.png"><img class=" wp-image-4469 alignright" src="http://dev.blogs.nuxeo.com/files/2012/04/iwork-logo.png" alt="" width="209" height="121" /></a>Last week I got slightly frustrated when I received a .pages file that I could not open with any software on my Ubuntu system. And I could not see a preview on Nuxeo because this format is currently not supported. For those who have never heard about &#8220;.pages&#8221; files, they are documents made using the Apple iWork Pages application, which has its own format.  With the growing population of MacOS users, this will surely happen again. But fear not, because today I will show you how to create your own file converters on a Nuxeo application so that you can, for instance, add an HTML preview for the iWork files without having to install anything on your laptop.</p>
<h2>What&#8217;s your file&#8217;s mime-type?</h2>
<p>A first and mandatory step to deal with files in Nuxeo is to be sure you&#8217;ll get the right mime-type. I&#8217;ve first tried to upload a Pages file into &#8230; <a href="http://dev.blogs.nuxeo.com/2012/04/monday-dev-heaven-add-html-preview-iworks-pages-files.html" class="read_more">Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://dev.blogs.nuxeo.com/files/2012/04/iwork-logo.png"><img class=" wp-image-4469 alignright" src="http://dev.blogs.nuxeo.com/files/2012/04/iwork-logo.png" alt="" width="209" height="121" /></a>Last week I got slightly frustrated when I received a .pages file that I could not open with any software on my Ubuntu system. And I could not see a preview on Nuxeo because this format is currently not supported. For those who have never heard about &#8220;.pages&#8221; files, they are documents made using the Apple iWork Pages application, which has its own format.  With the growing population of MacOS users, this will surely happen again. But fear not, because today I will show you how to create your own file converters on a Nuxeo application so that you can, for instance, add an HTML preview for the iWork files without having to install anything on your laptop.</p>
<h2>What&#8217;s your file&#8217;s mime-type?</h2>
<p>A first and mandatory step to deal with files in Nuxeo is to be sure you&#8217;ll get the right mime-type. I&#8217;ve first tried to upload a Pages file into our intranet but it was detected as a zip file. A quick look at the mime-type using the so called mime-type command confirmed I was dealing with a zip file:</p>
<pre class="brush: bash; title: ; notranslate">
[~]$ mimetype hello.pages
hello.pages: application/zip
</pre>
<p>So I have to add a small contribution to the <a title="MimetypeRegistryService on Nuxeo Platform Explorer" href="http://explorer.nuxeo.org/nuxeo/site/distribution/current/viewComponent/org.nuxeo.ecm.platform.mimetype.service.MimetypeRegistryService">MimetypeRegistryService</a>. Details are as usual on explorer.nuxeo.org .</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;extension
    target=&quot;org.nuxeo.ecm.platform.mimetype.service.MimetypeRegistryService&quot;
    point=&quot;extension&quot;&gt;
   &lt;fileExtension name=&quot;pages&quot; mimetype=&quot;application/vnd.apple.pages&quot; ambiguous=&quot;false&quot; /&gt;
  &lt;/extension&gt;
</pre>
<p>This code will make sure that each time a Pages file is uploaded in Nuxeo, its mime-type will be set to &#8216;application/vnd.apple.pages&#8217;. Now that I know what kind of file I&#8217;m dealing with, I can start using converters.</p>
<h2>An introduction to converters</h2>
<p>A Pages file is basically a zip file containing all of its different assets, such as images and some XML files for the content. But the good thing is that sometimes, the zip also contains a preview folder, itself containing a pdf preview of the document. This is just perfect for our needs. I will create a &#8220;pages2PDF&#8221; converter.</p>
<p>A <a title="Converter service" href="http://explorer.nuxeo.org/nuxeo/site/distribution/current/viewComponent/org.nuxeo.ecm.core.convert.service.ConversionServiceImpl">converter</a> can be added as usual through an extension point.</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;extension target=&quot;org.nuxeo.ecm.core.convert.service.ConversionServiceImpl&quot;
    point=&quot;converter&quot;&gt;

    &lt;converter name=&quot;pages2pdf&quot; class=&quot;org.nuxeo.ecm.platform.convert.plugins.Pages2PDFConverter&quot;&gt;
      &lt;destinationMimeType&gt;application/pdf&lt;/destinationMimeType&gt;
      &lt;sourceMimeType&gt;application/vnd.apple.pages&lt;/sourceMimeType&gt;
    &lt;/converter&gt;

  &lt;/extension&gt;
</pre>
<p>It basically comes down to three things. We need a <em>sourceMimeType</em>, a <em>destinationMimeType</em> and a Java Class to handle the conversion. We can have as many <em>sourceMimeType</em>s as we want. A classic example would be the <em>any2pdf</em> converter that can take XML, HTML, plain text, RTF or any other LibreOffice supported format. We will choose the Pages mimeType &#8216;application/vnd.apple.pages&#8217;. Then we want only one <em>destinationMimeType</em>: &#8216;application/pdf&#8217;. The goal of our Java Class will be to take a Pages file as input and return a pdf file. This class must implement the <em>Converter</em> interface. That makes two methods to implement: <em>init</em> and <em>convert</em>.</p>
<p>As stated in the documentation, <em>init</em> can be used to retrieve some configuration information from the <em>XMap</em> descriptor. I can already tell you that we don&#8217;t need any options so my <em>init</em> implementation will be empty.</p>
<p>The<em> convert</em> method gives us a <em>BlobHolder</em> and a parameter<em> Map</em> and must return another <em>BlobHolder</em>. So all we have to do is look for the pdf preview in the Pages file, extract it and return it as a <em>BlobHolder</em>. Here&#8217;s what I did:</p>
<pre class="brush: java; title: ; notranslate">
public class Pages2PDFConverter implements Converter {

    private static final String PAGES_PREVIEW_FILE = &quot;QuickLook/Preview.pdf&quot;;

    @Override
    public BlobHolder convert(BlobHolder blobHolder,
            Map&lt;String, Serializable&gt; parameters) throws ConversionException {
        try {
            // retrieve the blob and verify its mimeType
            Blob blob = blobHolder.getBlob();
            String mimeType = blob.getMimeType();
            if (mimeType == null || !mimeType.equals(&quot;application/vnd.apple.pages&quot;)) {
                throw new ConversionException(&quot;not a pages file&quot;);
            }
            // look for the pdf file
            if (ZipUtils.hasEntry(blob.getStream(), PAGES_PREVIEW_FILE)) {
                // pdf file exist, let's extract it and return it as a
                // BlobHolder.
                InputStream previewPDFFile = ZipUtils.getEntryContentAsStream(
                        blob.getStream(), PAGES_PREVIEW_FILE);
                Blob previewBlob = new FileBlob(previewPDFFile);
                return new SimpleCachableBlobHolder(previewBlob);
            } else {
                // Pdf file does not exist, conversion cannot be done.
                throw new ConversionException(
                        &quot;Pages file does not contain a pdf preview.&quot;);
            }
        } catch (Exception e) {
            throw new ConversionException(
                    &quot;Could not find the pdf preview in the pages file&quot;, e);
        }
    }

    @Override
    public void init(ConverterDescriptor descriptor) {
    }
}
</pre>
<p>Now we can convert a Pages file to a pdf. But to be able to preview it, it must be in HTML. So the next logical step is to make a &#8216;pages2html&#8217; converter.</p>
<h2>PagesToHMTL converter for the preview service</h2>
<p>A very cool feature about the converters is that they can be chained. If I want a &#8216;pages2html&#8217; converter, I can have it by first converting the Pages file to a pdf, and then converting the pdf to HTML. This contribution would look like this:</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;extension target=&quot;org.nuxeo.ecm.core.convert.service.ConversionServiceImpl&quot;
    point=&quot;converter&quot;&gt;

    &lt;converter name=&quot;pages2html&quot;&gt;
      &lt;conversionSteps&gt;
        &lt;subconverter&gt;pages2pdf&lt;/subconverter&gt;
        &lt;subconverter&gt;pdf2html&lt;/subconverter&gt;
      &lt;/conversionSteps&gt;
    &lt;/converter&gt;

  &lt;/extension&gt;
</pre>
<p>We now have our &#8216;pages2html&#8217; converter, which means Pages files will be previewable in Nuxeo. That&#8217;s it for today. If you have any questions, use the comments section or go to <a title="Nuxeo Answers" href="http://answers.nuxeo.com/">answers.nuxeo.com</a>. See you on Friday!</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/04/monday-dev-heaven-add-html-preview-iworks-pages-files.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[Q&amp;A Friday] Nuxeo WCM, blogs, wikis.</title>
		<link>http://dev.blogs.nuxeo.com/2012/04/qa-friday-nuxeo-wcm-blogs-wikis.html</link>
		<comments>http://dev.blogs.nuxeo.com/2012/04/qa-friday-nuxeo-wcm-blogs-wikis.html#comments</comments>
		<pubDate>Fri, 06 Apr 2012 18:10:46 +0000</pubDate>
		<dc:creator>Laurent Doguin</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[ECM]]></category>
		<category><![CDATA[Friday Q&A]]></category>
		<category><![CDATA[Nuxeo]]></category>

		<guid isPermaLink="false">http://dev.blogs.nuxeo.com/?p=4465</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="Nuxeo WCM, blogs, wikis" width="157" height="123" /></a><p class="wp-caption-text">Nuxeo WCM, blogs, wikis</p></div>
<p>Cool question asked by Nelson Silva: what about Blogs, Wikis, and WCM features? We get this question a lot actually. Publishing the content you manage in your ECM on the web seems perfectly legit. And there are as of now many different ways to do this in the Nuxeo Platform. You can use the publishing features with WebEngine, and you can create small Blogs and Wiki documents. These can be seen as light features compared to full-fledged WCM solutions and they are indeed! Nuxeo as a vendor won&#8217;t take the path to becoming a WCM solution with complex features like multilingual web publishing, portal management, online marketing capabilities, and personalization. You&#8217;d be much better off with a best-of-breed WCM solution connected to Nuxeo through CMIS or Content Automation APIs, if your project requires advanced WCM capabilities.</p>
<p>However, some WCM features or Web Publishing features in Nuxeo &#8230; <a href="http://dev.blogs.nuxeo.com/2012/04/qa-friday-nuxeo-wcm-blogs-wikis.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="Nuxeo WCM, blogs, wikis" width="157" height="123" /></a><p class="wp-caption-text">Nuxeo WCM, blogs, wikis</p></div>
<p>Cool question asked by Nelson Silva: what about Blogs, Wikis, and WCM features? We get this question a lot actually. Publishing the content you manage in your ECM on the web seems perfectly legit. And there are as of now many different ways to do this in the Nuxeo Platform. You can use the publishing features with WebEngine, and you can create small Blogs and Wiki documents. These can be seen as light features compared to full-fledged WCM solutions and they are indeed! Nuxeo as a vendor won&#8217;t take the path to becoming a WCM solution with complex features like multilingual web publishing, portal management, online marketing capabilities, and personalization. You&#8217;d be much better off with a best-of-breed WCM solution connected to Nuxeo through CMIS or Content Automation APIs, if your project requires advanced WCM capabilities.</p>
<p>However, some WCM features or Web Publishing features in Nuxeo could totally make sense and might happen!</p>
<p>So as Alain said, if you need to build a WCM-like feature:</p>
<blockquote><p>There is no &#8220;ready-to-use&#8221; bundle. Each Nuxeo project that has a &#8220;Content Management&#8221; flavor faces many options :<br />
- for front-end templating engine (JSF based? WebEngine based? other language based ? Leveraging NX Themes? )<br />
- Content/Structure model (Generic articles? more personalized objects?)<br />
- publishing pattern (ACL based? Source/Proxy based? Using lifecycle?).</p></blockquote>
<p>And it would certainly be good for Nuxeo to have a more advanced technical solution for each of these options. Here we would love input and potentially contributions from the community! Please bring your ideas and code, this is an official call to the community :) If you guys want to see WCM-like features in Nuxeo or on the Nuxeo Marketplace, we really want to talk more about this. We  need your input to organize the different light WCM-like features each of us would like to see integrated in Nuxeo.</p>
<p>There is another real reason why people could expect WCM based on Nuxeo. Now that I explained why we don&#8217;t focus at Nuxeo on this, I should reiterate that Nuxeo&#8217;s main mission is to provide a platform for developers to build content-centric applications, and certainly a WCM solution is a content-centric application. So YES a WCM solution made out of Nuxeo would make sense and be awesome. However, it is simply not Nuxeo&#8217;s mission to focus on this one. But if a new Application Builder partner wants to focus on that &#8212; I think it would be a very good idea to compete in the WCM arena. In that respect, I can only invite you to check out what people like Stepnet did with their solution SmartMedia. Although this is not WCM &#8212; it&#8217;s an editorial and publishing platform &#8212; it&#8217;s still very impressive!</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.blogs.nuxeo.com/2012/04/qa-friday-nuxeo-wcm-blogs-wikis.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

