Friday, January 20, 2012

Advanced QBE pattern (common using generics)

On previous post I introduced the QBE pattern.

The pattern saves us a lot of tedious binding code.
However, one still need to implement the same method for each Entity.

To save us the redundant work of defining the same QBE method for each entity, where only the entity is changed, we could utilize Generics.

Using Generics we will implement only one method in a base class, and each concrete QBE (on certain @Entity) will inherit from that base class.


Lets see that in action.

First, we define the interface for the base class:

public interface BaseDAO {

   

    /**
     * Perform a query based on the values in the given object.
     * Each (String) attribute will be searched based on the Like comparison.
     * Comply the QueryByExample (QBE) pattern
     * @param modelEntity The Entity with values to search
     * @param propertiesToExclude Any property which the search will ignored.
     * @return Instances that answer the given parameters values (empty if none)
     */
    public List getByElementsLike(T modelEntity, List propertiesToExclude);   

    /**
     * Perform a query based on the values in the given object.
     * Each attribute will be searched based on the Equality comparison.
     * Comply the QueryByExample (QBE) pattern
     * @param modelEntity The Entity with values to search
     * @param propertiesToExclude Any property which the search will ignored
     * @return Instances that answer the given parameters values (empty if none)
     */
    public List getByElementsEqual(T modelEntity, List propertiesToExclude);

}



 Second step is to write the Base class implementation

public class BaseDaoImpl implements BaseDAO {
//Get DB session access using Spring 3.1 Entity Manger
     @PersistenceContext
    protected EntityManager em;
  
    protected Class entityClass;

   
     //Initialize the entity class
     @SuppressWarnings("unchecked")
    public BaseRepositoryImpl() {
            ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
            this.entityClass = (Class) genericSuperclass.getActualTypeArguments()[0];
        }

    protected Class getEntityClass() {
        return entityClass;
    }   
  

    public List getByElementsLike(T modelEntity,List propertiesToExclude) {

        // get the native hibernate session
        Session session = (Session) em.getDelegate();

        // create an example from our model-entity, exclude all zero valued numeric properties
        Example example = Example.create(modelEntity).excludeZeroes().enableLike(MatchMode.ANYWHERE);

        for (String property : propertiesToExclude) {
            example.excludeProperty(property);
        }       

        // create criteria based on the customer example
        Criteria criteria = session.createCriteria(getEntityClass()).add(example);

        // perform the query       
        return criteria.list();

    }

    public List getByElementsEqual(T modelEntity,List propertiesToExclude) {

        // get the native hibernate session
        Session session = (Session) em.getDelegate();

        // create an example from our customer, exclude all zero valued numeric properties
        Example example = Example.create(modelEntity).excludeZeroes();

        for (String property : propertiesToExclude) {
            example.excludeProperty(property);
        }   

        // create criteria based on the customer example
        Criteria criteria = session.createCriteria(getEntityClass()).add(example);

        // perform the query       
        return criteria.list();
    }

}


Third step is to extend the base class:
@Entity

public class Order{
..
}

 

@Entity
public class Item{
..
}

 
public class OrderDaoImpl extends BaseDaoImpl implements
        BaseDao{

//No need to implement the QBE again here

}

public class ItemDaoImpl extends BaseDaoImpl implements
        BaseDao{

//No need to implement the QBE again here

}


Kindly let me know for any further improvements.

QBE pattern

When writing an enterprise system, there is a common pattern of a user who fill in a search form and get a corresponding result based on the given search parameters.

Handling this request manually in the backend is a bit tedious since for every search parameter, the developer need to check if the user insert a value and if so, concatenate the corresponding string into the WHERE clause in the SQL.

The Query By Example (QBE) pattern is a pattern that helps deal with the mentioned task.

It is implemented by ORM frameworks (such as Hibernate) and also avlaiable as part of possible to implement utilizing the the spec in JPA 2.0 (as seen in OpenJPA project)

The QBE implementation expect the model instance (the object which is annotated with @Entity).
That instance should have the form search values in it.
Than the implementation  framework does all the SQL wiring magic and save us the tedious work.
So at the end we just return the query result.

Lets discuss a case where a user want to query the Order object.

The Order class need to be annotated with @Entity


@Entity
public class Order{
..
}

Using a Hibernate implementation :
public List findByOrderElements(Order order) {

 Session session = getSession();

//Hibernate assembles the query with the given entity to query
 Example example = Example.create(order) //create Example object given the instance to query
     .enableLike(MatchMode.ANYWHERE) //optional parameters
     .excludeZeroes()
     .ignoreCase();

//Get the query result
 List result = session.createCriteria(Order.class)
     .add(example)
     .list();
        
 return result;
}


That's it...

Important note:
  • QBE will only work on one object (won't help in case the form input has properties of other related fields, i.e.  requires join)
  • Version properties, identifiers and associations are ignored (if QBE would consider the id than it would match only one instance...)

For even more advanced stuff regarding QBE pattern, please follow my next post.

Thursday, December 29, 2011

Unit Test on Spring via Maven - configuration tips



 This post is for newbies who set their project to run Spring powered Unit Tests via Maven.

There are many blogs who mention how to do it.
I would recommend to install STS IDE and create new Spring Template project.
It usually comes with built in Test package. The test package can be executed via JUnit.

The tricky part comes when you want to run the tests via Maven and set the Spring configuration xml file in your custom folder.

Using default setting, Maven might raise an exception complaining the Spring xml configuration file could not be found or Tests could not be found.

So, my two cents are:
cent 1: Make sure your test classes ends with Test (and not ending with Tests, for example, as it comes with the Spring default project)
cent 2: configuration can be resolved while defining the spring configuration path.
 The trick is to use the relative location as it is in the source folder, and not in the target compilation folder. Also note to use backslash as folder separation and not dots.

Configuration using classpath relative path:

@ContextConfiguration (value = "classpath:/com/company/app/OrderPersistenceTests-context.xml")

 @RunWith(SpringJUnit4ClassRunner.class)

public class OrderPersistenceTest {

...

}

or

Configuration using project relative path:

@ContextConfiguration (value = "file:src/test/resources/com/company/app/OrderPersistenceTests-context.xml ") 
@RunWith(SpringJUnit4ClassRunner.class)
public class OrderPersistenceTest {



...

} 


Run tests using maven:
If pom.xml has the skipTest tag with true as value, e.g.:

       

            

                org.apache.maven.plugins

                maven-surefire-plugin

                2.6

                 

                1.5

                1.7

               true

            

            

...


...

Then no test will be executed, even when explicitly executing maven with test goal


Good luck !

Friday, November 25, 2011

How to install (Go Daddy) certificate on Tomcat/Ubunto

Recently I spent a lot of time installing new certificate I bought from GoDaddy on my Tomcat server.
Although this process should be common, I could not create certificate chain via java keytool.
At the end I found that the GoDaddy documentation was lacking some basic info and I needed to find it my self.

So, for any of you who bought certificate via GoDaddy and need to deploy it into tomcat, here is the complete guide:

1. Create new public/private key (key pair) via keytool
Notes:
- It is important to provide complete path to keytool. Verify it located in the same JRE folder tomcat use.
- Mind the alias name, we need to keep consistency with the next steps.
script:
/complete/path/to/keytool -keysize 2048 -genkey -alias tomcat -keyalg RSA -keystore /path/cer/tomcat.jks

2. Create server csr file.
Needed to issue certificates from your CA (e.g. GoDaddy).
Notes:
- Use RSA as key algorithm
- Use same alias as you used in previous step
script:
/complete/path/to/keytool -certreq -keyalg RSA -alias tomcat -file /path/cer/tomcat.csr -keystore /path/cer/tomcat.jks

At the end of this step, go to your CA certificate management panel and re-key the certificate using the tomcat.csr file content.
Save the (extracted) files on your sever (in our example /path/cer/)

3. Get your server private key.
This step needed, since the private key required for the certification chain creation. The keystore file we created contains both public and private key.
Since keytool can not get the private key, we need to use additional tool.
For me KeyTool-IUI did the trick. You can use this link too.
The relevant menu item is specified in the image below:

The private key file should be in the format specified in the image below:


4. Create the certificate chain:
Notes:
- You can replace gd_bundle.crt with any root certificate given by your CA.
- Make sure the "-name" variable is the same as alias given in step #1.
script:
openssl pkcs12 -export -chain -CAfile /path/cert/gd_bundle.crt -in /path/cert/your_domain.crt -inkey /path/cert/tomcat.pem -out /path/cert/keystore.tomcat -name tomcat -passout pass:YOUR_PASSWORD

5. Update Tomcat server.xml file:
<Connector executor="tomcatThreadPool" protocol="org.apache.coyote.http11.Http11Protocol"
        URIEncoding="UTF-8"
        port="443"
        acceptCount="100"
        enableLookups="true" disableUploadTimeout="true"
        acceptorThreadCount="2"
        scheme="https" secure="true" SSLEnabled="true"
        keystoreFile="/path/cert/keystore.tomcat"
        keystorePass="YOUR_PASSWORD"
        keyAlias="tomcat" keystoreType="PKCS12"
        clientAuth="false" sslProtocol="TLS"
/>

Restart Tomcat and you are ready to go!

If this post saved you time, kindly share it with others.

Thursday, November 24, 2011

Convert PDF to image via PDFbox

Recently I have been asked to generate an image from a PDF file.

In this post I'll use the Apache project pdfbox as the ImageToPDF converter.

Convert PDF page into image
I'll specify two samples, however full complete documentation about  possible options and default values could be found here.

String pdfPath = "/path/to/file.pdf";
//config option 1:convert all document to image
String [] args_1 =  new String[3];
args_1[0]  = "-outputPrefix";
args_1[1]  = "my_image_1";
args_1[2]  = pdfPath;

//config option 2:convert page 1 in pdf to image
String [] args_2 =  new String[7];
args_2[0] = "-startPage";
args_2[1] = "1"
args_2[2] = "-endPage";
args_2[3] = "1";
args_2[4] = "-outputPrefix"
args_2[5] = "my_image_2";
args_2[6] = pdfPath;

try {
// will output "my_image_1.jpg"
        PDFToImage.main(args_1); 
// will output "my_image_2.jpg" 
   PDFToImage.main(args_2); 
      } catch (Exception e) { logger.error(e.getMessage(),e); }
and that's it. As simple s that.
The output image is very good and include also text that was created in JavaScript in the PDF.

Tuesday, November 8, 2011

Have you used bitly/TinyURL? Check out the following cool site

CatchyLink.com is a new site targeting anyone who seek to shorten a URL.
The differentiation from common URL shortening services in the web (such as bitly and TinyURL) is that CatchyLink generate ....hmmm.... catchy links :-) .

Other sites generates short url that is a collection of hashed letters, no human can remember it or tell it our loud, such as http://tinyurl.com/cvt4cpfaDff.

CatchyLink creates URL that not only is short but also one that humans can pronounce and remember.
Such as:  http://catchyLink.com/BigBlueOcean 
Catchy, right?



This is very useful if you need to tell someone else the link or you simply need a link that no one will forget. In our case you can tell your audience to enter the BigBlueOcean. Cool right?

CatchyLink also allows you to regenerate the Catchy Link, in case you did not like the suggested URL.   It actually quite funny & addictive ...  try it and see what I mean ... !

Storing long strings in Google App Engine

Recently I am experimenting with Google App Engine development for a small cool project I involved in.
(p.s. GAE has been recently got out of preview mode into release mode)

As you probably know,  the data is persist in NoSQL type storage.
This has some implications on the state of mind one need to model and access its data.

I was surprised to learn the concept and constraint this model brings ( such as that queries will use only AND no OR..).

Once interesting issue that I faced was the fact that String field is limited to 500 characters.

Since I needed to store longer strings, I immediately turned into the next data type which contains higher amount of characters - Text.
However, following that change I faced another problem - I could not do any queries on that field, since it could not be indexed.

Therefore I sought another solution.
I decided to split the long string into smaller chunks (500 long each) and store it in StringList type.
That provided me a way to keep the string length and have queries by this field (Google Query Language allows to do queries on list).

So my question is - do you have any other solution for storing long Strings given the fact that the field required to be searchable?

p.s.
The project was written in python.... grrrr... I have nothing further to say.