Wrong charset with GWT Dev-Mode in Eclipse

If you use .properties files to define the application strings, you will run into a strange behaviour of the GWT Dev-Mode in Eclipse.

All .properties files have a default charset of ISO-8859-1. You can see that on your global preferences:

eclipse-prefs

If you write your text, it will be encoded into ISO-8859-1. Now the internal Jetty sends HTTP responses with a charset ISO-8859-1, your text will be unchanged. But if the browser displays the website in UTF-8, all of your texts have the wrong charset (i.e. German umlaute will be wrong). There is no config option to change the behaviour of the Jetty, but you can set the default charset of the .properties files to UTF-8. Then the HTTP responses will change your text encoding, but the browser will change it back to the right charset (set Content-type UTF-8 within your index.html!).

Set focus on a textfield to prevent validation

In the SignInWindow of the trial registry the login textfield has always a red border, because it executes the validation (must not empty) too earlier. So it is necessary to set the focus on that textfield, if we open the window. The following code is copied from the Sencha forum:

Window window = new Window();
window.setWidth(400);
FormPanel formPanel = new FormPanel();                 
                
TextField<String> passwordField = new TextField<String>();                
passwordField.setFieldLabel("xyz");
passwordField.setEmptyText("abcd");
passwordField.setAllowBlank(false);    
passwordField.setMaxLength(255);
passwordField.setPassword(true);
// passwordField.focus(); - Comment this
                
formPanel.add(passwordField);
window.add(formPanel);

window.setFocusWidget(passwordField); // Added this line
window.show();

It doesn’t work to set focus() on the textfield, it is better to let the window decide that.

GXT webdesktop – no background image

If you don’t see the background image of your Desktop, your website probably don’t load the associated CSS files. First at all, you have to include the CSS into your start page:


<link type="text/css" rel="stylesheet" href="gxt-2.2.5/css/gxt-all.css">
<link type="text/css" rel="stylesheet" href="gxt-2.2.5/desktop/css/desktop.css">

Start your appliaction in Development Mode, and open the start page in your browser. If there isn’t the background image visible, you should check your page with a debug-tool like Firebug. Navigate to the CSS link (mostly in <head>) and try to open the link. If the file could not be found (you can not see the CSS definitions), your GXT resources are not available within the application. Copy the necessary files into your WAR or in your deployment directory.

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();
	}

Recursively delete .svn directories

rm -rf `find . -type d -name .svn`

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.

Renew a self-signed certificate with Eisfair

Go to Service Administration->Certs Service->Manage certificates. The script provides a menu to select the certificate and the its operations. Choose the certificate (1), like webserver or mailserver. Choose option 11 to renew the certificate request. Follow the screen output. Select 12 to sign the request with the CA certificate. Choose option 14 to create a new certificate and to copy it on the right place. Restart your webserver or mailserver process (/etc/init.d/).

If you have one certificate for multiple namebased hosts on your webserver, you shouldn’t select option 12. Instead follow the instructions on this blog entry: .

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());