Sesawi Parking Management Application

I have published a new application for parking management. I named this application Sesawi. This application consist of four Java programs:

  1. Sesawi setup: setup sesawi initial database and configuration in application server. https://github.com/sfranklyn/sesawi-setup
  2. Sesawi api: interface definition between client and application server. https://github.com/sfranklyn/sesawi-api
  3. Sesawi: parking management web application. https://github.com/sfranklyn/sesawi
  4. Sesawi client: parking management desktop application. https://github.com/sfranklyn/sesawi-client

This is one of the most complex application I have developed. Application business logic is mostly on the web but we need desktop application to do printing and interface with devices.

Advertisements

Laptop baru saya Axioo NEON HNM

Selama ini saya menggunakan laptop buatan lokal Axioo NEON RNE. Axioo adalah merk lokal Indonesia. Laptop saya masuk foto dalam berita waktu saya dikunjungi Menkominfo Rudiantara. Untuk menunjukkan apresiasinya maka perusahaan Axioo Indonesia memberikan saya laptop high end Axioo NEON HNM

Saya tentu saja senang sekali mendapat laptop baru yang lebih baru. Tapi ternyata laptop ini memberikan banyak pekerjaan tambahan buat saya. Selama ini saya biasanya develop menggunakan distro Fedora. Kenapa? Karena Linus Torvald pembuat kernel Linux pakai Fedora, Java versi terbaru biasanya keluar di Fedora terlebih dahulu dan Fedora didukung Red Hat yaitu pembuat distro Linux yang paling banyak dipakai oleh perusahaan bisnis.

Laptop ini sudah mengikut sertakan DVD berisi distro Linux yaitu distro Just KLIXS. Tapi sayangnya saya kurang cocok dengan distro ini. Tapi distro ini jalan mulus di laptop ini dan memberikan petunjuk kepada saya bagaimana caranya supaya Fedora Linux bisa jalan mulus di laptop ini. Ternyata laptop ini power managementnya hanya bisa jalan mulus di Windows. Jadi di Fedora Linux 21 kita harus mematikan ACPI dengan memberikan kernel parameter acpi=off di konfigurasi Grub2.

Berikutnya masih ada pekerjaan yang harus dilakukan kalau anda memakai Java. Java dari OpenJDK di Fedora Linux masih banyak bugsnya. OpenJDK 8 bisa menjalankan WildFly 8 nya JBoss dengan mulus akan tetapi tidak bisa menjalankan NetBeans 8. Solusinya: download dan pakai JDK dari Oracle.

Java dan AS/400

1. Pengantar

Java adalah bahasa pemrograman yang sangat populer dan digunakan oleh banyak kalangan. Walaupun diciptakan oleh Sun Microsystem tetapi Java telah menjadi milik suatu komunitas yang amat luas. Saat ini hak cipta dan merek Java dimiliki oleh Oracle yang membeli Sun Microsystem walau demikian arah perkembangan teknologi Java tidak semata-mata ditentukan oleh Oracle. Komunitas pemakai Java yang banyak dan aktif ikut serta menentukan perkembangan Java. Lisensi teknologi Java saat ini adalah lisensi GPL versi 2. Lisensi ini adalah lisensi open source dan free software. Ketersediaan source Java menjamin kelangsungan hidup Java.

Sedangkan AS/400 (IBM i) adalah komputer bisnis yang dibuat IBM. Apa keunggulan AS/400?

  1. Kompabilitas ke belakang yang panjang. Anda masih bisa menjalankan program yang anda buat 20-an tahun lalu di AS/400 model terbaru.
  2. Kestabilan. AS/400 bisa dioperasikan selama bertahun-tahun tanpa mengalami gangguan. Jika terjadi kerusakan pada salah satu bagian mesin seperti hard disk maka AS/400 bisa diganti bagian yang rusak tanpa perlu melakukan shutdown.
  3. Kemudahan pemakaian. Walaupun jumlah kemampuan yang disediakan oleh AS/400 luar biasa banyaknya akan tetapi semua kemampuan didokumentasikan dengan sangat baik. Pemakai juga dituntun oleh prompt sehingga tahu persis parameter mana yang dibutuhkan dan mana yang tidak. Tersedia juga sistem menu yang sangat lengkap.
  4. Keamanan. Sangat sedikit eksploit keamanan yang bisa digunakan untuk menembus keamanan sistem secara teknis. Operating system dari AS/400 yaitu OS/400 dari sejak awal sudah dirancang mengutamakan keamanan. Tentu saja keamanan bukan sekedar masalah teknis tapi juga prosedur pemakaian sistem. Tapi secara teknis celah keamanan AS/400 sangatlah sedikit.
  5. Skalabilitas. AS/400 tersedia dalam skala kecil dimana 1 mesin bisa digunakan puluhan user sampai skala besar dimana 1 mesin bisa digunakan ribuan user. Jika 1 mesin besar tidak cukup maka beberapa mesin besar bisa dikonfigurasi sehingga terlihat sebagai satu sistem saja dan bisa melayani puluhan ribu user.

Mengingat hal diatas maka pemakaian Java dan AS/400 untuk membangun platform software bisnis anda adalah suatu investasi bisnis yang baik untuk jangka panjang. Dalam tutorial berikut penulis akan membagikan beberapa tehnik pemakaian Java dan AS/400.


2. Perangkat Lunak

Dalam menuliskan tutorial ini penulis menggunakan perangkat lunak berikut:

  1. Open JDK versi 7
  2. Maven versi 3.1.1
  3. NetBeans 7.4

Program Java yang dibuat di uji dengan dijalankan diatas Linux. Penulis menggunakan Manjaro Linux 64-bit. Program RPG yang dibuat duji dengan dijalankan diatas OS/400 v5r1.


3. Data Queue

RPG adalah bahasa pemrograman paling populer di AS400. Data queue adalah fasilitas messaging standar di AS/400. Data queue bisa digunakan untuk komunikasi antara program RPG dan Java. Dalam tutorial berikut penulis akan memberikan contoh program dimana program Java menuliskan data ke data queue. Data dalam data queue akan dibaca oleh program RPG lalu diproses. Hasil pemrosesan ditaruh dalam data queue. Program Java lalu membaca data queue dan menampilkan hasil proses dari RPG.

Terlebih dahulu kita perlu membuat library di AS/400 untuk source dari RPG dan data queue.

===>CRTLIB TUTOR

Lalu kita membuat data queue. Panjang data queue harus sama dengan panjang data yang dikirim oleh program.

===>CRTDTAQ DTAQ(TUTOR/Q01) MAXLEN(36)
===>CRTDTAQ DTAQ(TUTOR/Q02) MAXLEN(33)

Jadikan library TUTOR sebagai current library dan buat source file QSRC. Masuk ke dalam source file itu dengan WRKMBRPDM. Buatlah member PGDQ dengan tipe RPGLE.

===>CHGCURLIB TUTOR
===>CRTSRCPF FILE(QSRC)
===>WRKMBRPDM FILE(TUTOR/QSRC)
===>STRSEU SRCFILE(TUTOR/QSRC) SRCMBR(PGDQ) TYPE(RPGLE)

Lalu masukkan code berikut:

     D Q01             S             10A   INZ('Q01')
     D Q02             S             10A   INZ('Q02')
     D LIB             S             10A   INZ('TUTOR')
     D Q01L            S              5  0 INZ(36)
     D Q02L            S              5  0 INZ(33)
     D WAIT            S              5  0 INZ(-1)
     D NOW             S               D
     D BDAY            S               D
      *
     D Q01DS           DS
     D  NM01                         30A
     D  BDAYS                         6S 0
      *
     D Q02DS           DS
     D  NM02                         30A
     D  AGE                           3S 0
      *
     C                   CALL      'QRCVDTAQ'
     C                   PARM                    Q01
     C                   PARM                    LIB
     C                   PARM                    Q01L
     C                   PARM                    Q01DS
     C                   PARM                    WAIT
      *
     C                   EVAL       NM02=NM01
     C                   EVAL       NOW=%DATE
     C                   EVAL       BDAY=%DATE(BDAYS:*YMD)
     C                   EVAL       AGE=%DIFF(NOW:BDAY:*YEARS)
      *
     C                   CALL      'QSNDDTAQ'
     C                   PARM                    Q02
     C                   PARM                    LIB
     C                   PARM                    Q02L
     C                   PARM                    Q02DS
      *
     C                   EVAL      *INLR=*ON
     C                   RETURN

Compile member PGDQ dengan menggunakan option 14 dari PDM.

Saatnya membuat program Java anda dengan menggunakan Maven. Jalankan perintah berikut di command line

$ mvn archetype:generate -DinteractiveMode=false \
   -DarchetypeGroupId=org.apache.maven.archetypes \
   -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.1 \
   -DgroupId=samuelf.web.id -DartifactId=dataqueue -Dpackage=dataqueue

Maven akan membuat file pom.xml, source file App.java dan AppTest.java. Hapuslah source file App.java dan AppTest.java. Sesuaikan isi file pom.xml anda hingga seperti dibawah ini:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>samuelf.web.id</groupId>
  <artifactId>dataqueue</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>dataqueue</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>net.sf.jt400</groupId>
      <artifactId>jt400-full</artifactId>
      <version>4.7.0</version>
    </dependency>
  </dependencies>
</project>

Buat file DataQueueExample.java dengan isi seperti ini:

/*
 * Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dataqueue;

import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400SecurityException;
import com.ibm.as400.access.AS400Text;
import com.ibm.as400.access.AS400ZonedDecimal;
import com.ibm.as400.access.CharacterFieldDescription;
import com.ibm.as400.access.DataQueue;
import com.ibm.as400.access.DataQueueEntry;
import com.ibm.as400.access.ErrorCompletingRequestException;
import com.ibm.as400.access.IllegalObjectTypeException;
import com.ibm.as400.access.ObjectDoesNotExistException;
import com.ibm.as400.access.Record;
import com.ibm.as400.access.RecordFormat;
import com.ibm.as400.access.ZonedDecimalFieldDescription;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Data queue example.
 *
 * @author Samuel Franklyn <sfranklyn@gmail.com>
 */
public class DataQueueExample {

    private static final Logger logger = Logger.getLogger(
            DataQueueExample.class.getName());
    private final Properties configProperties = new Properties();

    /**
     * Load properties file from class path and write log into file.
     */
    public DataQueueExample() {
        try {
            InputStream inputStream = this.getClass().getClassLoader().
                    getResourceAsStream("config.properties");
            configProperties.load(inputStream);

            FileHandler fileHandler = new FileHandler("log.xml");
            logger.addHandler(fileHandler);
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Write to data queue using Record object.
     *
     * @param name
     * @param birthday
     */
    public void writeDataQueue(String name, long birthday) {
        String systemName = configProperties.getProperty("as400.systemname");
        String userName = configProperties.getProperty("as400.username");
        String password = configProperties.getProperty("as400.password");
        String dataQueue = configProperties.getProperty("as400.dataqueue1");

        AS400 as400 = new AS400(systemName, userName, password);
        DataQueue dq = new DataQueue(as400, dataQueue);

        CharacterFieldDescription nameFD
                = new CharacterFieldDescription(new AS400Text(30, as400),
                        "NAME");
        ZonedDecimalFieldDescription birthdayFD
                = new ZonedDecimalFieldDescription(new AS400ZonedDecimal(6, 0),
                        "BIRTHDAY");

        RecordFormat recordFormat = new RecordFormat();
        recordFormat.addFieldDescription(nameFD);
        recordFormat.addFieldDescription(birthdayFD);

        Record record = new Record(recordFormat);
        record.setField("NAME", name);
        record.setField("BIRTHDAY", new BigDecimal(BigInteger.valueOf(birthday),
                0));

        try {
            byte[] byteData = record.getContents();
            dq.write(byteData);
        } catch (AS400SecurityException | ErrorCompletingRequestException |
                ObjectDoesNotExistException | IOException |
                InterruptedException | IllegalObjectTypeException ex) {
            logger.log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Read from data queue using Record object.
     *
     * @return
     */
    public Record readDataQueue() {
        String systemName = configProperties.getProperty("as400.systemname");
        String userName = configProperties.getProperty("as400.username");
        String password = configProperties.getProperty("as400.password");
        String dataQueue = configProperties.getProperty("as400.dataqueue2");

        AS400 as400 = new AS400(systemName, userName, password);
        DataQueue dq = new DataQueue(as400, dataQueue);

        CharacterFieldDescription nameFD
                = new CharacterFieldDescription(new AS400Text(30, as400),
                        "NAME");
        ZonedDecimalFieldDescription ageFD
                = new ZonedDecimalFieldDescription(new AS400ZonedDecimal(3, 0),
                        "AGE");

        RecordFormat recordFormat = new RecordFormat();
        recordFormat.addFieldDescription(nameFD);
        recordFormat.addFieldDescription(ageFD);

        try {
            DataQueueEntry DQData = dq.read(-1);
            Record record = recordFormat.getNewRecord(DQData.getData());
            String name = (String) record.getField("NAME");
            BigDecimal age = (BigDecimal) record.getField("AGE");
            if (name != null) {
                return record;
            }
        } catch (AS400SecurityException | ErrorCompletingRequestException |
                IOException | IllegalObjectTypeException |
                InterruptedException | ObjectDoesNotExistException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
        return null;
    }

}

Buat file DataQueueExampleTest.java dengan isi seperti ini:

/*
 * Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dataqueue;

import com.ibm.as400.access.Record;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class DataQueueExampleTest {

    @Test
    public void dataQueueExampleTest() {
        Logger logger = Logger.getLogger(DataQueueExampleTest.class.getName());
        DataQueueExample dqe = new DataQueueExample();

        logger.info("Write Data Queue");
        dqe.writeDataQueue("SAMUEL FRANKLYN", 681125);

        logger.info("Read Data Queue");
        Record record = dqe.readDataQueue();
        String name;
        try {
            if (record != null) {
                name = (String) record.getField("NAME").toString().trim();
                BigDecimal age = (BigDecimal) record.getField("AGE");
                logger.log(Level.INFO, "NAME :{0} AGE:{1} years",
                        new Object[]{name, age});
                assertTrue(name.equals("SAMUEL FRANKLYN"));
                assertTrue(age.longValue() == 45);
            }
        } catch (UnsupportedEncodingException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }
}

Untuk bisa menjalankan program java ini anda harus mencopy dari file config-example.properties di direktori src/main/java/resource ke file config.properties lalu menyesuaikan isinya. Isi dari config-example.properties

# Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
as400.systemname=127.0.0.1
as400.username=USER
as400.password=PASSWORD
as400.dataqueue1=/QSYS.LIB/TUTOR.LIB/Q01.DTAQ
as400.dataqueue2=/QSYS.LIB/TUTOR.LIB/Q02.DTAQ

Untuk menjalankan tutorial ini masuklah kedalam AS/400 lalu panggil PGDQ.

===>CALL PGDQ

Lalu panggil Maven dengan goal test:

$ mvn test

4. JDBC

Kita bisa mengakses database di AS/400 dengan menggunakan API standard dari Java yaitu JDBC (Java Database Connectivity). Untuk bisa mencoba hal ini kita perlu menciptakan tabel di AS/400. Rubah current library ke TUTOR. Masuk ke dalam source file QSRC dengan WRKMBRPDM. Buat member SQPERSON dengan type SQL.

===>CHGCURLIB TUTOR
===>WRKMBRPDM FILE(TUTOR/QSRC)
===>STRSEU SRCFILE(TUTOR/QSRC) SRCMBR(SQPERSON) TYPE(SQL)

Lalu isi SQPERSON dengan statement SQL berikut:

CREATE TABLE TUTOR/PERSONR
(
  PS_NAME  CHAR(30),
  PS_BDAY  NUMERIC( 6, 0),
  PRIMARY KEY (PS_NAME)
);

RENAME TABLE TUTOR/PERSONR TO PERSON;

Rename tabel dilakukan supaya nama record format dari tabel berbeda dengan nama tabel. Hal ini perlu supaya tabel bisa diakses juga dari RPG. Lalu ciptakan tabel dengan menjalankan perintah:

===>RUNSQLSTM SRCFILE(TUTOR/QSRC) SRCMBR(SQPERSON)

Statement SQL dalam SQPERSON akan dijalankan dan tabel akan tercipta dalam library TUTOR.

Saatnya membuat program Java anda dengan menggunakan Maven. Jalankan perintah berikut di command line

$ mvn archetype:generate -DinteractiveMode=false \
   -DarchetypeGroupId=org.apache.maven.archetypes \
   -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.1 \
   -DgroupId=samuelf.web.id -DartifactId=jdbc -Dpackage=jdbc

Maven akan membuat file pom.xml, source file App.java dan AppTest.java. Hapuslah source file App.java dan AppTest.java. Sesuaikan isi file pom.xml anda hingga seperti dibawah ini:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>samuelf.web.id</groupId>
  <artifactId>jdbc</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>jdbc</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>net.sf.jt400</groupId>
      <artifactId>jt400-full</artifactId>
      <version>4.7.0</version>
    </dependency>
  </dependencies>
</project>

Buat file JdbcExample.java dengan isi seperti ini:

/*
 * Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jdbc;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Java Database Connectivity example
 *
 * @author Samuel Franklyn <sfranklyn@gmail.com>
 */
public class JdbcExample {

    private static final Logger logger = Logger.getLogger(
            JdbcExample.class.getName());
    private final Properties configProperties = new Properties();
    private Connection conn = null;

    /**
     * Load properties file from class path, write log into file and connect to
     * database.
     */
    public JdbcExample() {
        try {
            InputStream inputStream = this.getClass().getClassLoader().
                    getResourceAsStream("config.properties");
            configProperties.load(inputStream);

            FileHandler fileHandler = new FileHandler("log.xml");
            logger.addHandler(fileHandler);

            String driver = configProperties.getProperty("as400.driver");
            String jdbcUrl = configProperties.getProperty("as400.jdbcurl");
            String userName = configProperties.getProperty("as400.username");
            String password = configProperties.getProperty("as400.password");
            logger.info("Connect to AS/400");
            Class.forName(driver);
            conn = DriverManager.getConnection(jdbcUrl, userName, password);
        } catch (IOException | ClassNotFoundException | SQLException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Insert record into person table
     *
     * @param psName
     * @param psBday
     * @return
     */
    public int insertRecord(String psName, BigDecimal psBday) {
        String insertRecord = "INSERT INTO PERSON ("
                + "PS_NAME,"
                + "PS_BDAY "
                + ") VALUES ("
                + "?,"
                + "?"
                + ")";
        try {
            PreparedStatement insertStmt = conn.prepareStatement(insertRecord);

            insertStmt.setString(1, psName);
            insertStmt.setBigDecimal(2, psBday);

            return insertStmt.executeUpdate();
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
        return 0;
    }

    /**
     * Select from person table using person name.
     *
     * @param psName
     * @return
     */
    public ResultSet selectRecord(String psName) {
        String selectRecord = "SELECT "
                + "PS_NAME,"
                + "PS_BDAY "
                + "FROM PERSON "
                + "WHERE "
                + "PS_NAME = ?";
        try {
            PreparedStatement selectStmt = conn.prepareStatement(selectRecord);
            selectStmt.setString(1, psName);

            ResultSet resultSet = selectStmt.executeQuery();
            if (resultSet.next()) {
                return resultSet;
            }
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
        return null;
    }

    /**
     * Update person birthday identified by person name
     *
     * @param psName
     * @param psBday
     * @return
     */
    public int updateRecord(String psName, BigDecimal psBday) {
        String updateRecord = "UPDATE PERSON "
                + "SET PS_BDAY = ? "
                + "WHERE "
                + "PS_NAME = ?";
        try {
            PreparedStatement updateStmt = conn.prepareStatement(updateRecord);

            updateStmt.setBigDecimal(1, psBday);
            updateStmt.setString(2, psName);

            return updateStmt.executeUpdate();
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
        return 0;
    }

    /**
     * Delete record identified by person name.
     *
     * @param psName
     * @return
     */
    public int deleteRecord(String psName) {
        String deleteRecord = "DELETE FROM PERSON "
                + "WHERE "
                + "PS_NAME = ?";
        try {
            PreparedStatement deleteStmt = conn.prepareStatement(deleteRecord);

            deleteStmt.setString(1, psName);

            return deleteStmt.executeUpdate();
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
        return 0;
    }
}

Buat file JdbcExampleTest.java dengan isi seperti ini:

/*
 * Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jdbc;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class JdbcExampleTest {

    @Test
    public void jdbcExampleTest() {
        Logger logger = Logger.getLogger(JdbcExampleTest.class.getName());
        JdbcExample je = new JdbcExample();

        logger.info("Insert record");
        String psName = "SAMUEL FRANKLYN";
        BigDecimal psBday = new BigDecimal(BigInteger.valueOf(681125), 0);
        assertTrue(je.insertRecord(psName, psBday) > 0);

        logger.info("Select record");
        ResultSet resultSet = je.selectRecord(psName);
        try {
            if (resultSet != null) {
                String name = resultSet.getString(1).trim();
                BigDecimal bday = resultSet.getBigDecimal(2);

                logger.log(Level.INFO, "PS_NAME:{0}", name);
                logger.log(Level.INFO, "PS_BDAY:{0}", bday);

                assertTrue(psName.equals(name));
                assertTrue(bday.longValue() == 681125);
            }
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, null, ex);
        }

        logger.info("Update record");
        psBday = new BigDecimal(BigInteger.valueOf(0), 0);
        assertTrue(je.updateRecord(psName, psBday) > 0);

        logger.info("Delete record");
        je.deleteRecord("SAMUEL FRANKLYN");
    }
}

Untuk bisa menjalankan program java ini anda harus mencopy dari file config-example.properties di direktori src/main/java/resource ke file config.properties lalu menyesuaikan isinya. Isi dari config-example.properties

# Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
as400.driver=com.ibm.as400.access.AS400JDBCDriver
as400.jdbcurl=jdbc:as400://127.0.0.1/tutor
as400.username=USER
as400.password=PASSWORD

Untuk menjalankan panggil Maven dengan goal test:

$ mvn test

5. Command Call

Kita dapat memanggil command di AS/400 dengan menggunakan API CommandCall.

Saatnya membuat program Java anda dengan menggunakan Maven. Jalankan perintah berikut di command line

$ mvn archetype:generate -DinteractiveMode=false \
   -DarchetypeGroupId=org.apache.maven.archetypes \
   -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.1 \
   -DgroupId=samuelf.web.id -DartifactId=commandcall -Dpackage=commandcall

Maven akan membuat file pom.xml, source file App.java dan AppTest.java. Hapuslah source file App.java dan AppTest.java. Sesuaikan isi file pom.xml anda hingga seperti dibawah ini:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>samuelf.web.id</groupId>
  <artifactId>commandcall</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>commandcall</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>net.sf.jt400</groupId>
      <artifactId>jt400-full</artifactId>
      <version>4.7.0</version>
    </dependency>
  </dependencies>
</project>

Buat file CommandCallExample.java dengan isi seperti ini:

/*
 * Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package commandcall;

import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400SecurityException;
import com.ibm.as400.access.CommandCall;
import com.ibm.as400.access.ErrorCompletingRequestException;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Command call example.
 *
 * @author Samuel Franklyn <sfranklyn@gmail.com>
 */
public class CommandCallExample {

    private static final Logger logger = Logger.getLogger(
            CommandCallExample.class.getName());
    private final Properties configProperties = new Properties();

    /**
     * Load properties file from class path and write log into file.
     */
    public CommandCallExample() {
        try {
            InputStream inputStream = this.getClass().getClassLoader().
                    getResourceAsStream("config.properties");
            configProperties.load(inputStream);

            FileHandler fileHandler = new FileHandler("log.xml");
            logger.addHandler(fileHandler);
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

    public class CommandResult {

        private boolean result;
        private CommandCall commandCall;

        public boolean isResult() {
            return result;
        }

        public void setResult(boolean result) {
            this.result = result;
        }

        public CommandCall getCommandCall() {
            return commandCall;
        }

        public void setCommandCall(CommandCall commandCall) {
            this.commandCall = commandCall;
        }
    }

    /**
     * Call a command on AS/400.
     *
     * @param cmd
     * @return
     */
    public CommandResult commandCall(String cmd) {
        String systemName = configProperties.getProperty("as400.systemname");
        String userName = configProperties.getProperty("as400.username");
        String password = configProperties.getProperty("as400.password");

        AS400 as400 = new AS400(systemName, userName, password);
        CommandCall cc = new CommandCall(as400);

        try {
            CommandResult cr = new CommandResult();
            cr.result = cc.run(cmd);
            cr.commandCall = cc;
            return cr;
        } catch (AS400SecurityException | ErrorCompletingRequestException |
                IOException | InterruptedException |
                PropertyVetoException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
        return null;
    }
}

Buat file CommandCallExampleTest.java dengan isi seperti ini:

/*
 * Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package commandcall;

import com.ibm.as400.access.AS400Message;
import commandcall.CommandCallExample.CommandResult;
import java.util.logging.Level;
import java.util.logging.Logger;

import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class CommandCallExampleTest {

    @Test
    public void commandCallExampleTest() {
        Logger logger = Logger.getLogger(
                CommandCallExampleTest.class.getName());

        CommandCallExample cce = new CommandCallExample();
        CommandResult cr = cce.commandCall("CLRPFM PERSON");

        if (cr.isResult()) {
            logger.info("Success");
        } else {
            logger.info("Fail");
        }

        AS400Message[] messagelist = cr.getCommandCall().getMessageList();
        for (AS400Message messagelist1 : messagelist) {
            logger.log(Level.INFO, "{0}: {1}",
                    new Object[]{messagelist1.getID(),
                        messagelist1.getText()});
        }

        assertTrue(cr.isResult());
    }
}

Untuk bisa menjalankan program java ini anda harus mencopy dari file config-example.properties di direktori src/main/java/resource ke file config.properties lalu menyesuaikan isinya. Isi dari config-example.properties

# Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
as400.systemname=127.0.0.1
as400.username=USER
as400.password=PASSWORD

Untuk menjalankan panggil Maven dengan goal test:

$ mvn test

6. Program Call

Selain memanggil command kita juga bisa memanggil program di AS/400. Program yang dipanggil menerima input paramater dan menghasilkan output parameter.

Jadikan library TUTOR sebagai current library. Masuk ke dalam source file QSRC dengan WRKMBRPDM. Buatlah member PGBDAY dengan tipe RPGLE.

===>CHGCURLIB TUTOR
===>WRKMBRPDM FILE(TUTOR/QSRC)
===>STRSEU SRCFILE(TUTOR/QSRC) SRCMBR(PGBDAY) TYPE(RPGLE)

Lalu masukkan code berikut:

     D NOW             S               D
     D BDAY            S               D
      *
     C     *ENTRY        PLIST
     C                   PARM                    BDAYS             6 0
     C                   PARM                    AGE               3 0
      *
     C                   EVAL       NOW=%DATE
     C                   EVAL       BDAY=%DATE(BDAYS:*YMD)
     C                   EVAL       AGE=%DIFF(NOW:BDAY:*YEARS)
      *
     C                   EVAL      *INLR=*ON
     C                   RETURN

Compile member PGBDAY dengan menggunakan option 14 dari PDM.

Saatnya membuat program Java anda dengan menggunakan Maven. Jalankan perintah berikut di command line

$ mvn archetype:generate -DinteractiveMode=false \
   -DarchetypeGroupId=org.apache.maven.archetypes \
   -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.1 \
   -DgroupId=samuelf.web.id -DartifactId=pgmcall -Dpackage=pgmcall

Maven akan membuat file pom.xml, source file App.java dan AppTest.java. Hapuslah source file App.java dan AppTest.java. Sesuaikan isi file pom.xml anda hingga seperti dibawah ini:

<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>samuelf.web.id</groupId>
  <artifactId>pgmcall</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>pgmcall</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>net.sf.jt400</groupId>
      <artifactId>jt400-full</artifactId>
      <version>4.7.0</version>
    </dependency>
  </dependencies>
</project>

Buat file PgmCallExample.java dengan isi seperti ini:

/*
 * Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package pgmcall;

import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400PackedDecimal;
import com.ibm.as400.access.AS400SecurityException;
import com.ibm.as400.access.ErrorCompletingRequestException;
import com.ibm.as400.access.ObjectDoesNotExistException;
import com.ibm.as400.access.ProgramCall;
import com.ibm.as400.access.ProgramParameter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Program call example.
 *
 * @author Samuel Franklyn <sfranklyn@gmail.com>
 */
public class PgmCallExample {

    private static final Logger logger = Logger.getLogger(
            PgmCallExample.class.getName());
    private final Properties configProperties = new Properties();

    /**
     * Load properties file from class path and write log into file.
     */
    public PgmCallExample() {
        try {
            InputStream inputStream = this.getClass().getClassLoader().
                    getResourceAsStream("config.properties");
            configProperties.load(inputStream);

            FileHandler fileHandler = new FileHandler("log.xml");
            logger.addHandler(fileHandler);
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

    public class ProgramResult {

        private boolean result;
        private ProgramCall pgmCall;
        private ProgramParameter[] parmList;

        public boolean isResult() {
            return result;
        }

        public void setResult(boolean result) {
            this.result = result;
        }

        public ProgramCall getPgmCall() {
            return pgmCall;
        }

        public void setPgmCall(ProgramCall pgmCall) {
            this.pgmCall = pgmCall;
        }

        public ProgramParameter[] getParmList() {
            return parmList;
        }

        public void setParmList(ProgramParameter[] parmList) {
            this.parmList = parmList;
        }
    }

    /**
     * Call a program on AS/400.
     *
     * @param pgm
     * @return
     */
    public ProgramResult pgmCall(String pgm) {
        String systemName = configProperties.getProperty("as400.systemname");
        String userName = configProperties.getProperty("as400.username");
        String password = configProperties.getProperty("as400.password");

        AS400 as400 = new AS400(systemName, userName, password);

        try {
            AS400PackedDecimal aspd= new AS400PackedDecimal(6, 0);
            ProgramParameter[] parmList = new ProgramParameter[2];
            parmList[0] = new ProgramParameter(aspd.toBytes(681125));
            parmList[1] = new ProgramParameter(3);

            ProgramCall pc = new ProgramCall(as400, pgm, parmList);
            ProgramResult pr = new ProgramResult();
            pr.result = pc.run();
            pr.pgmCall = pc;
            pr.parmList = parmList;
            return pr;
        } catch (AS400SecurityException | ErrorCompletingRequestException |
                IOException | InterruptedException |
                ObjectDoesNotExistException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
        return null;
    }
}

Buat file PgmCallExampleTest.java dengan isi seperti ini:

/*
 * Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package pgmcall;

import com.ibm.as400.access.AS400Message;
import com.ibm.as400.access.AS400PackedDecimal;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import pgmcall.PgmCallExample.ProgramResult;

@RunWith(JUnit4.class)
public class PgmCallExampleTest {

    @Test
    public void commandCallExampleTest() {
        Logger logger = Logger.getLogger(
                PgmCallExampleTest.class.getName());

        PgmCallExample pce = new PgmCallExample();
        ProgramResult pr = pce.pgmCall("/QSYS.LIB/TUTOR.LIB/PGBDAY.PGM");

        if (pr.isResult()) {
            logger.info("Success");
        } else {
            logger.info("Fail");
        }

        AS400PackedDecimal aspd= new AS400PackedDecimal(3, 0);
        byte[] ageBytes = pr.getParmList()[1].getOutputData();
        Double age = aspd.toDouble(ageBytes);
        logger.log(Level.INFO, "AGE: {0} years", age);

        AS400Message[] messagelist = pr.getPgmCall().getMessageList();
        for (AS400Message messagelist1 : messagelist) {
            logger.log(Level.INFO, "{0}: {1}",
                    new Object[]{messagelist1.getID(),
                        messagelist1.getText()});
        }

        assertTrue(pr.isResult());
    }
}

Untuk bisa menjalankan program java ini anda harus mencopy dari file config-example.properties di direktori src/main/java/resource ke file config.properties lalu menyesuaikan isinya. Isi dari config-example.properties

# Copyright 2013 Samuel Franklyn <sfranklyn@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
as400.systemname=127.0.0.1
as400.username=USER
as400.password=PASSWORD

Untuk menjalankan panggil Maven dengan goal test:

$ mvn test

GlassFish in Production

Currently I have deployed three web applications in production
using GlassFish for my company Galileo Indonesia:

  1. GIWS.
    Galileo Indonesia Web Service is a web service that expose Galileo XML
    Select API as a standard web service.

    What is XML Select API? XML Select API is an API to interact with
    Galileo GDS (Global Distribution Service) application. We can
    display availability, display fare and book
    reservation in Galileo GDS using XML Select API. In XML Select API you
    send your request in XML to HCM (Host Connection Manager)
    using Microsoft DCOM. The HCM will translate your XML
    request into proprietary protocol and sending it to GDS. GDS
    response to your request is send to HCM using proprietary protocol. The
    HCM will translate the response into XML and send it to your
    application. To encapsulate XML API I use EJB3 stateful session bean
    and com4j.
    Why using stateful session bean? Because XML Select API consist of
    stateless and statefull API. To use com4j in GlassFish you must put
    com4.jar in  <GlassFish
    directory>\domains\domain1\lib.

    To expose XML Select API as SOAP Web
    Service we need XSD
    and WSDL.
    Since XML Select API is created before XSD becomes standard there is no
    XSD for XML Select. To solve this I use Trang
    to generate XSD from XML Select documentation and examples. After
    generated the XSD is refined further manually by reading the
    documentation and testing. Using NetBeans wizard I generated WSDL based
    upon the XSD. Based upon the WSDL using NetBeans Wizard I generated
    stub code for web service. Finally I code the implementation of the web
    service by calling XML Select SFSB. The
    implementation code is simply stripping the SOAP header from web
    service and feed the XML request to XML Select API. After XML Select
    responded I replace XML Select header with standard SOAP header.

    For security I use custom handler
    in JAX-WS.
    Using custom handler I check SOAP header for user name and password.
    Based on this user name, password and web services accessed I do
    authentication and authorization checking.

    Frameworks and library used in this application are: JSF, Spring Framework,
    iBatis, RichFaces,
    Facelets
    and Quartz.

    This application developed using NetBeans
    IDE
    and deployed to GlassFish.
    Since this application needs XML Select and Microsoft DCOM the
    application is deployed to GlassFish running on top of Windows
    2003 Server
    . To run GlassFish as a Windows service I am using
    Java
    EE 5 SDK
    . I use GlassFish Java EE bundle from Java EE SDK
    download. When installing Java EE 5 SDK I just have to choose checkbox
    install as Windows Service to install GlassFish as Windows Service.

    This
    application contains a lot of classes generated by JAX-WS
    therefore in development I have to increase GlassFish PermGen memory
    setting by using -XX:PermSize=256m and -XX:MaxPermSize=256m JVM options.

  2. GalileoIM.
    GalileoIM is a web application that can be used by travel agent to send
    booking information to their customer using Short Message Service.

    Galileo IM is one of many applications built using web services
    provided by GIWS. Other application that is built using GIWS is Galileo IBE
    (Internet Booking Engine).

    To send SMS I use SMSLib.
    However I am not using SMSLib in form of jar file. SMSLib lacks
    intensive logging and error checking needed by my application. So I
    modified SMSLib source to add intensive logging and error checking. I
    use SMSLib by utilizing SMSServer class. In servlet context listener I
    run  SMSServer in a separate thread to monitor database.
    Whenever GalileoIM wanted to send SMS it just have to write to the
    database monitored by SMSServer.

    User
    can send SMS using 2 way: 

    1. By using web browser accessing the web
      application. 
    2. By putting booking file in certain queue and
      put
      note with certain format in the booking file. To accomodate the second
      way I monitor the travel agent queue using periodic task run using
      Quartz.

    Frameworks and library used in this application is the same as GIWS
    with the addition of SMSLib. 

    This
    application can not be updated using undeploy and deploy method using
    GlassFish web console because this application uses Java Comm API to
    access serial port. To update the application I have to undeploy the
    application, restart GlassFish and deploy the updated version.

  3. Galileo
    Club
    .
    Galileo Club is a web application to manage point reward program from
    Galileo Indonesia. This application counts number of booking segments
    produced by Galileo Indonesia travel agents. Every night the
    application checks active booking file in Galileo Indonesia PCC.
    Booking segments creation and cancellation are recorded. To do this I
    use Quartz scheduler calling an EJB3 stateless session beans. Because
    the batch process runs very long I have to use multi threading
    programming for optimization. Since the batch process needs maximum
    speed I do not use GIWS from Galileo Club. I embed some code from GIWS
    into Galileo Club.

    In
    this application I migrated from Spring based architecture into EJB3
    based architecture. This application uses EJB3 and JPA to replace
    Spring and iBatis. I also use Optimus library from PrimeFaces
    to eliminate JSF navigation in XML. To display chart in this
    application I use Chart
    Creator
    .

Techniques I use in my application to enhance managebility by GlassFish:

  1. Use logging with certain pattern for integration
    with GlassFish log viewer. I prefix my log information by
    using APP0001 where APP is my application identity and 0001 a log
    number. A pattern like this  is recognized by GlassFish as
    Message Id.
  2. Overiding toString method of classes that is stored in
    session. This way I can see session information from user who is
    logging on the application.
  3. Activate monitoring capability of GlassFish so we can see
    resource usage of our application.

Replacing Toplink Essentials with EclipseLink

EclipseLink is full version of TopLink donated
by Oracle to Eclipse foundation.
Full features of EclipseLink can be read in
http://www.eclipse.org/eclipselink/

TopLink Essentials is a subset of
TopLink donated by Oracle as JPA
reference implementation. Why the Essentials suffix?
Thats because full feature of TopLink is not in
TopLink Essentials. Only features necessary for
JPA implementation is in TopLink Essentials.

In Java EE 6 and GlassFish 3 EclipseLink will become
JPA reference implementation.

But we do not have to wait for Java EE 6 or
GlassFish 3 to be able to use EclipseLink
because EclipseLink is fully compatible with
TopLink Essentials. We can replace Toplink
Essentials with EclipseLink. How?

  1. Download and unzip EclipseLink from
    http://www.eclipse.org/eclipselink/downloads/
  2. Add one line of text in your persistence.xml file.
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    Add those line under persistence unit element.
  3. Add eclipselink.jar jar in jlib directory from
    EclipseLink installation into group of library
    used by your application.

Enjoy and learn the sophisticated features of EclipseLink.

VisualVM is a NetBeans Platform application

VisualVM is a new GUI tools included in
Java SE 6 update 7.
When I run the application the look and feel is very familiar.
I suspect something so I open its About dialog.
Well my suspicion is right: VisualVM is a NetBeans Platform application.

What this means? Well may be it’s time to use NetBeans Platform
instead of Eclipse RCP? He he he. I don’t know since I’m not
developing any GUI apps. However this will make NetBeans Platform
much more appealing to Java developer. Great strategic move by Sun.

Things to do after installing NetBeans 6

  • Select Tools and then Templates from NetBeans Menu.
  • Scroll down and expand User Configuration Properties.
  • Select User.properties.
  • Click Open in Editor.
  • Change the default values.
  • Select Tools and then Templates from NetBeans Menu.
  • Expand Licenses.
  • Select Default License.
  • Click Open in Editor.
  • Change the default values. I change it into:
    <#if licenseFirst??>
    ${licenseFirst}
    </#if>
    ${licensePrefix}${nameAndExt}
    ${licensePrefix}
    ${licensePrefix}Created on ${date}, ${time}
    <#if licenseLast??>
    ${licenseLast}
    </#if>
    

Stateful Web Service using HTTP Session and Cookies

I need to develop a stateful web service. Kohsuke and Scot is using
WS-Addressing to develop the web service.

Unfortunately this approach is not possible for me. Because many clients of my
web service will still be using ASP Classic, VB 6 and PHP. So I use HTTP Session
and cookies to develop my web service and web service client.

I already demo my approach at Indonesia Java User Meeting (JaMU) at
24 November 2007. I use the excellent duo NetBeans 6 and GlassFish 2 to develop
and deploy my web service. I use Spring beans with session scope to
store the web service state. For data access I use the iBatis.
The web service is developed using contract first approach:
Built the XSD, built the WSDL and then generate the web service
from WSDL using NetBeans 6 Wizard.

For this demo I create 2 web service client.
One is a web application using JSF web framework. This web application
use RichFaces and Facelets components. One is a .NET GUI application
developed using Visual Studio C# Express 2005.

In case anyone interested the demo can be downloaded from:

The license is Apache license so feel free to use it for commercial purpose.

Galileo Indonesia SMS Confirm

I just finished developing first application for my new employer. The application is a value added service for travel agents using Galileo GDS. Travel agents can
register passenger booking number in my application. The application will retrieve passenger reservation information and send SMS to passenger mobile number. The application provide template for travel agents
to customize SMS message. The application will also bill the travel agents monthly for the service.

I created this application using JSF , Spring Framework , iBatis , XML Select, ECS , CookXml, com4j , SMSLib, NetBeans and GlassFish. The hardest part is using XML Select to retrieve passenger reservation information from Galileo GDS and parse it into Java object. I have to create XML and parse XML. I use ECS to create the XML and CookXml to parse XML into Java object. XML Select is a COM object so I have to use com4j to access XML Select.

Functionally this application is simple. The hard part is integration with XML Select. I have to use com4j, ECS and CookXml libraries to integrate with XML Select. This application will be deployed using my favorite application server: GlassFish. Hopefully this application will pass internal test and deployed to customer soon.