Hooks revisited (6) - create a custom finder

Override AssetEntryQueryFinderImpl

Define a finder interface as follows:

 

public interface CustomAssetEntryQueryFinder {

public List<AssetEntry> findEntries(

CustomAssetEntryQueryWrapper customEntryQuery)

throws SystemException;

}

 

Subsequently create an implementation of the interface:

 

public class CustomAssetEntryQueryFinderImpl

extends BasePersistenceImpl<CustomAssetEntryQuery>

implements CustomAssetEntryQueryFinder {

...

@Override

public List<AssetEntry> findEntries(

CustomAssetEntryQueryWrapper entryQuery)

throws SystemException;

...

}

}

 

As a template for the custom finder class we can use the unmodified source of the framework's finder implementation class AssetEntryFinderImpl. Actually we will need to integrate an additional, however optional, SQL fragment into the existing code. The finder method will look something like this:

 

@Override

public List<AssetEntry> findEntries(

CustomAssetEntryQueryWrapper entryQuery)

throws SystemException {

// fetch liferay's session factory

SessionFactory sessionFactory =

(SessionFactory)PortalBeanLocatorUtil.locate("liferaySessionFactory");

Session session = null;

try {

// open session using liferay's session factory

session = sessionFactory.openSession();

SQLQuery q = buildAssetQuerySQL(

entryQuery, false, session);

return (List<AssetEntry>)QueryUtil.list(

q, getDialect(),

entryQuery.getStart(),

entryQuery.getEnd());

}

catch (Exception e) {

throw new SystemException(e);

}

finally {

closeSession(session);

}

}

 

Please note that the custom finder implementation will be loaded by the plug-in context loader due to the simple fact that, in contrast with the access service classes, it will be part of the plug-in package war. The framework's original finder, on the other hand, is loaded by the portal's context loader. This difference must be reflected in the coding. We need the portal's SessionFactory to create the database session because the referenced core tables are not known for the plug-in's default SessionFactory. Similarly, we need to access the portal properties through the PropsUtil class instead of accessing them directly as in the original finder implementation. However, these are only minor technical differences; the custom finder implementation will still remain very close to the template.

 

The complete SQL statement will be compiled from all the search criteria supplied by the entryQuery argument of the method:

 

protected SQLQuery buildAssetQuerySQL(

CustomAssetEntryQueryWrapper entryQuery,

Session session)

throws SystemException {

...

// append join condition

if (entryQuery.getAuthorName().length() > 0) {

sb.append("INNER JOIN ");

sb.append("User_ ON ");

sb.append("(AssetEntry.userID = User_.userId) ");

}

...

// append where condition

if (entryQuery.getAuthorName().length() > 0) {

sb.append(" AND (User_.screenname = ?)");

}

...

// set positional bind variable

if (entryQuery.getAuthorName().length() > 0) {

qpos.add(enryQuery.getAuthorName());

 

}

 

We need to regenerate the implementation part of the plug-in in order to add the finder to the entity. This works like a charm thanks to the Service Builder and our effort of splitting the build job into several build targets. Thus we were able to fulfill requirement d).