суббота, 6 августа 2011 г.

Alfresco: strong text search with wildcard using lucene

My new problem is not very difficult, but have interesting solution (I think :)). For example we have four objects in our alfresco repository that have next titles:
  • James John
  • Li Joan
  • Johan Jazz
  • Bill

For get all objects that begins from 'Joh', I use the next query:
+TYPE:"my:object" +@cm\:title:"joh*"

The result of the query:
  • James John
  • Johan Jazz
  • Li Joan

'Joan' doesn't contain 'joh' in title. For solve that I modify my query:
+TYPE:"my:object" +@cm\:title:"[joh*]"

This query returns the right result:
  • James John
  • Johan Jazz

You can find more lucene tricks in wonderful book that called: "Lucene in Action" :)

вторник, 2 августа 2011 г.

Quartz: running jobs sequentially

To initialize (import dictionaries, create system users and roles, etc) our system we use quartz. But yesterday after I've created new job I saw that my new job depends on other jobs. Still I don't get how can I create dependencies over jobs and I think that the usage of dependencies in jobs is an ugly solution. The solution is simply to run jobs sequentially - one by one. But I couldn't find fast way to do that. One job runs in one thread and if I set threads count to 1, then I solve my problem. Here is the code to do that:

Properties schedProps = new Properties();
schedProps.setProperty(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, SimpleThreadPool.class.getName());
schedProps.setProperty(StdSchedulerFactory.PROP_THREAD_POOL_PREFIX + ".threadCount", "1");
StdSchedulerFactory factory = new StdSchedulerFactory(schedProps);
Scheduler initScheduler = factory.getScheduler();
Now all jobs in initScheduler will run one by one.
It's simple and actually work :)

вторник, 28 июня 2011 г.

Generate changelog from Bamboo with Mercurial


We use bamboo(v.3) for supports continuum integration in our project and mercurial as control version system. We wrote some core functions for the project and now should test it. Testers want to see what's new we do in new build. For this reason developers should wrote changelog for new build. But we are lazy developers and don't want to do this :) Unfortunately, bamboo can not generate changelog for mercurial. For make this, I added new stage to bamboo and create one script task in it.

Bamboo has list of global variables that you can use in scripts. Full list of these variables you can see here. I interested two of these variables:
bamboo.repository.revision.number - The revision number
repository.previous.revision.number - The previous revision number (might not exist if for example is initial build)
Now, I simple need to get changes between these revisions. Mercurial has powerful command:
hg log. It supports different templates. I use next command to get log:
hg log -r ${bamboo.repository.previous.revision.number}:${bamboo.repository.revision.number} --template "{rev}:{author} - {desc}\n" -P ${bamboo.repository.previous.revision.number}
I use flag -P to exclude revision from previous build.

Our build server works under Windows Server 2008 and I wrote batch in script task to generate changelog.

IF EXIST C:\changelog.txt (
  COPY C:\changelog.txt C:\changelog.txt.tmp

ECHO Build ${bamboo.buildNumber} - ${bamboo.buildTimeStamp} > C:\changelog.txt

IF ${bamboo.repository.previous.revision.number}==${bamboo.repository.revision.number} (
   echo [No changes] >> C:\changelog.txt
) ELSE ( 
   hg log -r ${bamboo.repository.previous.revision.number}:${bamboo.repository.revision.number} --template "{rev}:{author} - {desc}\n" -P ${bamboo.repository.previous.revision.number} >> C:\changelog.txt

ECHO ++++++++++++++++++++++++++ >> C:\changelog.txt
ECHO. >> C:\changelog.txt

IF EXIST C:\changelog.txt.tmp (
  TYPE C:\changelog.txt.tmp >> C:\changelog.txt
  DEL C:\changelog.txt.tmp

пятница, 29 апреля 2011 г.

Process workflow with alfresco and actitviti

Alfresco release new version of their ECM - 3.4.e. Major feature of this release is integration with activiti BPM platform. That's a good news, because JBPM 3 is obsolete. Of course, I try to use it and have some problems ;) In our projects we use WorkflowService to control business processes. To move workflow from one task to another we have to end current task and specify the transition name(more details you can find here:
    workflowService.endTask(task.getId(), "transitionName");

But when we migrate simple workflow from jbpm to activiti, we got exception :(

I start to discover alfresco sources and found interesting method in activiti workflow component:
    private WorkflowTask endNormalTask(String taskId, String localTaskId, String transition)
        // Retrieve task
        Task task = taskService.createTaskQuery().taskId(localTaskId).singleResult();
        if(task == null)
            String msg = messageService.getMessage(ERR_END_UNEXISTING_TASK, taskId);
            throw new WorkflowException(msg);
        // Signal the transition on the task
        if (transition != null && 
            // Only 'Next' is supported as transition.
            String msg = messageService.getMessage(ERR_END_TASK_INVALID_TRANSITION, transition, taskId, ActivitiConstants.DEFAULT_TRANSITION_NAME);
            throw new WorkflowException(msg);
        // The task should have a historicTaskInstance
        HistoricTaskInstance historicTask = historyService.createHistoricTaskInstanceQuery().taskId(task.getId()).singleResult();
        return typeConverter.convert(historicTask);

YOOHOO! Now, you can use only "Next" keyword to move activiti workflow and code to end task should looks like this:

вторник, 16 ноября 2010 г.

Share smartgwt js over several gwt modules

When you create smartgwt module you have the following lines in your *.gwt.xml file:

<inherits name="com.smartgwt.SmartGwt"/>

Everything works fine. When you load your module at the first time, the browser gets all smartgwt js libs(ISC_*.js) and caches it. In our application we have got five gwt modules and all of them are using smartgwt. And when we load each module for the first time, it is getting 2 MB of js files. For our five modules browser downloads over 10 MB of smartclient libs. That's too much! To solve this problem I discover SmartGwt.gwt.xml. It inherits from module that called SmartClientDefault:

<script src="sc/modules/ISC_Core.js"/>
<script src="sc/modules/ISC_Foundation.js"/>
<script src="sc/modules/ISC_Containers.js"/>
<script src="sc/modules/ISC_Grids.js"/>
<script src="sc/modules/ISC_Forms.js"/>
<script src="sc/modules/ISC_RichTextEditor.js"/>
<script src="sc/modules/ISC_Calendar.js"/>
<script src="sc/modules/ISC_DataBinding.js"/>

And that's our problem. All js have relative paths. But Smartgwt has wonderful module that called SmartGwtNoScript that does not have a dependence on SmartClientDefault and we can include all scripts using absolute paths!
The solution is to replace inherits from com.smartgwt.SmartGwt by the following code in all modules that need smartgwt(or create one root module):

<inherits name="com.smartgwt.SmartGwtNoScript"/>
<script src="/mod/sc/modules/ISC_Core.js"/>
<script src="/mod/sc/modules/ISC_Foundation.js"/>
<script src="/mod/sc/modules/ISC_Containers.js"/>
<script src="/mod/sc/modules/ISC_Grids.js"/>
<script src="/mod/sc/modules/ISC_Forms.js"/>
<script src="/mod/sc/modules/ISC_RichTextEditor.js"/>
<script src="/mod/sc/modules/ISC_Calendar.js"/>
<script src="/mod/sc/modules/ISC_DataBinding.js"/>

вторник, 9 ноября 2010 г.

Simplify if

From time to time we write unoptimized code. For program to be cute it is fun to be optimized.
For example this is a possible way to write if sequence:

if (p.equals("Completed")){
return true;
} else {
return false;

But to be optimized the method body should look like this:

return "Completed".equals(p);

What's really interesting is that it's not only looking good. Indeed it helps you to evade null pointer exception in case when p equals null. We are not able to call method from null - it'll throw exception, but when using equals() method this would be processed correctly.

To study this in depth we can explore StringUtils.java (the one that is in org.apache.commons.lang package).

public static boolean equals(String str1, String str2) {
return str1 == null ? str2 == null : str1.equals(str2);

Lets look at the method in JAVA source code and the values it may return:

StringUtils.equals(null, null) = true
StringUtils.equals(null, "abc") = false
StringUtils.equals("abc", null) = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false

It returns true in case of equality. So, we can use this or the same logic to write our optimized pieces of code.

Have fun, optimize :)

четверг, 4 ноября 2010 г.

Height for DateChooser (Smart GWT)

In our project we are using Smart GWT component (DateChooser) which allows user to select dates ranges. It looks like this:
date chooser height bug.

Smart GWT has a bunch of useful things (datasources, for example). But when I need some UI customization, sometimes I am having troubles :) And now I've got problems with height of the DateChooser component.

Both date choosers have height 200 px, but the right one is smaller then the left because it has only five week rows. Our tester is very carping guy :) though he had posted a bug in the bug tracker. I had spent some time and found a solution. All that I needed was to wrap DateChooser in a layout. I wrote simple helper method for doing this:

    public static Canvas wrapDateChooser(DateChooser dateChooser, String width, String height) {
        VLayout layout = new VLayout();
        return layout;

fixed date chooser bug

Go and close bug in JIRA, YEAH!

Most popular