Friday, July 31, 2009

Generic JCR DAO with Jackrabbit OCM

There is an GenericHibernateDao in Appfuse project. It is save a lot of code to do CRUD database operation (Thanks to the great Object-Relational Mapping (ORM) framework hibernate, and spring framework of course).

In Java Content Repository world, there is Object Content Mapping (OCM) framework, Jackrabbit OCM. I translate GenericHibernateDao into GenericJcrDao (with Spring module jcr):
The interface:

import java.util.Collection;

public interface GenericJcrDao {

public Object findByUUID(String uuid);

public Collection getAll();

public Collection getAllInScope(String scope);

public Object findByPath(String path);

public T save(T object);

public Collection findByProperty(String propertyName, String value);

public void remove(final T object);

public String exportXML(String path);
}


The implementation:


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;

import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.ocm.exception.JcrMappingException;
import org.apache.jackrabbit.ocm.manager.ObjectContentManager;
import org.apache.jackrabbit.ocm.query.Filter;
import org.apache.jackrabbit.ocm.query.Query;
import org.apache.jackrabbit.ocm.query.QueryManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springmodules.jcr.JcrCallback;
import org.springmodules.jcr.jackrabbit.ocm.JcrMappingCallback;
import org.springmodules.jcr.jackrabbit.ocm.JcrMappingTemplate;

public class GenericDaoJcrImpl implements GenericJcrDao {

@Autowired
@Qualifier("jcrMappingTemplate")
protected JcrMappingTemplate jcrMappingTemplate = null;

public void setJcrMappingTemplate(JcrMappingTemplate jcrMappingTemplate) {
this.jcrMappingTemplate = jcrMappingTemplate;
}

protected final Log log = LogFactory.getLog(getClass());
private Class persistentClass;

/**
* Constructor that takes in a class to see which type of entity to persist
*
* @param persistentClass
* the class type you'd like to persist
*/
public GenericDaoJcrImpl(final Class persistentClass) {
this.persistentClass = persistentClass;
}

@SuppressWarnings("unchecked")
@Override
public T findByUUID(final String uuid) {
return (T) jcrMappingTemplate.execute(new JcrMappingCallback() {

public Object doInJcrMapping(ObjectContentManager manager)
throws JcrMappingException {

return manager.getObjectByUuid(uuid);
}
});
}

@SuppressWarnings("unchecked")
public Collection getAll() {
QueryManager queryManager = jcrMappingTemplate.createQueryManager();
Filter filter = queryManager.createFilter(persistentClass);

Query query = queryManager.createQuery(filter);
return (Collection) jcrMappingTemplate.getObjects(query);
}

public T save(final T object) {
jcrMappingTemplate.execute(new JcrMappingCallback() {

public Object doInJcrMapping(ObjectContentManager manager)
throws JcrMappingException {

manager.insert(object);
manager.save();

return null;

}
});
return object;

}

public void update(final T object) {
jcrMappingTemplate.execute(new JcrMappingCallback() {

public Object doInJcrMapping(ObjectContentManager manager)
throws JcrMappingException {
manager.update(object);
manager.save();
return null;
}
});

}

public void remove(final T object) {
jcrMappingTemplate.execute(new JcrMappingCallback() {

public Object doInJcrMapping(ObjectContentManager manager)
throws JcrMappingException {
manager.remove(object);
manager.save();
return null;
}
});
}

public Object findByPath(String path) {
return jcrMappingTemplate.getObject(path);
}

@SuppressWarnings("unchecked")
public Collection findByProperty(String propertyName, String value) {
QueryManager queryManager = jcrMappingTemplate.createQueryManager();
Filter filter = queryManager.createFilter(persistentClass);
filter.setScope("//");
filter.addEqualTo(propertyName, value);
Query query = queryManager.createQuery(filter);
Collection result = jcrMappingTemplate.getObjects(query);
return (Collection) result;
}

@SuppressWarnings("unchecked")
@Override
public Collection getAllInScope(String scope) {
QueryManager queryManager = jcrMappingTemplate.createQueryManager();
Filter filter = queryManager.createFilter(persistentClass);
filter.setScope(scope);
Query query = queryManager.createQuery(filter);
return (Collection) jcrMappingTemplate.getObjects(query);
}

@Override
public String exportXML(final String path) {
final OutputStream out = new ByteArrayOutputStream();
jcrMappingTemplate.execute(new JcrCallback() {

public Object doInJcr(Session session) throws IOException,
RepositoryException {

session.exportDocumentView(path, out, true, false);
return out;
}

});
return out.toString();
}

}

Thursday, July 30, 2009

JSP Taglib :attribute xml does not accept any expressions

I suffered "attribute xml does not accept any expressions" exception when use jstl xml tag to transform xml. This exception is caused by nested EL expression in the xml tag:






I googled about the solution for "attribute xml does not accept any expressions" exception. Some one said it might be the old version jsp taglib's problem. I read my code again and again, finally find out the problem.

The jsp taglib I used is 1.1.2


taglibs
standard
1.1.2


This jar shipped a lot of TLD declaration. The mistake I made is delcared an old version:
<%@ taglib prefix="x" uri="http://java.sun.com/jstl/xml" %>


to use the new version, the declaration should be:

<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>


Here is the detail explanation.

Monday, July 27, 2009

Tomcat Symbolic link folders

One of my project need to show a lot of pictures of products. So keep the pictures at webapp directory is not a good idea. I still have problem to configure apache http server to work with tomcat. Alternatively, I choose the symbolic link folder solution. The picture folder is separately on other directory and create an symbolic link in the webapp directory. Here is the solution:

1. Enable your webapp symbolic linkable:

create "context.xml" follow the directory structure:
"webapp/META-INF/context.xml"
with the content:




Now the webapp is symbolic-able as deployed.

2. create the symbolic

The product pictures is in "/home/ke/products"

cd the webapp directory and use this command to create link:
sudo ln -s home/ke/products /usr/local/tomcat6/webapps/mywebapp/images/products


3. In the JSP file, the products pictures can be referred as:




Thursday, July 23, 2009

Unofficial Maven Repository for Spring Modules Jcr 0.9 with Ocm patch

It is never easy to survive in the open source world. I'm getting back to Java Content Repository. It took me long time to get Spring JCR modules running since "Jackrabbit OCM in Spring still hasn’t found a home". The source code can be downloaded from here:
http://jira.springframework.org/browse/MOD-446


As a Maven enthusiast, I create a maven repository use the subversion repository provided by Google Code. Please use it properly, I only provide it for your convenience.
1. add my unofficial repository:)



absorbx
http://absorbx.googlecode.com/svn/trunk/repo



2. Add Spring modules jcr dependency:


org.springmodules
spring-modules-jcr
0.9



(The patched spring-modules-jcr-0.9 source code is included. )

Tuesday, July 14, 2009

Practical Spring Security JSP Taglibs

Some practical examples show you how to use Spring security jsp taglibs, <sec:authorize> and <sec:authentication>, in the real project.


1. Print out greeting information.

Welcome, 


It is also safe to print some extend properties, for example, email:


email: 


2.Show menu according to user's role:

Only show user list and delete to role as "ROLE_ADMIN".
(Please notice that property name should be "ifAllGranted")

  • Delete User
  • List users


  • 3. Nested
    Show the welcome information if user is logined.
    (Please notice that property name should be "ifAllGranted")

    
    welcome,  logout
    
    

    If no user login, show the login link.
    (Please notice that property name should be "ifNotGranted")

    
    please login: login
    
    

    4. Use with other JSTL tag

    check if the current logged in user if is the author of the post, if true, show "edit" link. And if the current user has Manager role, also show the edit link.


    
         
     
    
     
        
      
              
              
               
               
    

    Monday, July 6, 2009

    Java Date to Javascript Date

    In JavaScript, a specific date can be created via:

    var yesterday= new Date(2009,7,6);


    What if we need to create javascript Date based value fetched from database via Java?
    Apprently, split String is not a good idea.:)


    //create a javaScript Date object, is current date.
    var date = new Date();
    //set date string use JSTL tag
    var dateString="";
    //let javaScript parse this string and set the date.
    date.setTime(Date.parse(dateString));

    Friday, July 3, 2009

    Install Mysql and enable remote access on Ubuntu

    1. Install mysql

    sudo apt-get install mysql-server


    2. Bind mysql to your public IP address
    edit mysql config file:
    sudo vi /etc/mysql/my.cnf

    change "bind-address" to public IP address
    bind-address = 123.456.789

    3. grant privileges
    GRANT ALL PRIVILEGES ON *.* TO 'root'@'123.456.789%' IDENTIFIED BY 'password' WITH GRANT OPTION;


    4. restart mysql
    sudo /etc/init.d/mysql restart

    Thursday, July 2, 2009

    use google code as your public maven repository

    It is hard to develop project without Maven. However, not all projects submit their jar into public maven repository. We can install them into our local repository. But it does not ease development with team members since every one has to install it on their local repository. Thanks to google code, we can setup an public maven repository.

    1. Install jar into local repository to get the directory structure

    mvn install:install-file -Dfile=path-to-your-artifact-jar \
    -DgroupId=your.groupId \
    -DartifactId=your-artifactId \
    -Dversion=version \
    -Dpackaging=jar \
    -DcreateChecksum=true


    2. Import the installed artifact into your google project via subversion
    From: C:/Documets and Settings/user/.m2/repository/
    to : https://yourproject.googlecode.com/svn/trunk/repo

    3. Tell maven your semi-public repository:)
    
    
    your.groupid
    http://yourproject.googlecode.com/svn/trunk/repo
    
    
    

    Now, other team members don't need setup their local repository anymore.

    Wednesday, July 1, 2009

    How to pass data from JSP to javascript

    A friend asked me what is the best way to pass data from JSP to Javascript. I'm not sure if this is the best way, but the way I used.

    1. single value:

    var name="${name}";


    if there is attribute "name", this line will be:
    var name="Ke CAI";

    if does not exist:
    var name;

    2. Collection to javascript array:
    It's not a good idea to append string use iteration. Here is the code I draw pie chart use google visualization api.


    var data = new google.visualization.DataTable();
    data.addColumn('string', 'StyleNo');
    data.addColumn('number', 'Quantity');
    var dataArray= new Array();


    dataArray[${status.index}]=['${item.styleno}',${item.total}];

    data.addRows(dataArray);


    This will be translated into:

    var dataArray= new Array();

    dataArray[0]=['7312J',14];

    dataArray[1]=['7311C',7];