Tag: Java

Tip: How to move an Alfresco category

Alfresco has a category hierarchy that can be used to categorize content. Unlike tags, which are not in a hierarchy and can be created by anyone, categories must be managed by an administrator. But even an administrator cannot move a category from one parent to another through the user interface. When it is time to reorganize your categories, how do you do it?

It’s actually pretty easy to do this with code. Your first thought might be, “Well, a category is a node and server-side JavaScript can work with nodes, so I’ll just write a quick script to do the move,” and who could blame you–that’s a well-reasoned line of thinking. But if you look at the source for the current JavaScript API ScriptNode object’s “move” method, you’ll see that it assumes that the association it is creating is “cm:contains”. Categories are associated with an association called “cm:subcategories”, not “cm:contains”. So, at least in this release, JavaScript can’t help us.

Luckily, Alfresco’s Java API is up to the task. When you call the NodeService’s moveNode method you have full control over the new relationship that gets created.

For stuff like this it is often handy to whip up a little Java-backed web script. All the web script needs is the source node reference that needs to be moved and a target node reference to move the source node reference to. Here’s the class with debug and parameter checking removed:

public class MoveCategory extends DeclarativeWebScript {

  // Dependencies
  private NodeService nodeService;

  @Override
  protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {

    final String sourceNodeRefString = req.getParameter("sourceNodeRef");
    final String targetNodeRefString = req.getParameter("targetNodeRef");

    // snag the nodes
    NodeRef sourceNodeRef = new NodeRef(sourceNodeRefString);
    String sourceName = (String) nodeService.getProperty(
                                   sourceNodeRef,
                                   ContentModel.PROP_NAME);
    NodeRef targetNodeRef = new NodeRef(targetNodeRefString);
    String targetName = (String) nodeService.getProperty(
                                   targetNodeRef,
                                   ContentModel.PROP_NAME);

    // move the source node to the target
    nodeService.moveNode(sourceNodeRef,
                         targetNodeRef,
                         ContentModel.ASSOC_SUBCATEGORIES,
                         QName.createQName(
                           NamespaceService.CONTENT_MODEL_1_0_URI,
                           sourceName));

    // set up the model
    Map<String, Object> model = new HashMap<String, Object>();
    model.put("sourceNodeRef", sourceNodeRefString);
    model.put("sourceName", sourceName);
    model.put("targetNodeRef", targetNodeRefString);
    model.put("targetName", targetName);

    return model;
  }

  public void setNodeService(NodeService nodeService) {
    this.nodeService = nodeService;
  }

}

If you need to see how to wire up the web script with Spring configuration, or you want to see the rest of the web script files (like the descriptor & view), you can take a look at this zipped up Eclipse project.

I should mention that in my web script descriptor, I configured the web script to require an authenticated user, but I set it to run as admin. That gives non-admin users the ability to move categories around using this web script. You may or may not want to do that.

Also, because this is just an example, I’m using the zip overlay method of deployment. For production, you should be using AMPs.

For more Java-backed web script examples, see this wiki page. And if you would prefer to use Maven to develop your Java-backed web scripts, take a look at this project on Google Code.

Can GateIn, the new JBoss Portal/eXo Portal combination, outshine Liferay?

I know I’m way behind on this. I’m kind of surprised at how little attention it has received. Maybe I need to refresh my portal-based news feeds. In any case, earlier this Summer, JBoss and eXo announced they would be combining the JBoss Portlet Container with eXo Portal to create a new project called GateIn. Other than the similarity between the concepts “portal” and “gate” I’m not sure what they are going for with the name, but don’t let that throw you off. To get an idea of what it’s about, check out the demo.

Most of our clients looking for open source Java portals have been interested in either JBoss Portal or Liferay. In choosing between the two, one consideration was that, historically, JBoss Portal has been less about out-of-the-box portlets and flashy UI and more about providing a presentation framework. Clients developing solutions that were really 100% custom apps with a portal-like interface leaned toward JBoss Portal (especially if they were already a JBoss shop). Clients looking for more of an “instant community” with ease-of-use on the configuration side and a large number of out-of-the-box portlets leaned more toward Liferay. GateIn appears to be a big step forward for JBoss Portal in terms of the user experience for portal administration and makes JBoss Portal about more than just a framework for presentation services.

Beyond requiring a great user experience for both end users (site consumers) and portal administrators (content managers), portals must also have a fast and intuitive development model. I think this is especially true lately as lighter-weight presentation frameworks have become more popular. As the difference in capabilities between portal and non-portal presentation frameworks becomes less and less, portals can’t afford to offer a soul-sucking development experience.

I haven’t spent any time customizing GateIn so I can’t comment on the developer experience. What I do know is that when you move from developing code using lightweight frameworks like Drupal or Django to Java portal servers like Liferay, you feel the increased complexity immediately. Anti-Java-ites will say that a lot of the complexity in the development experience is there because it’s Java and it will always be that way. I don’t think that’s true–look at frameworks like Grails and Wicket.

The point is, for GateIn to be a serious challenger to Liferay, they’ll need to provide not only the eye candy on the front-end, but also a developer experience that approaches the productivity level we can get with non-portal frameworks. If they can do that, they have a chance against Liferay. Of course even if they manage to do that, they are still up against the “Do we really need a portal server to do this?” undercurrent that threatens both projects. But that’s another blog post.

Google App Engine Now Supports Java

I’ve been playing with the newly-released Java support in Google App Engine and it is pretty cool. You can do more than I expected you could:

  • The Google App Engine Eclipse plug-in gives you a template project and associated config files, Ant build scripts, a deployment tool, and a local run-time environment that acts like GAE (user service, data store, limitations imposed by the platform).
  • You’ve got full persistence and query capability via JDO. You pretty much just model your entities as POJO’s, then you annotate the fields in those classes as “persistent” and you’re good to go. You do JDOQL to query your objects. Queries will only return the first 1000 results.
  • You can run cron jobs. A cron job wakes up on a schedule and invokes a URL you specify.
  • Servlets and JSPs are supported but you can also use things like Struts and Spring (See Will it Work in Google App Engine?).
  • You can take advantage Google’s User service, which means anyone with a Google account can sign-in to your app without creating a new account.
  • You can take advantage of Memcache if you need it (JCache).
  • You can fetch URLs via the URL Fetch service or java.net.URLConnection.
  • You can send mail via JavaMail.
  • You can use their Image service to resize, rotate, flip, and crop images.
  • Both JDK 5 and JDK 6 are supported.

There are some limits:

  • Execution of requests is limited to 30 seconds and that includes URLs invoked by cron jobs.
  • You can’t write to the file system. If you need to write out files, I assume you’d use S3 or something.
  • You can’t open sockets.
  • Each developer can create up to 10 applications and apps can’t be deleted so don’t fill up on Hello Worlds.
  • You can run an app that has up to 500 MB of storage and serves 5 million page views per month at no cost.

The beauty, obviously, is that as a developer, you get to focus on the code and let Google worry about scaling. For many applications, this Platform-as-a-Service (PaaS) will be preferred over Infrastructure-as-a-Service (IaaS). In an IaaS setup, you can use solutions like RightScale to automatically provision new nodes to handle spikes in demand, but you still have to set that up. Plus, you’ve got the additional cost and headache of installing, configuring, and maintaining the application server and database software (and making sure it is set up to work when new nodes are auto-provisioned). With the app engine, scaling globally is pretty simple: Step 1 – Write (Good) Code; Step 2 – Deploy Code to GAE.