Blog do projektu Open Source JavaHotel

piątek, 30 maja 2014

GWT, Spinner and HTML 5

GWT standard widget set does not contain number "spinner" but it is very easy to reuse HTML 5 "spinner" input control.

class SpinnerInt extends TextBoxBase {

    public static native InputElement createInputElement(Document doc,
            String type, String min, String max) /*-{
  var e = doc.createElement("INPUT");
  e.type = type;
  e.min = min;
  e.max = max;
  return e;
    }-*/;

    SpinnerInt(int min, int max) {
        super(createInputElement(Document.get(), "number",
                Integer.toString(min), Integer.toString(max)));
        this.addStyleName("spinner-style");
    }

}

Using the same technique one can also implement others HTML 5 widgets not implemented in GWT so far (like "time")

środa, 21 maja 2014

JavaHotel, Jython 2.7 and Google App Engine

Introduction

I decided to go ahead and upgrade Jython I'm using from Jython 2.5 (Jython 2.5.4rc1) to Jython 2.7 (Jython 2.7beta2). It works without any problem but I was stuck after deploying to Google App Engine.  The exception error was as follows:

Caused by: java.lang.ExceptionInInitializerError
 at jnr.posix.POSIXFactory.(POSIXFactory.java:15)
 at org.python.modules.posix.PosixModule.(PosixModule.java:63)
 at org.python.modules.Setup.(Setup.java:29)
 at org.python.core.PySystemState.initBuiltins(PySystemState.java:1317)
 at org.python.core.PySystemState.doInitialize(PySystemState.java:1056)
 at org.python.core.PySystemState.initialize(PySystemState.java:982)
 at org.python.core.PySystemState.initialize(PySystemState.java:938)
It was very nasty because it worked in Development Mode (local environment) and it is not easy to debug the application after deploying to the production environment.

Solution 

After spending some time, analyzing exception stack and digging through different versions jnr-posix module (used by Jython for system related stuff) especially Platform class I found the solution.  It was because Google App Engine does not set os.name property (it is null). So the solution was to enhance appengine-web.xml file.
  <system-properties>
    ......
    <property name="os.name" value="linux"/>
    <property name="os.arch" value="amd64"/>    
  </system-properties>
It works now but two questions are pending around me:
  • How it worked with Jython 2.5
  • While Google App Engine set this variables in Development Mode and does not set in Production Mode.

piątek, 9 maja 2014

Glassfish to JBoss (WildFly) migration

Introduction
I decided to migrate JavaHotel application to WildFly (former JBoss) keeping Glassfish version still alive. The reason was very simple. I was unable to call remote EJB deployed to Glassfish. It works from another Glassfish, also from Java standalone application  (following instructions under this link) but I failed to call EJB from another web container (Tomcat or Jetty). I tried to follow instructions from this blog. But the list of jars is valid for Glassfish 3.0, in 4.0 the jars are different and after spending a lot of time combining different sets of jars I finally gave up and switch to WildFly. I was successful but had to overcome some problems related not only to migration from one web container to another but also related to migration from EclipseLink JPA to Hibernate JPA.
Last but not least - to call remote EJB deployed to WifdFly server it is enough to add jboss-client.jar to classpath regardless of the client type.
I'm ignoring trivial tasks related to migration like: data source migration, EJB addressing, JNDI variables etc.
Several persistence-units in the single persistence.xml
Problem
I used to have a single persistence.xml file containing all persitence-units I'm using in different configurations. For instance "RESOURCE-LOCAL" persistence-unit for Tomcat and "JTA" fo JEE container. EclipseLinks at the moment of invoking Persistence.createEntityManagerFactory reads only persistence-unit requested, Hibernate reads the whole content of persistence.xml just failing if any of the persistence-units cannot be initialized.
Solution
Very simple : just split the single persistence.xml into several containing only persitence-unit necessary in the given context.
Different strategies for @Id @GeneratedValue(strategy=GenerationType.AUTO)
Problem
EclipseLink and Hibernate use different strategies for generating global object IDs. EclipseLink creates a separate table (sequence) and Hibernate JPA uses sequence hibernate_sequence (checked for Postresql and ApacheDerby). So after switching from one framework to another on existing table one can run into trouble (duplicate primary key) when both methods overlaps. It costed me a lot of time to discover the problem.
Solution
Use different @GeneratedValue strategy or do not switch framework.
@Lob column for PostgresSql
Problem
@Entity
public class LobRecord implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @Lob
    private byte b[];

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    /**
     * @return the b
     */
    public byte[] getB() {
        return b;
    }

    /**
     * @param b the b to set
     */
    public void setB(byte[] b) {
        this.b = b;
    }
    
}
Unfortunately, Postgresql does not have direct BLOB or LOB column type. EclipseLink translates the @Lob column to bytea (what I expected) but Hiberbate generates oid column type which causes a lot of trouble.
Solution
There is no universal solution to this problem.
  1. Remove @Lob annotation. Both EclipseLink and Hibernate generates bytea column type. But after removing this annotation for ApacheDerby this column is generated as VARCHAR () FOR BIT DATA (not BLOB) which is not valid
  2. Add direct specification @Column(columnDefinition="bytea". But it will not work for ApacheDerby (or any other database, it is PostreSql specific)
  3. Adjust annotation any time database or framework is changed. 
Hiberate does not like hierarchical references in DELETE command
Problem
@Entity
public class CountryRecord implements Serializable {
....
}

@Entity
public class ProvinceRecord implements Serializable {
...    
    @JoinColumn(nullable=false)
    private CountryRecord country;
}

@Entity
)
public class CityRecord implements Serializable {

...
    @JoinColumn(nullable = false)
    private ProvinceRecord prov;
...
}

@NamedQueries({
    @NamedQuery(name = "removeCities", query = "DELETE FROM CityRecord r WHERE r.prov.country= ?1")
p.country= ?1)")
}

EclipseLink does not complain but Hibernate throws an exception
ERROR: HHH000177: Error in named query: removeCities
org.hibernate.QueryException: could not resolve property: country of: teste.entity.CityRecord [DELETE FROM teste.entity.CityRecord r WHERE r.prov.country= ?1]
 at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:83)
 at org.hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:77)

What is more intriguing - Hibernate has nothing against this type of hierarchy in SELECT statement.
Solution
Replace hierarchical reference by nested SELECT.
@Entity
@NamedQueries({
    @NamedQuery(name = "removeCities", query = "DELETE FROM CityRecord r WHERE r.prov in (SELECT p FROM ProvinceRecord p WHERE p.country= ?1)")
}

Hibernate does not like duplicated named query

@Entity
@NamedQueries({
    @NamedQuery(name = "removeCities", query = "DELETE FROM CityRecord r WHERE r.prov in (SELECT p FROM ProvinceRecord p WHERE p.country= ?1)"),
    @NamedQuery(name = "removeCities", query = "DELETE FROM CityRecord r WHERE r.prov in (SELECT p FROM ProvinceRecord p WHERE p.country= 
}

EclipseLink accepts it.  
Different default column naming for class references
Problem
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = { "name", "company" }))
public class PersonRecord implements Serializable {


    private String name;

    @JoinColumn(nullable = false)
    private CompanyRecord company;
,,,,
}

It works for Hibernate but failed for EclipseLink. This is because Hibernate generates company as column name for company reference class but EclipseLink generates company_id column name so the unique constraint fails. After replacing company with company_id in the UniqueConstraint annotation the result is opposite.
Solution
Unfortunately, Hibernate ignores name parameter in JoinColumn annotation. To redefine column name it is necessary to add Column annotation. But EclipseLink does not accept both JoinColumn and Column annotation for the same field. So the only solution for both frameworks is to add name parameter to JoinColumn annotation which is ignored by Hibernate but works for EclipseLink
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = { "name", "company" }))
public class PersonRecord implements Serializable {

    private String name;

    @JoinColumn(nullable = false,name="company")
    private CompanyRecord company;

Different resource filepath
Problem
Assume we want to deploy a simple .war to web container containing  resource/param.txt and want to read this file.
That's pretty simple just:

public class Listener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("Start");
        URL u = Listener.class.getClassLoader().getResource("resource/param.txt");
        System.out.println("U=" + u.getFile());
...
But sometimes is was convenient for me to read this file using :

InputStream i = u.openStream 
and sometimes to read this resource like regular file in the file system using getFile method.
There is no problem on all webcontainers (even Google App Engine infrastructure). For instance, on Tomcat getFile() method returns:

U=/home/hotel/.netbeans/8.0/apache-tomcat-8.0.3.0_base/webapps/ReadRes/WEB-INF/classes/resource/param.txt
But on WildFly it returns something like:
U=/content/ReadRes.war/WEB-INF/classes/resource/param.txt
It does not reflect the place where resource is unpacked, it should be something like:
.../{standalone}/tmp/vfs/temp/temp577a2348203a1442/content-34f69a82c7d2649f/WEB-INF/classes/resource/param.txt
Solution
Of course, it is necessary to read resource file using OpenStream (or any other method) and read file in the file system using file path. 
But I cannot use it for Jython code deployed as a resource which needs file path and there is no simple way to overcome it. The only solution is to deploy Jython code outside .war file and use directory file path.

niedziela, 4 maja 2014

Enhancement to MVP GWT/Jython framework

Introduction
I added several enhancement to my MVP framework. Source code is available here, the demo version (deployed to Google App Engine) is available here. I'm planning to use this enhancements in the JavaHotel application. The description is available here.
Disclosure panel
It is an utilization of GWT DisclosurePanel. Demo version: link -> Different lists -> Dialog with disclosure. I'm planning to use it for more advanced room booking options (group booking). Because in most cases a single room is booked it is not necessary to expose group booking options all the time. The implementation also raises Jython action events before opening and closing the disclosure panel.
Autohide dialog
It is a GWT DialogBox widget with 'autoHide' constructor parameter set to true. Demo version: link -> Autohide dialog. I'm using this feature while exposing the link for PDF downloading. This link is enclosed in autohide dialog just making removing this small dialog more convenient.
Modeless dialog
It is a GWT DialogBox with 'modal' constructor parameter set to false. link -> Modeless dialog ->Modeless. After displaying the last dialog it is still possible to enter values into underlying dialog.I'm planning to use it in the JavaHotel application for more sophisticated searching.
Unfortunately, working with modeless dialog causes some complications and questions. For instance : whether modeless dialog should be removed while underlying dialog is closed ? It requires more elaboration.
Programmatic switching active line in lists
As a default the active line in the list immediately after creation is not specfied. The user should manually navigate to the other lines if necessary. I added the programmatic way of changing the active line - for instance - to implement more advanced searching. link -> Different lists -> List with custom search. I'm planning to use this option for more advanced booking.
Programmatic change active line in dateline panel
This problem is similar to above but is related to dateline widget. link -> Panel date -> To date.
URL query string
Allows passing parameters from query string to Jython backing code. More details.
Strange thing while deploying JSPWiki for Clouds application
I spent some time trying to resolve log message:
Unsupported major.minor version 51.0
The meaning of this  message is obvious: one is trying to execute java code in JVM not supporting this Java version. For instance: byte code created with JDK 1.8 in JVM 1.7. I indeed launched Eclipse with JDK 1.8 but JSPWiki code was compiled having 1.7 compatibility level. This message was throws from JSP (not pure Java) code.
I discovered that this message is thrown after executing the application on local machine in Development mode before deployment to Google App Engine. Probably the JSP pages are compiled at that moment and later I was unable to find any way to force recompiling it in 1.7 compatibility mode. After relaunching the Eclipse with JDK 1.7, running the application locally and redeploying it to Google App Engine again the problem disappeared.

Byliśmy na koncercie

14 kwietnia 2014 roku byliśmy na przedstawieniu orkiestrowym opery Christopha Willibalda Glucka "Ifigenia na Taurydzie" (po kliknięciu na "poniedziałek, 14 kwietnia" rozwinie się skład wykonawców), podobało nam się bardzo.
Więcej informacji na temat samego wykonania od strony realizacyjnej można znaleźć w tym wywiadzie.
Gluck był postacią na styku epok, odchodzącego się w przeszłość stylu włoskiego i nowego nurtu opery klasycznej. Bezpośrednim następcą Gluck był sam Mozart, aczkolwiek tylko jedna z jego oper, Idomeneo, nawiązuje stylistycznie bezpośrednio do twórczości Glucka. Zostawił po sobie bardzo bogaty dorobek, chociaż tylko kilka jego oper weszło na stałe do współczesnego repertuaru. "Ifigenia na Taurydzie" to jedno z ostatnich a zarazem najchętniej wykonywanych jego dzieł.
Nie ma przesady w entuzjastycznej recenzji zawartej po tym linkiem, do Warszawy zawitał naprawdę wielki świat operowy z najwyższej półki. Rewelacyjnie śpiewała Helena Juntunen, uzupełniająca wspaniały głos ekspresją o charakterze aktorskim. Ifigenia to postać skomplikowana, miotana gwałtownymi emocjami od smutku, zgrozy i przerażenia do radości, od klęski do zwycięstwa i uniesienia. Oddanie tych emocji wymaga użycia środków nie tylko o charakterze wokalnym i solistka doskonale się w tej roli sprawdziła.
Fenomenalnie śpiewał tenor Eric Barry jako Pylades oraz baryton David Pershall jako Orestes. Dla solistów doskonałym uzupełnieniem był dobrze śpiewający chór i oraz świetnie grająca orkiestra.
Trudno znaleźć jakieś słaby punktu tego przedstawienia, oby muzyki na tym poziomie było w Warszawie jak najwięcej.
Jedynym problemem była sama formuła przedstawienia, było to wykonanie orkiestrowe, a nie sceniczne, rozumienie fabuły jest bardzo istotne dla właściwego odbioru muzyki. Część widzów (łączenia ze mną)  ratowała się śledzeniem libretta bezpośrednio z wydrukowanego programu.
Aż dziwne, że tak dobre przedstawienie nie wypełniło w całości widowni. Może przyczyną jest - w co trudno uwierzyć - że było to dopiero drugie w historii przedstawienie tego dzieła na polskich scenach i część potencjalnych widzów odebrała tę propozycję jako przypomnienie dzieła z archiwum muzycznego, a nie dzieła z bieżącego nurtu wykonawczego.

Bardzo nam się także podobało przedstawienie (16 kwietnia 2014)  dwóch "Stabat Mater", Vivaldiego i Pergolesego w surowych wnętrzach warszawskiego kościoła parafialnego Kościoła Ewangelicko-Reformowanego. To była duża odwaga powierzyć młodemu kontratenorowi Janowi Jakubowi Monowidowi solowych partii altowych w obu Stabat, ale wykonawca sprawdził się w tej roli bardzo dobrze. Przedstawienie zostało zrealizowane przy użyciu skromnych środków, ale muzyka i wykonanie zabrzmiały doskonale. To bardzo popularne i chętnie nagrywane dzieła, ale nic nie zastąpi wykonania na żywo, w kościelnym wnętrzu i w bardzo dobrym wykonaniu.