Thursday, January 23, 2014

Vaadin JPAContainer, Filterable table and related entities

In the web 2.0 framework Vaadin you have containers which provide data to be displayed in your application.
These containers are very flexible and can for example be a databasebackend, a JPA system or your own implementation.

In my past post I showed you how to implement filtering for related fields.

Vaadin also provides many data aware components, for example a table component.
The table component is very sophisticated and allows displaying huge amounts of data in the webbrowser. The table has a lazy loading system, so as only the visible parts of a table are retrieved from the backend and sent to the webbrowser.

There also exists a addon component which has built in filter and sort support.

When using the table with jpa container, then you have to use several tricks to allow filtering on related fields.

The first trick is to display the related fields in the table

For this the simplest way is to add these related fields to the main entity you display.
You don't have to store the property, it's enough for the JPA container when you have a getXXX() method.

That way it displays the additional properties in the table. You could also use this way to show calculated related fields in the table.

This could look like this:
public String getProjectInfos()
{
    return projectNr+" - "+name;
}


When you now display these in the table, you can also filter on that field.
But then, you will get a error message, telling you that the sql select did not find the field for the where condition.

For this to work, you have to use the second trick

You can build your own FilterGenerator which then builds the correct criterias for your tables and relations.

contentTable.setFilterGenerator(new MyFilterGenerator());

The filter generator has different methods, when you don't want to override them, you can just return NULL and then the default behaviour is done.

For us the interesting method is the generateFilter() method.
Here you can implement your own conditions.

If you for example wish to filter with the LIKE statement, then you can do it this way:

@Override
public Container.Filter generateFilter(Object propertyId, Object value)
{
    if ("contract".equals(propertyId))
    {
        if (value != null && value instanceof String)
        {
            return new Like("contractID", value.toString()+"%");
        }
    }
    return null;

}

To now filter on a related table, you can use the IN condition, which then builds the correct sql statements.

@Override
public Container.Filter generateFilter(Object propertyId, Object value)
{
       if ("contracts".equals(propertyId))
        {
            if (value != null && value instanceof String)
            {
                String  lsNr= (String) value;
                EntityManager em= ((MyVaadinUI)UI.getCurrent()).getEntityManager();
                TypedQuery<Shippings> tq= em.createNamedQuery("Shippings.findByLikeProjectNr", Shippings.class);
                tq.setParameter("projectNr", lsNr+"%");
                List<Shippings> rs= tq.getResultList();
                if (rs.isEmpty())
                {
                    return new IsNull("shipping");
                }
                else
                {
                    if (rs.size() > 2000)
                    {
                        Notification.show("To many entries", "\n\nMake more restrictions", Notification.Type.WARNING_MESSAGE);
                        return new IsNull("shipping");
                    }
                    else
                    {
                        return new In("shipping", rs);
                    }
                }
            }
        }

    return null;
}

So when the property contracts has some value, we filter the contracts by projectNr and use the resulting result set to specify as the IN criteria.

If you are still with me, then you probably have a compiler error when you try this code.
The reason is, that the default JPAContainer has no implementation of the IN criteria.
Unfortunally the design of the JPAContainer does not allow to expand the capabilities in that area.

Fortunally there exists a fork of the JPAContainer which just provides the required IN() clause.
You can download the sources and add them to your project.

The source can be found here: https://github.com/lelmarir/jpacontainer

You can learn how to show related / nested properties in this post.

Run linux commands via job queue

Often we have build long running jobs under linux which then call other shell scripts when they are finished.
Sometimes it would be possible to run such tasks partially concurrently, but for this we need some sort of job queue for the linux shell.
Unfortunally the cron/crontab does not allow such dependencies.

The simplest solution is to install the task spooler from this site.
You should however first look if your distribution has a binary package for it.

In debian you can install it via:
apt-get install task-spooler

After this, you can just put new jobs in the queue via the ts command.
Please note that in debian the command is named tsp to prevent name conflicts with the moreutils package.

When you just type ts(p) the system shows you all running/pending/completed tasks.

To put a new job in the queue you just type this:
ts(p) /home/user/mytask.sh

The job is then startet as soon as possible.
Per default the task spooler does start one task and waits until it is finished.
When the first task is finished it executes the next one from the queue and so on, until the queue is empty.

You can tell the task spooler to run multiple tasks concurrently,
you just set the maximum number of allowed concurrent executions with this command:
ts(p) -S 2
This would allow the task spooler to run up to two tasks concurrently.

You can also set priority on tasks, remove them  from the queue an so on.
Look at the man page for more details.

As of 0.7.3 the man page does not list all options, to see all available options, use the -h option.

The output of the jost is per default stored in files in the /tmp folder.
You can view them, or use ts(p) to send them via email to some destination.

Wednesday, January 22, 2014

Installing additional skins in CKEditor 4.x

CKEditor is one of the most sophisticated webbrowser base html editors available.
The original version was named fckeditor and going to version 3 it was renamed to be simply ckeditor.

The F in the name was for the first name of the author, Frederico.

When you use the version 4 of the editor, you will receive a new look, due to large changes in the default skin. It is now blackgray/white instead of the "colorful" 3.x version.
A huge improvement in my opinion. The bright colors in 3.x where not looking very professional.

If for some reasons you wish to use another skin, then you can download alternate skins from the ckeditor home page with this link.
When downloading, it tells you how to install and activate the new skin.
Unfortunally this info is mostly wrong, and even in the main documentation the same errors are present.

To successfully install the new skin, you have to put the extracted files in the skins subdirectory (not in the plugins).
And to activate the new skin, you have to specify the config.skin = "new_skin" property. (And not the config.extraPlugin as documented).

So if you wish to have the "old" 3.x icons and colors, you can download the "kama" skin and activate it.