configure a loadable application

Archive

Let's start with the most important requirements, that your jarfile will be accepted as a loadable application:

  • The MANIFEST.MF needs an entry Implementation-Type with value "Application"

  • MANIFEST.MF needs an entry Application-Context which is the path to an XML-file. This path must conform Unix-path-notation, which means case-sensitive and path delimiter is "/".

  • The libraries, your applicatino depends on, must be noted at the Class-Path entry of MANIFEST.MF.
    You'll need to adapt your library paths to this runtime environment:
    below the directory, where SRStarter.jar is located, exists a directory lib, that contains all dependencies. Beside it, there's a directory ext for extensions (like your application) and a directory srv for the system services.

    Your Class-Path-entries must be relative paths, which means, if your application depends on glazedlists_java15.jar, this Class-Path-entry has to be noted at MANIFEST.MF as lib/glazedlists_java15.jar

Context

The default configuration of your application will be noted at so called context. That is an IOC-container in springframework words and will be defined as:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 ...
<beans>
   

Don't keep your eyes on the details above - just take it as an envelope for your definitions

Let's go ahead for the important parts of a context definition. First of all a defintion of the PreferencesConfigurer is needed. This class does the job to overwrite the declared defaults with the values read from users environment.

<bean id="placeHolderConfigurer" class="de.schwarzrot.data.access.pref.PreferencesConfigurer">
   <property name="locations" value="de/schwarzrot/sample/app/sample.properties" />
   <property name="searchSystemEnvironment" value="true" />
   <property name="systemPropertiesMode" value="1" />
   <property name="applicationName" value="Sample" />
   <property name="schemaName" value="sr" />
</bean>

What does each parameter stand for?

locations
The path of a properties file with your defaults in case there are no values in user environment yet.
searchSystemEnvironment
a value of "true" indicates, that user data will be looked for, "false" ignores them.
systemPropertiesMode
indicates, that properties can be overwritten via commandline parameters
applicationName
is the root level of java preferences. At linux systems, it will be a directory
schemaName
the Schema-identifier for configuration entities. At linux systems it will be a directory

Note: Java-preferences will be handled transparently by SRJRCFrames, which means, there's no difference to other persistence targets like SQL-database. Same transparency is true for the distinction of system- or user-preferences, so you don't have to care about preferences paths or nodes at application level.

The PreferencesConfigurer-instance assists the management of configurationstuff, so your real configuration will follow ...

Text and Image handling

To ease the translation of applications, it is fundamental to separate texts from application sourcecode. That's what resource files are for. A resourcefile is just a file, that will be stored in a jarfile and which is not a compiled java source. A resource may be a textfile or a binary file (like images or the like).

SRJRCFrames knows two main interfaces to resources, that will be used at application level (the third is part of black magic). MessageSource-services are the application servants.

The application messages are held by "messages.properties", which is the file name for the default language. All other languages have the country shortcut attachted to the filename, so german messages are held in a file "messages_de.properties".

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
   <property name="basenames">
      <list>
         <value>de.schwarzrot.recmgr.app.ui.messages</value>
         <value>de.schwarzrot.recmgr.app.ui.images</value>
      </list>
   </property>
</bean>

Environment

Configuration entities will be stored using java preferences - it makes no sense, to read from a database how to access the database. So local user properties are vital. But at application level, there's no need to distinct between configuration entities and other (database) entities, that's why SRJRCFrames uses the same application code for all persistence. The separation of user- and system preferences is used by SRJRCFrames that way, that the system preferences may contain defaults for the user settings, but the system settings are not changeable for a normal user.

SRJRCFrames uses different paths for system- and user-preferences. System-properties will be stored, using the path of the class SystemDefault. That class can not be instantiated
The paths of user properties start with the applicationName, followed by the schemaName. Finally the real path of the configuration class is added.

Configuration-Entity

Configuration entities are decendants of the class AbstractConfigBase and the Entitätsmanager, that performs the persistence jobs for preferences is registered for AbstractConfigBase.

Additionally to the rules of "normal" entities, you have to keep in mind these points:

a configuration entity is ever a system class! So public final boolean isUserType() of AbstractConfigBase returns always false. But you can mark single properies as user properties, see getUserAttributes. The following code snippet is from ApplicationConfig and constitutes, that position and size of the application window may be stored in the user environment:

@Override
public List getUserAttributes() {
   List rv = new ArrayList();

   rv.add("startupWidth");
   rv.add("startupHeight");
   rv.add("startupX");
   rv.add("startupY");

   return rv;
}

As noted earlier, all access to persistence are the same for all entities, so to save the configuration of our application, we could use this (the storing of application configuration is triggered at closing an application, so you don't need to care about it):

if (taFactory == null)
    taFactory = ApplicationServiceProvider.getService(TransactionFactory.class);

Transaction ta = taFactory.createTransaction();

ta.add(new TOSave(getAppConfig()));
ta.execute();