Documentation

(de:jvx)

Erste JVx Applikation (Schritt für Schritt)

Translations of this page:

This is an old revision of the document!


Das Ziel dieses Tutorials ist die Erstellung einer Applikation mit dem Enterprise Application Framework - JVx. Dazu wird ein erster Einblick in die Möglichkeiten des Frameworks gegeben.

Die Aufgabe der Applikation ist, die Daten aus einer Datenbanktabelle darzustellen und editierbar zu machen. Die Applikation erfordert eine Authentifizierung mit Benutzername und Passwort.

Wir setzen folgende Kenntnisse und Hilfsmittel voraus:

  • Eclipse IDE (>= 3.4) mit JDT (Empfohlen wird: Eclipse IDE für Java EE Entwickler)
  • JDK 6.0 (1.6) or höher
  • HSQLDB Bibliothek (http://www.hsqldb.org)
  • Datenbank- bzw. SQL Kenntnisse

Diese Dokumentation beschreibt folgende Bereiche:

Verzeichnisstruktur

Für die Applikationsentwicklung mit JVx wird eine spezielle Ordnerstruktur empfohlen. Diese erleichtert den Build Prozess und trennt von vornherein Abhängigkeiten zwischen Client und Server. Diese Struktur ist wie folgt zu erstellen:

Auf Wunsch kann auch eine herkömmliche Strukturierung:

verwendet werden. Die Dokumentation bezieht sich jedoch auf die empfohlene Struktur.

OrdnerBeschreibung
radEnthält Applikations- und Serverspezifische Dateien.
appsEnthält alle verfügbaren Applikationen. In diesem konkreten Beispiel ist nur eine Applikation enthaltene.
firstappCEnthält die Applikation mit Projektkonfiguration, Sourcen, Bibliotheken.
helpEnthält den Client für die Online Hilfe und die Hilfeseiten.
libsEnthält alle Bibliotheken, die sowohl am Client als auch am Server benötigt werden.
libs/clientEnthält alle Bibliotheken die ausschließlich am Client benötigt werden.
libs/serverEnthält alle Bibliotheken die ausschließlich am Server benötigt werden.
src.clientEnthält alle Sourcen die ausschließlich am Client benötigt werden.
src.serverEnthält alle Sourcen die ausschließlich am Server benötigt werden.
testEnthält Unit tests für Client und Server bzw. Bibliotheken.

Nachdem die Ordnerstruktur erstellt wurde, kopieren Sie die Bibliothek jvxclient.jar in den Ordner libs/client und die Bibliothek jvx.jar in den Ordner libs/server. Beide Bibliotheken sind im JVx Binärpaket enthalten.

Projektkonfiguration

Nachdem die Konfiguration durchgeführt wurde, kann mit Eclipse ein neues Projekt erstellt werden:

  • File / New / Java Project
  • Zu beachten ist, dass das Projekt im Applikationsverzeichnis firstapp abgelegt wird.
  • Entfernen des src Ordner von den Source Folders
    Setzen der Ordner src.client, src.server und test als Source Folder
  • Hinzufügen der jvx.jar Bibliothek, aus dem Projektverzeichnis JVxFirstApp/libs/server
  • Das Projekt kann nun erstellt werden

Das Projekt wird von Eclipse nun wie folgt dargestellt:

Zur Vollständigkeit kann der src Ordner gelöscht werden. Dieser wird in unserer Applikation nicht benötigt.

Applikationsentwicklung

Die Applikation benötigt Serverseitig eine Konfigurationsdatei für Einstellungen die nur die Applikation betreffen. Für die Konfiguration des Servers wird zusätzlich eine Konfigurationsdatei benötigt. Zuerst erstellen wir die Datei für die Applikation:

  • File / New / File - config.xml
    1)
1)
Erstellung direkt im Applikationsverzeichnis JVxFirstApp)
Die Datei wird wie folgt befüllt:
config.xml
<?xml version="1.0" encoding="UTF-8"?>
 
<application>
  <securitymanager>
    <class>com.sibvisions.rad.server.security.XmlSecurityManager</class>
    <userfile>users.xml</userfile>
  </securitymanager>
 
  <!-- predefined life-cycle object names -->
  <lifecycle>
    <mastersession>apps.firstapp.Session</mastersession>
    <application>apps.firstapp.Application</application>
  </lifecycle>  
</application>
ParameterBeschreibung
securitymanager/classDer Sicherheitsmanager für die Überprüfung von Benutzernamen/Passwort bei der Anmeldung an die Applikation.
securitymanager/usersfileDie Datei mit den erlaubten Benutzername/Passwort Kombinationen.
lifecycle/mastersessionDie Klassenbezeichnung des Server Objektes, das instanziert wird, wenn der Client eine Anmeldung durchführt bzw. eine neue MasterSession startet.
lifecycle/applicationDie Klassenbezeichnung des Server Objektes das instanziert wird beim ersten Zugriff auf die Applikation. Für alle weiteren Zugriffe wird dieses Objekt wiederverwendet.
Die Konfigurationsdatei des Servers muss im Verzeichnis ../JVxFirstApp/rad/server abgelegt werden. Dieses Verzeichnis scheint in unserem Eclipse Projekt jedoch nicht auf, da es sich auf einer höheren Verzeichnisebene befindet. Die Konfigurationsdatei könnte direkt im Dateisystem erstellt werden oder wir erstellen einen Verzeichnis-Link in unserem Projekt:
  • File / New / Folder
Anschließend kann die Konfigurationsdatei erstellt werden:
  • File / New / File - config.xml
Die Datei wird wie folgt befüllt:
config.xml
<?xml version="1.0" encoding="UTF-8"?>
 
<server>
</server>
Der Server benötigt für unsere Applikation keine speziellen Parameter.

Für den Client benötigen wir nun eine Klasse die vom Typ javax.rad.application.IApplication ist. Von JVx wird eine Standard Implementierung durch com.sibvisions.rad.application.Application implementiert. Von dieser werden wir unseren Client ableiten und erstellen somit eine Klasse, im Verzeichnis src.client, mit folgendem Source Code:
FirstApplication.java
package apps.firstapp;
 
import javax.rad.application.genui.UILauncher;
import javax.rad.remote.IConnection;
 
import com.sibvisions.rad.application.Application;
import com.sibvisions.rad.server.DirectServerConnection;
 
/**
 * First application with JVx, Enterprise Application Framework.
 * <p/>
 * @author René Jahn
 */
public class FirstApplication extends Application
{
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Initialization
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * Creates a new instance of <code>FirstApplication</code> with a technology
   * dependent launcher.
   * <p/>
   * @param pLauncher the technology dependent launcher
   */
  public FirstApplication(UILauncher pLauncher)
  {
    super(pLauncher);
  }
 
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Overwritten methods
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * {@inheritDoc}
   */
  @Override
  protected IConnection createConnection() throws Exception
  {
    return new DirectServerConnection();
  }
 
  /**
   * {@inheritDoc}
   */
  @Override
  protected String getApplicationName()
  {
    return "firstapp";
  }
 
}  // FirstApplication
MethodeBeschreibung
KonstruktorDer Standardkonstruktor kann nicht verwendet werden, da jede Applikation mit einem Technologieabhängigen Launcher gestartet wird. Dieser Launcher wird bereits im Konstruktor an die Applikation übergeben.
createConnectionDas Kommunikationsprotokoll wird initialisiert. Für unsere Applikation ist eine DirectServerConnection ausreichend, da sowohl Client als auch Server in der selben VM gestartet werden. Wird jedoch ein Applikationsserver eingesetzt könnte alternativ eine HttpConnection verwendet werden.
getApplicationNameLegt den Applikationsnamen fest. Dieser Name wird für die Kommunikation mit dem Server benötigt, da dieser abhängig vom Applikationsnamen die passende Applikationskonfiguration verwendet. In unserem Fall muss der Applikationsname firstapp lauten, da das Arbeitsverzeichnis ../JVxFirstApp/rad/firstapp/ ebenso lautet. Der Applikationsname MUSS immer dem Verzeichnisnamen entsprechen!
Nun ist es an der Zeit für den ersten Start der Applikation. Dafür erstellen wir eine Runtime Konfiguration:
  • Run / Run Configurations… / Application - New launch configuration - mit den Einstellungen:

ParameterDescription
Main classThe technology-dependant launcher is defined here. We use the Swing technology for our application and start a Swing application.
Program argumentsThe launcher must be told which application to start. For our Swing application, we can use the mechanism of programme arguments and pass the class name of our application.
The application can now be started and looks as follows: The first login attempt fails with the following message:
Userfile 'users.xml' does not exist!
This file was defined in the config.xml file of the application; however, it has not yet been created. We do so now here:
  • File / New / File - users.xml
We fill the file with the following:
users.xml
<?xml version="1.0" encoding="UTF-8"?>
 
<users>
  <user name="admin" password="admin"/>
</users>
Any number of user lines can be entered! Now the login to the application works perfectly. However, to fulfill our task, we still need the possibility to display or edit a database table. We will now turn to this part of the task. == Create a work screen== Before we create a WorkScreen, we prepare the application to display the WorkScreen. To do so, we extend our FirstApplication class as follows:
FirstApplication.java
package apps.firstapp;
 
import javax.rad.application.genui.UILauncher;
import javax.rad.genui.UIImage;
import javax.rad.genui.component.UIButton;
import javax.rad.genui.container.UIToolBar;
import javax.rad.genui.menu.UIMenu;
import javax.rad.genui.menu.UIMenuItem;
import javax.rad.remote.IConnection;
 
import com.sibvisions.rad.application.Application;
import com.sibvisions.rad.server.DirectServerConnection;
 
/**
 * First application with JVx, Enterprise Application Framework.
 * <p/>
 * @author René Jahn
 */
public class FirstApplication extends Application
{
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Initialization
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * Creates a new instance of <code>FirstApplication</code> with a technology
   * dependent launcher.
   * <p/>
   * @param pLauncher the technology dependent launcher
   */
  public FirstApplication(UILauncher pLauncher)
  {
    super(pLauncher);
  }
 
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Overwritten methods
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * {@inheritDoc}
   */
  @Override
  protected IConnection createConnection() throws Exception
  {
    return new DirectServerConnection();
  }
 
  /**
   * {@inheritDoc}
   */
  @Override
  protected String getApplicationName()
  {
    return "firstapp";
  }
 
  /**
  * {@inheritDoc}
  */
  @Override
  protected void afterLogin()
  {
    super.afterLogin();
 
    //configure MenuBar
 
    UIMenu menuMasterData = new UIMenu();
    menuMasterData.setText("Master data");
 
    UIMenuItem miDBEdit = createMenuItem
                          ("doOpenDBEdit", null, "DB Edit", 
                           UIImage.getImage(UIImage.SEARCH_LARGE));
 
    menuMasterData.add(miDBEdit);
 
    //insert before Help
    getMenuBar().add(menuMasterData, 1);
 
    //configure ToolBar
 
    UIToolBar tbMasterData = new UIToolBar();
 
    UIButton butDBEdit = createToolBarButton
                         ("doOpenDBEdit", null, "DB Edit", 
                          UIImage.getImage(UIImage.SEARCH_LARGE));
 
    tbMasterData.add(butDBEdit);
 
    getLauncher().addToolBar(tbMasterData);
  }
 
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Actions
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * Opens the edit screen.
   */
  public void doOpenDBEdit()
  {
    //TODO open the workscreen
  }
 
}  // FirstApplication
MethodDescription
afterLoginThis method is invoked form the super class after a successful login. We use this method to extend our menu and our ToolBar.

It is not necessary to undo our changes after logout as this is done by the super class.
doOpenDBEditThis method is called when the Menu or the ToolBar button are selected.
createMenuItemProvided by the super class to create menu entries. The first parameter contains the name of the method which is to be called when the menu entry is selected. The second parameter contains the command (ActionCommand) which does not play any role in our case. The text of the menu entry is to be defined in the third parameter and, lastly, the image for the entry is passed.
createToolBarButtonSimilar to createMenuItem, except that here a button is created which adjusts itself to the layout of the ToolBar.
UIImage.getImageProvides a predefined image from the image library of JVx.
We use a predefined image for convenience.
We now create the client class for our work screen:
  • File / New / Class
    src.client, apps.firstapp.frames.DBEditFrame
and use the following Source Code:
DBEditFrame.java
package apps.firstapp.frames;
 
import javax.rad.genui.container.UIGroupPanel;
import javax.rad.genui.container.UIInternalFrame;
import javax.rad.genui.control.UITable;
import javax.rad.genui.layout.UIBorderLayout;
import javax.rad.remote.AbstractConnection;
import javax.rad.remote.MasterConnection;
 
import com.sibvisions.rad.application.Application;
import com.sibvisions.rad.model.remote.RemoteDataBook;
import com.sibvisions.rad.model.remote.RemoteDataSource;
 
/**
 * A simple database table editor.
 * <p/>
 * @author René Jahn
 */
public class DBEditFrame extends UIInternalFrame
{
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Class members
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /** the application. */
  private Application application;
 
  /** the communication connection to the server. */
  private AbstractConnection connection;
 
  /** the DataSource for fetching table data. */
  private RemoteDataSource dataSource = new RemoteDataSource();
 
  /** the contacts tabl. */
  private RemoteDataBook rdbContacts = new RemoteDataBook();
 
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Initialization
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * Creates a new instance of DBEditFrame for a specific application.
   * <p/>
   * @param pApp the application
   * @throws Throwable if the remote access fails
   */
  public DBEditFrame(Application pApp) throws Throwable
  {
    super(pApp.getDesktopPane());
 
    application = pApp;
 
    initializeModel();
    initializeUI();
  }
 
  /**
   * Initializes the model.
   * <p/>
   * @throws Throwable if the initialization throws an error
   */
  private void initializeModel() throws Throwable
  {
    //we use a new "session" for the screen
    connection = ((MasterConnection)application.getConnection()).
    createSubConnection("apps.firstapp.frames.DBEdit");
    connection.open();
 
    //data connection
    dataSource.setConnection(connection);
    dataSource.open();
 
    //table
    rdbContacts.setDataSource(dataSource);
    rdbContacts.setName("contacts");
    rdbContacts.open();
  }
 
  /**
   * Initializes the UI.
   * <p/>
   * @throws Exception if the initialization throws an error
   */
  private void initializeUI() throws Exception
  {
    UIGroupPanel group = new UIGroupPanel();
    group.setText("Available Contacts");
 
    UITable table = new UITable();
    table.setDataBook(rdbContacts);
 
    group.setLayout(new UIBorderLayout());
    group.add(table);
 
    //same behaviour as centered component in BorderLayout 
    setLayout(new UIBorderLayout());
    add(group); 
 
    setTitle("Contacts");
    setSize(new UIDimension(400, 500));
  } 
 
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Overwritten methods
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * Closes the communication connection and disposes the frame.
   */
  @Override
  public void dispose()
  {
    try
    {
      connection.close();
    }
    catch (Throwable th)
    {
      //nothing to be done
    }
    finally
    {
      super.dispose();
    }
  }
 
} // DBEditFrame
MethodDescription
initializeModelInstantiates the objects for access to the server or to data.
InitializeUILayout of the work screen.
disposeEnds the connection to the server for the WorkScreen and closes the Frame. The connection must not be explicitely closed, as this takes place fully automatically by the GarbageCollector. This is however not a drawback in our first application.
createSubConnectionWe create our own connection to the server. This has the advantage that a separate Lifecycle object is used on the server. This object contains all objects which are needed by the WorkScreen. Once the WorkScreen is closed, the used memory is released. Moreover, each connection can have special parameters and timeouts. The requested Lifecycle object is defined with the class name: apps.firstapp.frames.DBEdit.

The class we will create later.
MemberDescription
connectionThe connection to the server, especially for the WorkScreen. A special communication protocol is used in the background. In our case, it is represented by the class DirectServerConnection.
dataSourceThe DataSource is independent of the communication protocol and takes care of the data transfer between client and server. The connection defines under which name the server-side object is to be found in the lifecycle object.
rdbContactsThe model and the controller for data display.
The name contacts defines under which name the server-side business object can be found.
tableThe view for data display.
The WorkScreen is now ready and can be integrated in the application. We now implement the missing call:
FirstApplication.java
public class FirstApplication extends Application
{
  ...
  ...
  ...
 
  /**
   * Opens the edit screen.
   * <p/>
   * @throws Throwable if the edit frame can not be opened
   */
  public void doOpenDBEdit() throws Throwable
  {
    DBEditFrame frame = new DBEditFrame(this);
 
    configureFrame(frame);
 
    frame.setVisible(true);
  }
 
}  // FirstApplication
MethodDescription
doOpenDBEditThe method can easily throw a Throwable. All application errors are caught by the application and shown in an information dialogue.
configureFrameThis method is provided by the super class and ensures that all frames have a similar look. This also includes the menu icon.
The client implementation is now finished. Before we can use the application, we must create the missing server classes. We create the following classes:
  • File / New / Class
    src.server, apps.firstapp.Application
Application.java
package apps.firstapp;
 
import com.sibvisions.rad.server.GenericBean;
 
/**
 * The LCO for the application.
 * <p/>
 * @author René Jahn
 */
public class Application extends GenericBean
{
 
}  // Application
Description
The class represents the lifecycle object for an application. There is exactly one instance of this class for each application, thereby enabling the use of session-wide objects.
  • File / New / Class
    src.server, apps.firstapp.Session
Session.java
package apps.firstapp;
 
import com.sibvisions.rad.persist.jdbc.DBAccess;
import com.sibvisions.rad.persist.jdbc.IDBAccess
 
/**
 * The LCO for the session.
 * <p/>
 * @author René Jahn
 */
public class Session extends Application
{
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // User-defined methods
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * Returns access to the database.
   * 
   * @return the database access
   * @throws Exception if a connection error occurs
   */
  public IDBAccess getDBAccess() throws Exception
  {
    DBAccess dba = (DBAccess)get("dBAccess");
 
    if (dba == null)
    {
      dba = new HSQLDBAccess();
 
      dba.setUrl("jdbc:hsqldb:hsql://localhost/firstappdb"); 
      dba.setUsername("sa");
      dba.setPassword("");
      dba.open();
 
      put("dBAccess", dba);
    }
 
    return dba;
  }  
 
}  // Session
Description
The class represents a lifecycle object for a session. In our case, a session begins with the login to the application and ends with the logout. There is exactly one instance of this object for each session. This allows objects to be used for the full duration of the login.

Thanks to the inheritance of apps.firstapp.Application it is very easy to use even application objects.
MethodDescription
getDBAccessOpens a new connection to a HyperSQL database, if this has not already happened.

The Exception Handling is taken over by the server.
  • File / New / Class
    src.server, apps.firstapp.frames.DBEdit
DBEdit.java
package apps.firstapp.frames;
 
import javax.rad.persist.IStorage;
 
import com.sibvisions.rad.persist.jdbc.DBStorage;
 
import apps.firstapp.Session;
 
/**
 * The LCO for the DBEdit WorkScreen.
 * <p/>
 * @author René Jahn
 */
public class DBEdit extends Session
{
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // User-defined methods
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  /**
   * Returns the contacts storage.
   * 
   * @return the contacts storage
   * @throws Exception if the initialization throws an error
   */
  public IStorage getContacts() throws Exception
  {
    DBStorage dbsContacts = (DBStorage)get("contacts");
 
    if (dbsContacts == null)
    {
      dbsContacts = new DBStorage();
      dbsContacts.setDBAccess(getDBAccess());
      dbsContacts.setFromClause("CONTACTS");
      dbsContacts.setWritebackTable("CONTACTS");
      dbsContacts.open();
 
      put("contacts", dbsContacts);
    }
 
    return dbsContacts;
  }
 
}  // DBEdit
Description
The class represents the lifecycle object for the DBEditFrame work screen. The objects can only be accessed via the SubConnection of the work screen.

Thanks to the inheritance of apps.firstapp.Session it is very easy to access all Session and Application objects.
MethodDescription
getContactsEnables the access to the database table CONTACTS. The method name must match the object name of the RemoteDataBook: contacts ⇒ getContacts.

The Exception Handling is taken over by the Server.
The application is now fully implemented and ready to run. So as to be able to work with the application, we need a database with the CONTACTS table which we want to access. The configuration of HyperSQL DB is not described in detail in this document, as the examples on the project page are detailed and suffice. In the next chapter, you will find a short summary of the necessary steps. == Create database == The following steps should take place to create and start a HyperSQL DB.
  • Copy the HyperSQL JDBC-Driver (hsqldb.jar) to the directory
    ''../JVxFirstApp/libs/server/'
  • Add the JDBC-Driver to the CLASSPATH of the JVxFirstApp Project
  • Create a database with the alias firstappdb and the following table:
    CREATE TABLE CONTACTS
    (
      ID            INTEGER IDENTITY,
      FIRSTNAME     VARCHAR(200) NOT NULL,
      LASTNAME      VARCHAR(200) NOT NULL,
      BIRTHDAY      DATE,
      STREET        VARCHAR(200),
      NR            VARCHAR(200),
      ZIP           VARCHAR(4),
      TOWN          VARCHAR(200)
    )
  • Start the database, e.g.:
    java -cp ../libs/server/hsqldb.jar org.hsqldb.Server -database.0 
         file:firstappdb -dbname.0 firstappdb
== The first application == Once the database has been started, the application can also be started. The final application should look as follows: The Source Code and the Eclipse project can be found in the Download section.
This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information