nedeľa 26. júla 2009

How to configure PostgreSQL datasource in Embedded JBoss

I have spent more than hour fighting this issue. I will wrote it down rather than forgetting about it. So that in case I have to do this again I will know where to look, and I hope that it might be helpful for others as well.

Environment: Seam 2.1.2, PostgreSQL, JBoss embedded

Scenario: Project generated by seam-gen originally used Hypersonic SQL database (HSQLDB). Later Postgre SQL database (PGSQL) was installed and properly configured with dev build profile. However tests which are running in embedded JBoss still use HSQLDB, the goal is to configure tests to run on PGSQL as well.

Documentation says: By default, a generated project will use the java:/DefaultDS (a built in HSQL datasource in Embedded JBoss) for testing. If you want to use another datasource place the foo-ds.xml into bootstrap/deploy directory.

Sounds easy considering that dev profile is already configured with PGSQL datasource which is woking with ordinary JBoss 5.1.0. One would assume that it is sufficient to copy myproject-dev-ds.xml file to bootstrap/deploy directory (rename it to myproject-test-ds.xml for clarity sake), then change persistence-test.xml according to persistence-dev.xml and all should work.

But in case this is done, running ant test task produces only this incomprehensible error:
org.jboss.deployers.client.spi.IncompleteDeploymentException: Summary of incomplete deployments (SEE PREVIOUS ERRORS FOR DETAILS):
*** CONTEXTS MISSING DEPENDENCIES: Name -> Dependency{Required State:Actual State}
jboss.jca:name=myProjectDatasource,service=DataSourceBinding
-> jboss:service=invoker,type=jrmp{Start:** NOT FOUND **}
-> jboss:service=invoker,type=jrmp{Create:** NOT FOUND **}
*** CONTEXTS IN ERROR: Name -> Error
jboss:service=invoker,type=jrmp -> ** NOT FOUND **
at org.jboss.deployers.plugins.deployers.DeployersImpl.checkComplete(DeployersImpl.java:576)
at org.jboss.deployers.plugins.main.MainDeployerImpl.checkComplete(MainDeployerImpl.java:559)
at org.jboss.embedded.Bootstrap.bootstrapURL(Bootstrap.java:149)
at org.jboss.embedded.Bootstrap.bootstrap(Bootstrap.java:183)
at org.jboss.embedded.Bootstrap.bootstrap(Bootstrap.java:195)
at org.jboss.seam.mock.EmbeddedBootstrap.startAndDeployResources(EmbeddedBootstrap.java:11)
at org.jboss.seam.mock.AbstractSeamTest.startJbossEmbeddedIfNecessary(AbstractSeamTest.java:1024)
at org.jboss.seam.mock.AbstractSeamTest.startSeam(AbstractSeamTest.java:915)
at org.jboss.seam.mock.SeamTest.startSeam(SeamTest.java:58)
... Removed 15 stack frames
where myproject-test-ds.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
  <jndi-name>myProjectDatasource</jndi-name>

  <use-java-context>false</use-java-context><!-- note this line -->

  <connection-url>jdbc:postgresql://localhost:5432/test</connection-url>
  <driver-class>org.postgresql.Driver</driver-class>
  <user-name>test</user-name>
  <password>test</password>
</local-tx-datasource>
</datasources>
and persistence-test.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Persistence deployment descriptor for test profile -->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
       version="1.0">
<persistence-unit name="myProject">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>

  <jta-data-source>myProjectDatasource</jta-data-source><!-- note this line -->

  <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="jboss.entity.manager.factory.jndi.name" value="java:/myProjectEntityManagerFactory"/>
  </properties>
</persistence-unit>
</persistence>
So both files seem to be configured properly, how come it is not working then? Solution can be found here: https://jira.jboss.org/jira/browse/JBPAPP-2223.

Workaround Description: remove "false" from the datasource file and add "java:/" prefix to the content of jta-data-source element in persistence.xml

And indeed after changing myproject-test-ds.xml like this:
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
 <local-tx-datasource>
     <jndi-name>myProjectDatasource</jndi-name>
     <connection-url>jdbc:postgresql://localhost:5432/test</connection-url>
     <driver-class>org.postgresql.Driver</driver-class>
     <user-name>test</user-name>
     <password>test</password>
 </local-tx-datasource>
</datasources>
and persistence-test.xml like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Persistence deployment descriptor for test profile -->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
          version="1.0">
 <persistence-unit name="myProject">
     <provider>org.hibernate.ejb.HibernatePersistence</provider>

     <jta-data-source>java:/myProjectDatasource</jta-data-source><!-- note this line -->

     <properties>
         <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
         <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
         <property name="hibernate.show_sql" value="true"/>
         <property name="hibernate.format_sql" value="true"/>
         <property name="jboss.entity.manager.factory.jndi.name" value="java:/myProjectEntityManagerFactory"/>
     </properties>
 </persistence-unit>
</persistence>
everything works like a charm.

piatok 24. júla 2009

Ako na to HTTPS, JBoss a Seam

Toto je krátky návod, ktorý by mal pomôcť pri konfigurácii HTTPS komunikácie vo vývojom prostredí, ktoré obsahuje aplikačný server JBoss 5.1.0.GA a aplikáciu vygenerovanú nástrojom seam-gen vo verzii 2.1.2.
  1. Vygenerovanie "selfsigned" certifikátu ak nemáme žiadny k dispozícii.
  2. Nastavenie JBoss HTTPS konektora.
  3. Konfigurácia stránok v Seame.
Vygenerovanie "selfsigned" certifikátu ak nemáme žiadny k dispozícii.

Na generovanie použijeme nástroj keytool, ktorý sa štandardne nachádza v Sun JDK.
cd %JAVA_HOME%\bin

C:\Program Files\Java\jdk1.6.0_10\bin\keytool -genkeypair -alias devServerCert -keyalg RSA -validity 1500 -keystore devServer.keystore

Enter keystore password: devserver
Re-enter new password: devserver
What is your first and last name?
[Unknown]:  Meno Priezvisko
What is the name of your organizational unit?
[Unknown]:  oddelenie
What is the name of your organization?
[Unknown]:  spolocnost
What is the name of your City or Locality?
[Unknown]:  mesto
What is the name of your State or Province?
[Unknown]:  stat
What is the two-letter country code for this unit?
[Unknown]:  sk
Is CN=Meno Priezvisko, OU=oddelenie, O=spolocnost, L=mesto, ST=stat, C=sk correct?
[no]:  yes

Enter key password for devservercert enter
 (RETURN if same as keystore password):
Je potrebné si uvedomiť, že heslo pre kľúč je také isté ako heslo pre keystore, preto je ako vstup na konci iba enter. Vygenerovaný súbor devServer.keystore okopírujeme do ...jboss-5.1.0.GA\server\default\conf\ za predpokladu, že používame profil default.

Nastavenie JBoss HTTPS konektora.

Za predpokladu, že používame profil default je potrebné zmeniť súbor ...\jboss-5.1.0.GA\server\default\deploy\jbossweb.sar\server.xml takto:
...
   <Connector protocol="HTTP/1.1" SSLEnabled="true"
        port="8443" address="${jboss.bind.address}"
        scheme="https" secure="true" clientAuth="false"
        keystoreFile="${jboss.server.home.dir}/conf/devServer.keystore"
        keystorePass="devserver" sslProtocol = "TLS" />
...
kde:
keystoreFile - je cesta kde je uloženýdevServer.keystore súbor
keystorePass - je heslo pre keystore a zároveň aj pre klúč v ňom uložený

Konfigurácia stránok v Seame.
  • konfigurácia portov pre HTTP (8080) a HTTPS (8443) v štandartnom konfiguračnom súbore pages.xml
<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.1.xsd"

    no-conversation-view-id="/home.xhtml"
    login-view-id="/login.xhtml"
    http-port="8080"
    https-port="8443">
...
  • nastavenie pre konkrétnu stránku aby sa zobrazovala cez HTTPS protokol (v prípade, že request bude požadovať HTTP presmeruje sa na HTTPS), napríklad pre stránku login.xhtml stačí pridať scheme="https" do súboru login.page.xml
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns="http://jboss.com/products/seam/pages"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.1.xsd"
   scheme="https">
...

utorok 14. júla 2009

Nová firemná web stránka

Od dnes je k dispozícii nová firemná web stránka na www.zont.eu.

Announcing new company web page

Since today there is a new company web page available at www.zont.eu.

utorok 7. júla 2009

New blog structure

After observing other companies successfully integrate a blog into their enterprise web pages, I made decision that this blog will become inseparable part of my company's web page which is being created at the moment.

The main goal is to bring a life into the not really very interesting static web presentation of the company, which in my opinion was already done successfully by others.

I plan to publish in this blog mainly technical solutions to problems which I have to tackle with, but which might be of interest for others as well, to a lesser degree I plan to publish news concerning the company as such.

Nové zameranie blogu

Po vzore iných spoločností, ktoré integrovali blog do svojej firemnej web stránky som sa rozhodol, že tento blog sa stane taktiež nedeliteľnou súčasťou mojej firemnej web stránky, ktorú v súčastnosti pripravujem.

Hlavným cieľom je oživiť nie príliš zaujímavú statickú webovú prezentáciu spoločnosti, tak ako sa to podľa môjho názoru podarilo iným.

Do blogu plánujem prispievať hlavne technickými riešeniami problémov, s ktorými sa stretnem, ale ktoré by mohli byť užitočné aj pre niekoho iného, taktiež v menšej miere novinkami ohľadom spoločnosti.

streda 1. júla 2009

Workaround for GWT Menubar issue 374

Issue link: Command based top level MenuItems (no sub-menu) stay highlighted when mouse leaves MenuBar.

Short description:

MenuItems on main MenuBar that have no sub-menus stay highlighted even after the mouse leaves the MenuBar. For example the fragment below produces just such a menu...


Workaround:

All workarounds provided on issue page required users to maintain their own GWT builds, which is pretty annoying for such a small nuisance. I have slightly modified one of those solutions, so that now you can package it into your application. It breaks some good practices concerning encapsulation, but it seems to work quite well with GWT 1.6.4. However use only at your own risk.
package com.yourcompany.gwtfix;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;

public class FixedMenuBar extends MenuBar {
    private static final String DEPENDENT_STYLENAME_SELECTED_ITEM = "selected";

    public void onBrowserEvent(Event event) {
        super.onBrowserEvent(event);
        MenuItem item = myFindItem(DOM.eventGetTarget(event));
        if (item == null) {
            return;
        }

        if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
            this.setSelectionStyle(item, false);
        } else if (DOM.eventGetType(event) == Event.ONMOUSEOVER) {
            this.setSelectionStyle(item, true);
        }
    }

    private void setSelectionStyle(MenuItem item, boolean selected) {
        if (selected) {
            item.addStyleDependentName(DEPENDENT_STYLENAME_SELECTED_ITEM);
        } else {
            item.removeStyleDependentName(DEPENDENT_STYLENAME_SELECTED_ITEM);
        }
    }

    private MenuItem myFindItem(Element hItem) {
        for (MenuItem item : getItems()) {
            if (DOM.isOrHasChild(item.getElement(), hItem))
                return item;
        }
        return null;
    }

    public FixedMenuBar() {
        super();
    }

    public FixedMenuBar(boolean autoClose) {
        super(autoClose);
    }
}