Blog Archives

Special characters within IzPack XML

If you need some defined XML entities like é within the IzPack installation XML, you can’t use it there. The reason: they aren’t defined. But you can define a subset within your XML:

  <?xml version="1.0" encoding="iso-8859-1" ?>
  <!DOCTYPE installation [
  <!ENTITY % iso-lat1 PUBLIC "ISO 8879:1986//ENTITIES Added Latin 1//EN//XML"
                    "http://www.oasis-open.org/docbook/xmlcharent/0.3/iso-lat1.ent">
  %iso-lat1;
  ]>
  <installation version="1.0">
    <!-- start here -->
  </installation>

These additional lines include the usual entities. It is now possible to use:

  <authors>
    <author name="Andr&eacute; Rothe" email="andre.rothe@domain.local" />
  </authors>

Code Formatter Eclipse

Today I had the problem, that I had installed a new Eclipse on my workstation, but I forgot the code style configuration at home. I tried to connect per SSH, but I have no X server on the machine at home. So I cannot run Eclipse to export the configuration as XML. But there is a simple solution for that, copy the information from the right configuration file.

You can find the formatter profiles in the file

/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs

There is a very long line starting with org.eclipse.jdt.ui.formatterprofiles, which you can copy to your local installation. Close your Eclipse and restart it after the change and you will find the new formatter in the drop-down-list within the preferences.

The better way would be to export the formatter definitions as XML within Eclipse and check-in the file into your Subversion/Git.

Log file of the Eclipse workspace

All errors are logged within


${WORKSPACE}/.metadata/.log

Here you can see ClassNotFoundExceptions and timeouts of I/O operations (like Maven index download).

Problem with DescriptorEventAdapter and EJBContext

If you have an AuditListener for your EclipseLink entities, you may have a problem to get the name of the current user at this level. You could use the InitialContext.lookup("java:comp/EJBContext") method, but it fails on my application. Another way is to use a servlet filter.

Define a filter class within your web.xml:

	<filter>
		<filter-name>PrincipalServletFilter</filter-name>
		<filter-class>de.uni_leipzig.smo.acltest.server.filter.PrincipalServletFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>PrincipalServletFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

Implement a singleton enum, which stores a ThreadLocal variable to hold the current principal object.

public enum PrincipalSingleton {
	INSTANCE;

	private ThreadLocal<Principal> principal = new ThreadLocal<Principal>();

	public Principal get() {
		return principal.get();
	}

	public void set(Principal user) {
		this.principal.set(user);
	}
}

Set the current principal within the filter.

public class PrincipalServletFilter
	implements Filter {

	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
		throws IOException, ServletException {
		PrincipalSingleton.INSTANCE.set(((HttpServletRequest) request).getUserPrincipal());
		chain.doFilter(request, response);
	}

	@Override
	public void init(FilterConfig config)
		throws ServletException {
	}
}

And finally use the principal within your audit class.

	private Principal getPrincipal() {
		return PrincipalSingleton.INSTANCE.get();
	}

Adding a web-server’s certificate to Java’s keystore

When you try to connect a secured website, you will need the server’s certificate within the keystore of Java. If you don’t have it, you will get a sun.security.provider.certpath.SunCertPathBuilderException because of an invalid handshake between server and client.

To solve that task, you can get the certificate from a webbrowser (like FireFox). Open the page security properties and export the certificate as *.PEM (Base64 encoded DER certificate) without the certification authorities. Store the file into your filesystem on <cert-path>.

Check your Java installation and login as user, which has write access to <java>/lib/security/cacerts.

Execute
keytool -import -file <cert-path> -alias <cert-name> -keystore <java>/lib/security/cacerts

The <cert-path> is the path to your saved certificate, <cert-name> is an alias for the certificate, you can use the webserver’s domain. The default password of the keystore cacerts is changeit
You will get the information about the certificate and at the end answer the question with yes.

If you have already used the alias within the keystore (i.e. with an old certificate), you can use

keytool -delete -alias <cert-name> -keystore <java>/lib/security/cacerts

to remove the old certificate.

Now, the Java application is able to connect the secured website. Double-check the used installation, sometimes your application uses its own JRE or another version on your filesystem.

Events

There are a lot of events within GXT. I have created a class-overview.

Sometimes I ask myself, which event I will get from a widget and which listener I have to use.

Follow these steps:

  1. Go to the documentation of the class, which is the event source (i.e. Grid)
  2. Look for the right event (like CellClick)
  3. You will see, that CellClick generates a GridEvent. GridEvents can have a generic type, which is related to the ModelData displayed within the grid.

  4. Go to enumeration Events. Choose the right EventType (Events.CellClick)
  5. There are also events like On***. These events are DOM events (browser events). You can also listen to OnClick, but you won’t get high level information like ModelData.

  6. Implement a listener class, which implements the interface Listener
  7. Because the CellClick event type generates a GridEvent, our listener should implement Listener<GridEvent>. There are some special listener like DNDListener which provide additional empty methods for some event types related to special field (like drag&drop). But it is always possible to implement the Listener interface and split the events on their types without any helper classes.

TreeStore<ModelData> store = new TreeStore<ModelData>();
// listen to all events
store.addStoreListener(new SpecialStoreListener());
// or 
store.add(Events.Store.Add, new BaseStoreListener());
store.add(Events.Store.BeforeClear, new BaseStoreListener());
store.add(Events.Store.Sort, new BaseStoreListener());
public class SpecialStoreListener extends StoreListener<ModelData> {
   // override the provided methods as needed
}
public class BaseStoreListener implements Listener<StoreEvent<ModelData>> {
   public void handleEvent(StoreEvent<ModelData> evt) {
      if (e.getType() == Store.Add) {

      } else if (e.getType() == Store.BeforeClear) {

      } else if (e.getType() == Store.Sort) {

      }
   }
}

As you can see, you will have always methods to register a special listener (i.e. store.addStoreListener() instead of store.addListener()). But it is not documented, which class can use such a listener. You have to look into the outline of each class. I have created a listener overview, so you can check the supported EventTypes for each listener.

Filter selection within a TreeGrid

Every node within a TreeGrid can be selected. But sometimes you only need the leafs or only a few of them. It is possible to filter the selection later, just before you execute an action on the selected nodes. But the better way is to prevent a selection on obsolete nodes. Use a custom SelectionModel for that.

public class CustomSelectionModel extends GridSelectionModel<ModelData> {

	public CustomSelectionModel() {
		addListener(Events.BeforeSelect, new NoSelectionListener());
	}

	private class NoSelectionListener
		implements Listener<SelectionEvent<ModelData>> {

		@Override
		public void handleEvent(SelectionEvent<ModelData> se) {
			ModelData model = se.getModel();
			if (model instanceof Something) {
				se.setCancelled(true);
			}
		}

	}
}

You can also use properties of the model to make a decision, but sometimes you can simply ask for the instance type (i.e. folders and files).

Bold font on TreeGrid

You can have a bold font on a TreeGrid. Create your own renderer and enhance the HTML returning by the renderer.

private class BoldGridCellRenderer extends TreeGridCellRenderer<ModelData> {
	protected String getText(TreeGrid<ModelData> grid, ModelData model, String property, int rowIndex, int colIndex) {
		return "<span style=\"font-weight:bold\">" + super.getText(grid, model, property, rowIndex, colIndex) + "</span>";
	}
}

Add the renderer to your tree column (use always TreeGridCellRenderer for that column!).

ColumnConfig name = new ColumnConfig("name", "Name", 300);
name.setRenderer(new BoldGridCellRenderer());

DateFormat

You can not use java.text.DateFormat within GWT/GXT applications. The class is not supported by the Google runtime environment. But there is a similar class com.google.gwt.i18n.client.DateTimeFormat which is useable:

DateTimeFormat dFormat = DateTimeFormat.getFormat("dd.MM.yyyy");
String date = dFormat.format(new Date());

DateTimeFormat tFormat = DateTimeFormat.getFormat("HH:mm:ss");
String time = tFormat.format(new Date());

This can be used within GridCellRenderer or ColumnConfig within a ColumnModel.

ColumnConfig config = new ColumnConfig("column", "Column", 100);
config.setDateTimeFormat(dFormat);

Icons

To create an icon you can use

AbstractImagePrototype icon = IconHelper.create("path/to/png");

Within a TreeGrid it is possible to use a ModelIconProvider

TreeGrid<ModelData> grid = new TreeGrid<ModelData>(store, columnModel);
grid.setIconProvider(new MyIconProvider());

The provider can return an icon for different situations (like expanded or collapsed nodes, some special node types).

public class MyIconProvider implements ModelIconProvider<ModelData> {

   private final TreeGrid<ModelData> grid;

   public MyIconProvider(TreeGrid<ModelData> grid) {
      this.grid = grid;
   }

   public AbstractImagePrototype getIcon(ModelData model) {
      if (model instanceof Something) {
         return IconHelper.create("img/something.png");
      }
      
      if (grid.isExpanded(model)) {
         return IconHelper.create("img/folder-open.png");
      } else {
         return IconHelper.create("img/folder-close.png");
      }
   }
}