Menu

Documentation Version 0.0.4

FullRelation Nano.H5
© Thomas Schneider 2012-2014

Introduction

NanoH5 (or FullRelation) is an UI independent gui implementation framework providing a model driven design (MDA). It is bound to the app framework tsl2.nano.commons and the jpa-service framework tsl2.nano.serviceaccess. It is possible to build a complete html5 application through a given class- or database-model.

  • Everything will be filled for you by defaults - presenting a full application getting a database connection
  • define it or implement it - all object-types have their representation as readable xml-file.

Goals

  • pure model implementation + plattform independency (works on android, too).
  • small, having as less as possible static dependencies to other libraries
  • everything has a default - all defaults are configurable (Convention over Configuration)
  • application, session and entity behaviors are configurable
  • implementation through simple java beans + optional bean presenters
  • you develop ui independent, but are able to use ui dependent extensions.
  • no new language to learn. knowing html5 allows to improve layout and styling.
  • navigates through given beans, showing bean-lists and bean-detail dialogs.
  • resolves all bean/entity relations to be browsed.
  • navigation can be a configurable workflow - or simply an entity browser
  • pre-defines formatting, validation and presentation of relations
  • pure html-5 (no javascript)
  • pure jpa - jpa-annotations are read to resolve attribute-presentation
  • independent of a special o/r mapper. all o/r mappers supporting javax.persistence with an EntityManager are usable.
  • simple database replication on user-loaded data - offline working possible
  • full key-navigation (shortcuts)
  • framework designs interfaces and provides extendable implementations
  • useable as standalone or web-service (with offline access), can connect to application-server or works standalone.
  • many features through nano.common, and nano.incubation like a rule, sql, action engine, network executor etc.
  • handling blobs of data (byte[]) to be presented in html as picture, audio, video or object.
  • planned interfaces:
    ddl-->beans through hibernate-tools
    jpa-->bean through annotation evaluation
    xsd-->bean (not finished yet!)
    java-interface-->java-bean (mock through internal proxy, not finished yet!)

Using the NanoHTTPD Server as base, this client application creates html surfaces, sending them through the integrated server to an html browser. Entry point is the file application.html defining the browser request http://localhost:8067.

It is not a real web-application platform but a simple way to use html5 as graphical user interface - in a standard client application.

The base framework is tsl2.nano.common. It is a full stack framework as simple and generic as possible - without dependencies to other libraries (except: simple-xml).

The data access is done by: * tsl2.nano.serviceaccess * tsl2.nano.directaccess

It is possible to use an ejb container in an application server, but the default is set to use jpa directly on the client (using tsl2nano.directaccess).

Why?

The base frameworks are grown through input of two industrial projects. the first project had to build a software fully configurable through a database. The second was a financial project.

project-environments: * windows-xp, windows-7, windows-terminal-server, ubuntu 12 * oracle 11, hsqldb * glassfish 2.1, toplink * jboss-eap 6.1, hibernate

What is it for?

this software should provide a fast way to create a standard application through a database model. through a complete set of configuration possibilities, a user may fit this application for his requirements. respecting a small set of rules, a software-developer is able to extend that application to do more specifics.

What this framework is not intended to be

  • the web-application mode is not designed or tested for big data transfers or high network traffics.
  • at the moment, only parts of the nano frameworks are used in productive applications.
  • at the moment it is on construction - no guarantee can be given for any function or feature.
  • no particular value is done for graphical design.

Usable modes

  • Client/Server application
  • Web application for small user-groups
  • Standalone or through connection to an application server
  • with or without local replication database
  • Usable as Entity-Browser configuring your data
  • Usable as full-configurable application
  • Usable as full-stack framework to develop model-driven applications

Third Party Libraries

Architecture

The architecture is defined by the application framework tsl2.nano.common. The data and service layer is defined by tsl2.nano.serviceaccess.

Model Driven Architecture (MDA))

Nano.h5 provides mechanisms to create a full configurable application from a given database definition file (ddl).

Creating an UML-Diagram with perhaps ArgoUML, or creating an ER-Diagram with f.e. architect you may generate a ddl script. Nano.H5 provides an ant-script (mda.xml) to generate a hsqldb-database and generating entity beans through hibernate-tools for the given jdbc-connection.

The other option would be to have an existing beans.jar ....

Process Description
  • Ant and hibernate-tools has to be in your classpath or environment directory.
  • Use a tool like ArgoUML or architect to create an UML-Diagram
  • Export the data model to a ddl file (sql statements to create the database). This file must be stored in the environment directory with extension sql (e.g. timedb.sql).
  • start mda.bat to generate the database from ddl file and creating beans.jar through hibernate tools.

Framework mechanisms - how to extend the framework

Configuration through Serialization

The environment and the beandefinition are the main constructs serializing it's properties to the file-system.
...
The BeanDefinition expects only AttributeDefinition_s from deserializings - to be more readable. This means, that extensions of AttributeDefinition are not handled!
...
On the data side, all collections are wrapped into an object of type _BeanCollector
, single instances that are prepared to be presented are wrapped into an object of type Bean. All attributes of a Bean are wrapped into BeanValue_s. The _BeanCollector and the Bean are extensions of BeanDefinition, handling the attributes. While the used xml-serializer Simple-XML is not able to create the desired root instance through reading an xml (we have to define the instance type on calling simple-xml), extensions of a BeanDefinition are handled through a special mechanism, implemented in the class Extension.

Registered services and definitions through the environment

TODO...

Starting / Test

The tsl2.nano.h5 framework can be started through it's jar tsl2.nano.h5-xxxxx.jar. A start script run.bat is available to do this in windows. Starting it, a given directory is used as a kind of workspace where you put all configuration and jar files into to be used. This jars may be ant, an o/r-mapper like hibernate with all it's dependencies. The configuration files are the environment.xml and all xml files describing the presentation of each entity bean. Icons for all buttons and backgrounds are in the icon folder. The main jar file can contain all dependent jar files (as described in the manifest file) or outside in the same directory as the main jar.

A possible start configuratin would be:

  • nano.h5 main directory with:
    tsl2.nano.h5-xxxx.jar containing all dependent jars as described in Dependencies
    tsl.nano.common-xxxx.jar providing bootstrap loading with special classloaders
    ** environment directory like the sample h5.sample

Normally, you will start with an example: download the file h5.sample-hibernate-fulllibs-0.0.3.zip to have an example using lots of features of this project - you have a simple test database and are able to generate your bean jar, see a trivial application-extension, workflow, autorization and rule.

Feel free to test, whether a database-connection of a project you know is working with nano.h5....

Sample Environment: h5.sample

A sample environment is h5.sample, containing all icons, jars and configurations for a project. It may be used for other nano.h5 projects. It uses:

  • ant libraries to generate entitiy beans through hibernate-tools and the sample database
  • hibernate with all dependencies as o/r mapper
  • hibernate-tools
  • hsqldb.jar as jdbc driver for a hsqldb database
  • sample databae timedb
  • sample icons for all buttons

Before you start nano.h5, you should start the sample hsqldb database:

h5.sample/runServer.bat

To start nano.h5 you have to call it with following syntax:

java -jar de.nano.h5.Loader [environment-path (default: config] [http-server-port (default: 8067)]

This call is implemented inside the start.bat script. Use that, if you are on windows.
If you start it on windows, a browser will be opened to show the initial screen:

Now you can login to the sample database. It is fully configurable, which o/r mapper and database should be used. After pressing Ok, a persistence.xml will be generated to be found by the javax.persistence implementation.

All entities of the jar-file, containing the entities, will be listed. You can filter the list and select one or more to edit them.

Then you will get a search page with a search filter and an empty list. Pushing the search-button will create the result list.

If you click a column header (here f.e. comments), the list will be sorted by this column - clicking on that column a second time, the sorting will be done in the other direction. The possible actions will be described in the next chapter.

Extending the Sample

The file h5.sample/environment.xml defines the application behaviour. For further informations read chapter The Environment.
It is possible to change the presentation of each bean. Inside the directory h5.sample/beandef all beans have configuration files to change their presentation and behaviour. If the beandef directory is empty, you can create the bean definitions by clicking on button 'exit' on the top left - this will save the current state and exits the application.

It is possible to create an own java project to define own application and bean behaviour. This is described in chapter Creating an own project.

The Environment

Loading a Nano.h5 application will create and use an environment directory as workspace for it. Resources like icons, configuration xml-file and libraries will be put there - being on top of classpath.

Everything of your application will be accessible through this environment. It provides all system-/ application properties and all application services.

A full list of configuration attributes can be found here

Language and Translations

The messages.properties is the language file to translate every application specific text. You can overwrite it through putting your own file into the environment-directory with sub-directory de/tsl2/nano/h5. All bean or bean-attribute-names will be translated.
All framework specific and generic texts will be translated through the internal de.tsl2.nano.messages.properties.

Application and Page Actions

On top of each html page you will see on the left side an application icon (clicking on it, it tries to load the help file nanoh5.html). On top right, all page-specific buttons are shown. The following list tries to describe them. They depend on the current type of bean. A bean list will have other buttons than a beans detail page.

Bean's search page top buttons

  • select all: will select all listed items to be accessed through 'open' or 'delete' buttons
  • de-select all: will de-select all listed items

All other page buttons (on the top)

  • print: shows a page with non-interactive presentation of the current page. use the browsers back-button to return to the application
  • export: shows a page with a pure text presentation like a csv file - to be copy/pasted into another file. use the browsers back-button to return to the application.
  • document: if configured in environment.xml, a text-file (a rtf-file is possible, too) can be search and replaced with key/values of the current page.
  • configure: ???
  • help: if a help html-file for the current page/bean can be found, it will be shown. use the browsers back-button to return to the application.
  • refresh: all configurations will be reloaded
  • exit: saves all current configuration values - creating files to be used to change properties - and stops the current user-session.
  • configure: goes into a configuration mode for the current page/bean.

Bean search and manipulation buttons

  • search: searches for all beans of the current type and filter.
  • reset: resets all search-filter fields and the result list
  • open: opens all selected beans. only active, if on page-creation at least one selected items is available.
  • new: creates a new item of the given type.
  • delete: deletes all selected items.

Bean detail buttons

  • save: saves the current bean.
  • close: closes the current page, returning to the last one without saving.

Dependencies

Static Dependencies (direct referenced by tsl2.nano)

  • simple-xml-2.7.jar

Dynamic Dependencies (used by tsl2.nano, but through compatibility-layer)

  • XmlUtil: velocity-1.6-dep.jar
  • CommonTest: junit-4.8.2.jar
  • AntUtil: ant-launcher.jar, ant.jar, ant-nodeps.jar
  • BeanEnhancer: javassist-3.12.0.GA.jar

No Dependencies, but useful to do the work

  • jdbc database driver (like hsqldb.jar)
  • jpa o/r mapper (like hibernate, toplink or ormlite)
  • generator tool to create entity beans (like hibernate-tools)

Hibernate 4 for example would have the following dependencies:

  • commons-collections-3.2.1.jar
  • commons-logging-1.1.1.jar
  • commons-beanutils-1.8.0.jar
  • commons-io-1.3.2.jar
  • commons-lang-2.4.jar
  • commons-codec-1.6.jar
  • dom4j-1.6.1.jar
  • javassist-3.12.0.GA.jar
  • antlr.jar

Specifying Rules, Queries and Actions to be used on Beans and Attributes

To do a structured work on a usable specification, rules, queries and actions can be defined before implementing or configuring the presentation. This is done by creating these items as xml-files inside the environments specifiation directory. To see how it works, hit the application button 'sample-codes' and have a look into the specification directory.

The ScriptTool

After login, you are able to execute queries and scripts like ant-scripts. You have to enable it in your environment.xml to see the ScriptTool in the list of BeanCollectors.

Layout and Styling

Using CSS

Html styles can be added through import of css files. On building each html page, the file meta-frame.html will be searched inside the environments css directory: css/meta-frame.html.
The meta-frame.html defines the html header and an empty body. Inside the header you should define the css style files you want to be used. The style files must define a class menu through the tags ul and li. Then, each page will have a menu at the top - instead of a button panel.

Configuring Presentation, Layout and Constraints

Each bean and each bean-attribute can define a layout and layout-constraints through it's presentable object (see class IPresentable). It is easy to do layout definitions programmatically through the BeanPresentationHelper, but in this chapter we describe only the xml configuration.

TODO describe

Bean-Collector Presentation

A bean-collector shows a set of bean-instances. The collector is defined by a bean-type or directly by a collection of items. The bit-field mode defines, which actions can be done on a bean-collector.

Mode: * Searchable: a search and reset action can be done on that bean-collector * Filter: a table filter will be provided * Editable: an open action is available * Creatable: new and delete actions are available * Assignable: an assign action can assign the current selection to the previous edited bean.

If an item was selected and opened, this item (a Bean) will be presented as detail in a new page.

direct queries through QueryResult

To define direct sql or jpa-ql queries beside the standard mechanism though compiled beans you have the possibility to show list of values direct through QueryResult which is an extension of BeanCollector.
QueryResult_s can be defined through the _ScriptTool. There you can test your queries and save it as QueryResult. The QueryResult will be loaded into the list of available bean-collector on next application start.

direct controlling a set of beans through the Controller

The Controller is an extension of BeanCollector to present a collection of beans through their actions. Theses actions should be ease change-actions for attributes - like de- or increasing their values. This feature should be used for touch-screen applications.

Bean Presentation

...

Multiple Value Relations

...

Value Groups and Sub-Panels

...

Attribute Presentation

...

Rule-Attributes

...

Showing calculated values through integrated rule engine

...

Presenting data or media like images, audio, video

If an attribute holds data of type byte[], this may be presented as image or any other non-textual type. The default-mechanism will declare the attributes type as TYPE_DATA which will save the attributes value to a temporary file to be sent through http to the client and shown as image - or if a special style was defined, as embed, object, audio, video, canvas or device - as known from HTML5 embedded content tags.

Working on a page using the Keyboard

The gui provides shortcuts/hotkeys for each button to activate. As html provides basic field tabbing (of course, that depends on your browser), it should be possible to work fast only with your keyboard.

On entering a search-page, the search button will have always the default-focus. If a search was done, the open button will have the default-focus.

On entering a detail-page, the save button, if existing, will have the default-focus.

Actions and Buttons

Each action is able to define a shortcut (keystroke). if not set, the default will be evaluated through the actions name. If that name contains a '&', the following character will be used as shortcut - if no '&' is contained and no keystroke was defined, the first character of the name will be used. E.g., if the name/label is "Clo&se", you have to hit ALT+s to activate this action.

Tableheader Buttons

Each table of beans will provide a table-header with Buttons to do up/down sorting (on first activation, up-sorting will be done, on second activation, down-sorting). On these Buttons we can't use the algorithm above to avoid shortcut collisions. These buttons will have shortcuts depending on their indexes. So, the first table-header column will be activated through a hit to ALT+1.

Networking Modes

The Nano.H5 application can be started in different modes.

  • Standard Single Access Mode:
    environment property http.ip is localhost. no other network node is able to connect to the application. useable as a simple client/server application.
  • Network Single Access Mode:
    environment property http.ip is a network ip of your system. all network nodes are able to connect to the application of your system, using one environment and session. useable in an intranet to do some teamwork.
    Network Multiple Access Mode:
    environment property http.ip is a network ip of your system. all network nodes are able to connect to the application of your system, using their own environment and session. may be used in an intranet.
    Network Multiple Security Mode:
    ** environment property http.ip is a network ip of your system. all network nodes are able to connect to the application of your system, using their own environment and session working with ssl (under construction!). may be used in the internet.

Authorization, Roles and Permissions

Permissions are set after connecting to the datasource through the persistence-unit. The permissions define activation of buttons and visiblity of fields. if all fields are invisible, no data and actions are available!

The application class NanoH5 has a method createAuthorization() that defines a subject with a user-principal and it's roles, defined by permissions. If a file [username]-permissions.xml is found, it will be used to fill the subject - if not, an admin-role with a wildcard-permission will permit anything!

Permissions contain a name - perhaps ended by a wildcard - and comma separated actions (a wildcard is possible, too. The permissions work on actions and data. The BeanContainer provides to ask for permissions: call BeanContainer.instance().hasPermission(name, actions) to check access to a call or to any data. The _Enviroment provides access to the implementation of _IAuthorization. Call _Environment.get(IAuthorization.class).hasAccess(name, actions) to check for permissions.

The framework does all checks for you. But if you need extended access to authority informations, read the following details.

Permissions on actions

To check whether a user can access a button (action) you call the hasAccess of IAuthorization or hasPermission of BeanContainer with the id of the action. The second method parameter may be a wildcard (*) or executable.

Permissions on data

To check whether an entity should be accessed by the current user, you call the hasAccess of IAuthorization or hasPermission of BeanContainer with the class-name + toString() representation of the current object. The second method parameter tells whether to read or write the object.

A navigator will guide the user through his application session. Before/after each page, the navigator will evaluate the next bean to present. This may be list of entities or simply the details of an entity.

The application can work on a simple navigation stack - a simple implementation is provided by the EntityBrowser. If a configuration file workflow.xml is found inside your environment-path, this workflow will be used, to navigate the user through his application session.

The EntityBrowser

The EntityBrowser works on a Navigation-Stack, putting all available entity-types to the first bean-collector to be able to browse through all beans and data.

A configured Workflow

If a configured workflow is available, this workflow will be used as navigator.
A workflow holds one or more activities defined by an enabling condition and an execution expression. After finishing a page, all activities will be checked for their entry/enabling condition. Only one activity should have a positive condition. This activity will be executed. The execution will be calling an EJB-QL given by the expression and returning the result of that query as next navigation bean.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<workflow>
   <activity name="times">
      <condition>!times.activated</condition>
      <expression>select t from Times t where t.project.id = :prjname</expression>
      <query-parameter length="1">
         <parameter>prjname</parameter>
      </query-parameter>
   </activity>
</workflow>

All parameters are stored and given by the workflow. The following parameters will be stored automatically: * response = {last user action name} * {activity-name}.size = count of entities found by your activity expression * {activity-name} = if your activity expression found exactly one entity, this entitiy will be referenced here. * {activity-name}.activated = true, if this activity was already activated

Use that parameters for your activity condition.

TODO: use bean-path to inspect condition expressions like 'times.type = F'.

Database Replication - Working Offline

It is possible to replicate the data loaded from remote database. The replication will be done through a second persistence-unit 'replication'. For each user an own local replication database will be created.

The replication is done in it's own thread to avoid conflictions with the application. The O/R mapper will create all tables through bean informations. A special bean holds the information (time, id, change-type) about the changes done by the user. All data, loaded and edited by the current user will be replicated to a local database.

The replication connection is configurable like the persistence-unit is. But at the moment, only the combination hsqldb and hibernate are tested - and it's only usable without application-server!

The replications hsqldb database will be started internally.
- database: replication-<user-name>
- port: 9898</user-name>

Using an Applicationserver

If you don't want to have a standalone appliation, you are able to use an application server like jboss. To do this you must have:

  • the application servers client libraries must be in your classpath. so copy them to your environment directory. with jboss eap 6.1 it would be jboss-client.jar.
  • any entity beans and remote interfaces of your ejb's should be in your classpath. so copy the jar holding them to your environement directory.
  • of course, the entity beans must be deployed to that server perhaps in a war-file.
  • be sure to have tsl2.nano.serviceaccess packed into that war-file. the service *IGenericService is essential.
  • add environement property 'applicationserver.authentification.service' (default: org.nano.[environment-name].service.remote.IUserService) with service class name.
  • add environment property 'applicationserver.authentification.method' (default: login) with service method to call. this method has to have two string-parameters for user and password. the method has to call ServiceFactory.instance().createSession(userObject, mandatorObject, subject, userRoles, features, featureInterfacePrefix)
  • on the login page input user and password
  • create a jndi.properties file in your environment. with jboss this would look like the following:

Example jndi for jboss eap 6.1

java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory
java.naming.factory.url.pkgs=org.jboss.ejb.client.naming
java.naming.provider.url=remote://localhost:4447
java.naming.security.principal=<jndi-prefix>
java.naming.security.credentials=<perhaps the application name>
jboss.naming.client.ejb.context=true

Example authentication service method

UserService.authenticate(String user, String password) {
...
    //fill the server side ServiceFactory
    if (!ServiceFactory.isInitialized()) {
        ServiceFactory.createInstance(this.getClass().getClassLoader());
        //registriere shared und error messages
        ResourceBundle bundle = ResourceBundle.getBundle("org.mycompany.myproject.shared_messages",
            Locale.getDefault(),
            this.getClass().getClassLoader());
        Messages.registerBundle(bundle, false);
        bundle = ResourceBundle.getBundle("org.mycompany.myproduct.error_messages",
            Locale.getDefault(),
            this.getClass().getClassLoader());
        Messages.registerBundle(bundle, false);
    }

    /*
     * a user session will be created on server side.
     */
    final Collection<String> userRoles = new LinkedList<String>();
    final Collection<String> mandatorFeatures = getMandatorFeatures();
    ServiceFactory.instance().createSession(null, getMandant(), null, userRoles, mandatorFeatures, null);
...
}

Generating your Entities

It is possible to generate your entity beans through a tool like hibernate-tools. for an example have a look at the sample-project nano.h5.sample.

If hibernate-tools creates your beans, it may create additional beans to use composed primary keys. To use them with nano.h5 you should extend these beans, to fill the id-bean from dependent entity fields. So, enhance the setter methods of this unique fields to fill the id-beans corresponding field, too.

class MyBean {
    @Id MyBeanId id;
    @Column MyType myUniqueField;
}

class MyBeanId {
    String field1;
    String myUniqueFieldId;
}

Developing, Deploying and Debugging

If you change sources of this plugin, you should start ant script eclipse-tsl2.nano.h5.xml with target tsl2nano.eclipse.h5.export and after that the 'deploy' target of your main project.

Normally, you don't have to create html-pages by yourself, but if you are interested in html5, have a look at the following tutorials/references: * W3C-Html5-Reference * Html-5.com * Webkompetenz * Html5 Poster

To analyse the html-page in your browser, for example in your Chrome-Browser, you can analyse components by mouse-right-click on analyse element to debug and change the current bean presentation.

jar-library dependencies

  • velocity-1.6-dep.jar: XmlUtil.transform (using CompatibilityLayer)
  • TODO: describe all jars!

Creating an own project

Nano.H5 is based on the framework tsl2.common and it's bean package. The bean package provides a generic and comfortable way to describe your user interface. If the standards of Nano.H5 doesn't fulfil your needs, you can develop own beans on top of Nano.H5 - without creating special gui-elements or interaction, this will be done by the framework - generating html-pages through the BeanPresentation implementation. Of course, this implementation is extendable, too. Have a look at chapter Dependencies to know, which jar-files you should copy to the environment directory (f.e. h5.sample).

If you download and unpack test.h5.sample, you yield an eclipse project referencing the tsl2.nano jar-files.

File Structure:

Auflistung der Ordnerpfade
Volumeseriennummer : 0059E65C 9A6F:E968
C:.
|   .classpath
|   .project
|   application.html
|   debug.log
|   environment.xml
|   h5.sample.log
|   run.bat
|   tree.txt
|   tsl2.nano.common.1.0.0.jar
|   tsl2.nano.h5.0.0.1.jar
|   tsl2.nano.h5.default-resources.jar
|   
+---h5.sample
|   |   ant-launcher.jar
|   |   ant-nodeps.jar
|   |   ant.jar
|   |   antlr-2.7.6.jar
|   |   antscripts.properties
|   |   antscripts.xml
|   |   application.html
|   |   commons-collections-3.2.1.jar
|   |   commons-lang-2.4.jar
|   |   dom4j-1.6.1.jar
|   |   environment.xml
|   |   freemarker.jar
|   |   h5.sample.sql
|   |   hibernate-tools-3.4.0.CR2.jar
|   |   hibernate.reveng.xml
|   |   hibernate3.jar
|   |   hibtool.xml
|   |   hsqldb.jar
|   |   javassist-3.12.0.GA.jar
|   |   jdbc-connection.properties
|   |   jdbc-connection.properties.bak
|   |   mda.bat
|   |   mda.properties
|   |   mda.xml
|   |   mypersistence-bean.xml
|   |   mypersistence-bean.xml.bak
|   |   mypersistence.xml
|   |   mypersistence.xml.bak
|   |   ojdbc14_g.jar
|   |   runServer.bat
|   |   shell.xml
|   |   slf4j-api-1.6.1.jar
|   |   timedb.jar
|   |   timedb.lck
|   |   timedb.log
|   |   timedb.properties
|   |   timedb.script
|   |   trang.jar
|   |   tsl2.nano.h5.default-resources.jar
|   |   
|   +---beandef
|   |       project.xml
|   |       start.xml
|   |       times.xml
|   |       
|   +---generated-bin
|   |   \---my
|   |       \---app
|   |               Loader.class
|   |               MyApp.class
|   |               
|   +---generated-src
|   |   \---my
|   |       \---app
|   |               Loader.java
|   |               MyApp.java
|   |               
|   \---META-INF
|           persistence.xml
|           
|           
\---META-INF
        MANIFEST.MF

The implementation Loader.java and MyApp.java provide an own entry for the application. The Loader only tells java to load MyApp. MyApp overwrites three methods. Only createBeanCollectors defines own beans and an own navigation stack.

Here is the implementation:

Loader

public class Loader extends AppLoader {
    public static void main(String[] args) {
        new Loader().start("my.app.MyApp", args);
    }
}

MyApp

public class MyApp extends NanoH5 {
    private static final Log LOG = LogFactory.getLog(MyApp.class);

    /**
     * @throws IOException
     */
    public MyApp() throws IOException {
    }

    /**
     * @param ipport ip + port
     * @param builder
     * @param navigation
     * @throws IOException
     */
    public MyApp(String ipport, IPageBuilder<?, String> builder) throws IOException {
        super(ipport, builder);
    }

    @Override
    @SuppressWarnings("rawtypes")
    protected BeanDefinition<?> createBeanCollectors(List<Class> beanClasses) {

    /*
     * Sample Workflow with three activities
     */
        LinkedList<BeanAct> acts = new LinkedList<BeanAct>();
        Parameter p = new Parameter();
        p.put("project", true);
        p.put("prjname", "test");
        acts.add(new BeanAct("timesByProject",
            "project&true",
            "select t from Times t where t.project.id = :prjname",
            p,
            "prjname"));
        p = new Parameter();
        p.put("prjname", "test");
        acts.add(new BeanAct("organisation",
            "!organisation.activated",
            "select p from Organisation p where ? is null",
            p,
            "prjname"));
        p = new Parameter();
        p.put("organisation", "test");
        acts.add(new BeanAct("person",
            "organisation.activated & (!person.activated)",
            "select p from Person p where p.organisation = ?",
            p,
            "organisation"));
        Workflow workflow = new Workflow("test.workflow", acts);
        Environment.persist(workflow);

        /*
         * use a rule with sub-rule
         */
        LinkedHashMap<String, ParType> par = new LinkedHashMap<String, ParType>();
        par.put("A", ParType.BOOLEAN);
        par.put("x1", ParType.NUMBER);
        par.put("x2", ParType.NUMBER);
        Rule<BigDecimal> testRule = new Rule<BigDecimal>("test", "A ? (x1 + 1) : (x2 * 2)", par);
        testRule.addConstraint("x1", new Constraint<BigDecimal>(BigDecimal.class, BigDecimal.ZERO, BigDecimal.ONE));
        testRule.addConstraint(Rule.KEY_RESULT, new Constraint<BigDecimal>(BigDecimal.class, BigDecimal.ZERO,
            BigDecimal.TEN));
        Environment.get(RulePool.class).add("test", testRule);

        //another rule to test sub-rule-imports
        Environment.get(RulePool.class).add("test-import",
            new Rule<BigDecimal>("test-import", "A ? 1 + §test : (x2 * 3)", par));

        BigDecimal result =
            (BigDecimal) Environment.get(RulePool.class).get("test-import")
                .run(MapUtil.asMap("A", true, "x1", new BigDecimal(1), "x2", new BigDecimal(2)));

        LOG.info("my test-import rule result:" + result);

        /*
         * define a query
         */
        String qstr = "select db_begin from times t where t.db_end = :dbEnd";

        HashMap<String, Serializable> par1 = new HashMap<>();
        Query<Object> query = new Query<>("times.begin", qstr, true, par1);
        QueryPool queryPool = Environment.get(QueryPool.class);
        queryPool.add(query.getName(), query);

        /*
         * define an action
         */
        Method antCaller = null;
        try {
            antCaller = ScriptUtil.class.getMethod("ant", new Class[] { String.class, String.class, Properties.class });
        } catch (Exception e) {
            ManagedException.forward(e);
        }
        Action<Object> a = new Action<>(antCaller);
        a.addConstraint("arg1", new Constraint<String>(Environment.getConfigPath() + "antscripts.xml"));
        a.addConstraint("arg2", new Constraint<String>("help"));
        Environment.get(ActionPool.class).add("ant", a);

        /*
         * define a Controller as Collector of Actions of a Bean
         */
        final BeanDefinition timeActionBean = new BeanDefinition(Times.class);
        timeActionBean.setName("time-actions");
        BeanDefinition.define(timeActionBean);
        final Controller controller = new Controller(timeActionBean, IBeanCollector.MODE_SEARCHABLE);
        timeActionBean.getActions().clear();
        timeActionBean.addAction(new SecureAction("times.actions.one.hour.add", "+1") {
            @Override
            public Object action() throws Exception {
//                this.shortDescription = 
                return controller;
            }
        });
        timeActionBean.addAction(new SecureAction("times.actions.one.hour.subtract", "-1") {
            @Override
            public Object action() throws Exception {
                return controller;
            }
        });
        timeActionBean.saveDefinition();
        controller.saveVirtualDefinition(timeActionBean.getName()+ "-controller");

        /*
         * define a specific bean-collector presenting a query (SQL or JPA-QL)
         */
        qstr = "\nselect t.day as Day, p.name as Project t.dbbegin as Begin, t.dbend as End, t.pause as Pause\n"
            + "from times t join project p on p.id = times.projid\n"
            + "where 1 = 1\n";

        query = new Query<>("times-overview", qstr, true, null);
        queryPool.add(query.getName(), query);

        QueryResult qr = new QueryResult<>(query.getName());
        qr.saveVirtualDefinition(query.getName());

        /*
         * define own beans to present your entities another way
         */
        Collection<Times> times = Environment.get(IBeanContainer.class).getBeans(Times.class, UNDEFINED, UNDEFINED);

        BeanCollector<Collection<Times>, Times> beanCollector =
            new BeanCollector<Collection<Times>, Times>(times, BeanCollector.MODE_ALL);

        AttributeDefinition space1 = beanCollector.getPresentationHelper().addSpaceValue();
        beanCollector.addAttribute("path-test", new PathExpression<>(Times.class, "id.dbBegin"), null, null);
        beanCollector.addAttribute("rule-test", new RuleExpression<>(Times.class, "§test-import"), null, null);
        beanCollector
            .addAttribute(
                "sql-test",
                new SQLExpression<>(
                    Times.class,
                    "?" + query.getName(), Object[].class),
                null, null);
        beanCollector.addAttribute("virtual-test", "I'm virtual", null, null, null);
        beanCollector.addAttribute("picture", new Attachment("picture", Environment.getConfigPath()
            + "/icons/attach.png"), null, null);
        beanCollector.setAttributeFilter("path-test", "creation", "dbEnd", "pause", space1.getName(), "project",
            "comment");
        //more fields on one line (one field has grid-width 3)
        beanCollector.getPresentable().setLayout((Serializable) MapUtil.asMap(L_GRIDWIDTH, 12));
        //let the field 'comment' grow to full width
        beanCollector.getAttribute("comment").getPresentation()
            .setLayoutConstraints((Serializable) MapUtil.asMap(ATTR_SPANCOL, 11, ATTR_BORDER, 1, ATTR_SIZE, 150));

        /*
         * add a specified action
         */
        beanCollector.addAction(new SpecifiedAction<>("ant", null));

        /*
         * save it as beandef
         */
        BeanDefinition.define(beanCollector);
        beanCollector.saveDefinition();

        /*
         * define your own navigation stack
         */
        return beanCollector;
    }

    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        startApplication(MyApp.class, MapUtil.asMap(0, "http.connection"), args);
    }
}

Performance

Generic features like authorization for actions and data, filtering of columns and field, loading bitmaps etc. may slow down the application performance. The following tips may increase the performance:

set the following environment.xml properties:

  • extract all sub-jars from main jar 'nano.h5.xxx.jar'. nested jar loading is really slow.
  • disable check of data-permission: check.permission.data=false
  • set log-level to info: default.log.level=8
  • disable multiple field/column filter: collector.use.multiple.filter=false
  • get only 50 lines per search: service.maxresult=50
  • ???: bean.use.beanpresentationhelper.filter=false
  • turn off replication: use.database.replication = false

Problems and Solutions

  • Beans showing currencys with EURO can't be saved
    Set the character encoding of your browser's current page to UTF-8. E.g. in Chrome: Menu=>Tools=>Enconding

Changelog

| Version | Date | Description |
| 0.0.1 | 06.07.2013 | First alpha Version
| 0.0.2 | 21.09.2013 | beta Version (full basic feature implementation)
| 0.0.3 | 01.01.2014 | beta Version (basic features + authorization + workflows + rules)

TODOs

  • (v) BeanCollector.createItem() --> replace common BeanUtils call to be able to run on android
  • (v) main arguments: bean-jar, jdbc-url, user, passwd
  • (v) Show count of items
  • (v) Navigation Links have Problems
  • (v) show logging
  • (v) visible icons read by page
  • (v) Button-Panel for
  • (v) Use Xml-Configuration for BeanDefinitions
    (v) Print
    (v) Export
    (v) select all
    (v) deselect all
  • (v) Use Environment
  • (v) Extend BeanContainer:
    (-) new action: 'getValueBetween()'
    (v) extend all finders with start index (see maxresult) to have a result range
    ** (v) beancollector with next() and previous() data (using 'start' index and 'maxresult')
  • (v) tooltips for buttons
  • (v) check running in java 7
  • (v) add java-compiler (tools.jar, 12MB) of jdk6
  • (v) create ide for sample project
  • (v) If search result is only one element, select it
  • (v) hibernate-tools: (solved through beancollector.createNewItem() setting UUID
  • (v) on multiple selection, put all selected elements to the stack
  • (v) Problem: creating a new element, copying an existing one, one-to-many connections will be lost
  • Dependencies
    (v) Log and LogFactory
    (v) DefaultFormat: StandardToStringStyle and ToStringBuilder
    (v) StringUtil --> BeanUtil
    (v) BeanClass --> StringUtil --> CollectionUtil --> DefaultFormat
  • (x) Application Menu: reset (--> caches, environment, navigation), restart, login, logout
  • (x) default attribute names without @id field
  • (x) Nesting Beans
  • (x) Bean with Layout
  • (v) Right-Alignments for Numbers
  • Problem on NanoHttp cancelling button panel (sometimes)
  • (-) Check for single selection
  • Check navigation (check input on button action like 'open' without selecting an item. At the moment it will return to the last bean)
  • Styling (Collector, Details)
  • Show Progress-Page (using Statistics)
  • Html-Table:
    (v) Sorting-Header
    (v) Previous, Next
    Style (of sorting header etc.)
    up, down (for sorting values)
  • configure to have generated IDs
  • read documentation
  • Searches on big data:
    first count data
    (v) button to show one-to-many in table
    ** use thread to be interupted
  • (v) internal export and view (replacing ant-like variables and showing the document)
  • generate const class from property file
  • (x) create xsd through CommonTest with trang.jar
  • (x) add configuration action (html-tool to edit xml files)
    ** ConfigBeanContainer to configure BeanDefinition for special beans
  • Nice-To-Have
    eval validation annotations
    BeanPresenterHelper: test OptionsWrapper
    min-search-field + button ==> max-search-field visible. standard: filtering with astericks
    add navigation to new sub-class of beandefinition
    create wiki-logger
    envolve logictable and/or tableprocessor
    create GenericOperator from SOperator to read available Operations from xml.
    eval language per session
  • Refactoring:
    (v) RegularExpressionFormat ==> RegExpFormat
    (v) refactore ScriptUtil: extract Ant calls
    (v) util.bean ==> bean
    extract bean-package as project
    nano.h5 ==> fullrelation
    (?) refactore environment property names to use logic path-algorithm
    (x) file-access: use Environment.getResource() reading through jar or file system
    extract api
  • Interfaces:
    java-interface-jar filled with BeanProxy to be used as mocks
    reading xsd through dom - creating beandefinitions (as xml)
    ** BeanEnhancer enhancing Beans having only attributes with getters/setters
  • Replication / Offline
    (-) FileBeanContainer serializing all lists of all BeanCollectors
    (-) GenericBeanContainer using filled FileBeanContainer re-attaching all serialized bean lists
    ** mechanism to synchronize local and remote database - no serialization needed.
  • Validate against Html5-xsd in debug mode
  • include LogicTable?
  • (x) check starting application multiple times
    depends on the datamodel: gruppe --> grupperolle(only for specific gruppe) --> rolle
    The new item has to be put to the list of it's parent container. This list has to be saved before the new item!
    ** The beancollector now holds a
  • Problem: Filtering on Entities doesn't work (findBetween is not able to do a between for 'entity-columns')
  • Problem: Filtering BeanCollectors of Entities doesn't work after sorting twice
  • internationalization: english RegExpFormat, messages.properties
  • (x) remove config path from environment (-->transient)
  • dynamic jar-loading inside used standard jars does not work without static entry in manifest
  • Argo-UML 0.34
    ** how to create ddl from model
  • PowerDesigner
    (v) create ant-script:
    (v) sql-statements with ddl
    (v) hibtool hbm2java
    (v) replace jdbc-connection-properties
    (v) start nano.h5
    jmeter integration test
    ** automated crud test (pushing search/new/delete buttons for all entity types), profiling and counting errors in log-file
  • multiple type/format evaluation in BeanValue (new member for type?) Presentable and BeanPresentationHelper
  • (x) permission configuration
  • waiting message - new thread, answering on finish (e.g. on generating)
  • provide last exception of log-file
  • ( ) use actual h2 or hsqldb
  • (-) extend layout-managment for nested beans <- extend your bean-definition with attributes of other beans.
  • (x) generic navigation through hsql statements
  • ( ) bean navigation actions
  • ERRORS
    hsqldb 1.8 is not able to do select max(count(color)) from Colors group by color
    hibernate3 is - on special circumstances - not able to load fields with empty ('') strings. This results in an java.lang.StringIndexOutOfBoundsException: String index out of range: 0
    failure: presentable.layout --> simple-xml: Transform of class java.util.LinkedHashMap not supported
    (v) failure: sorting numbers/currencies sorts as strings
    BeanPresentationHelper.defineAdditionalAttributes(): how to avoid javaassist class
    presentation not written to xml --> see first failure
    every bean gets a new beandef copy with copies of attributedefs --> attributedef evaluations for every bean!
    one-to-many: if no cascade-type is defined,the attribute should not be editable!
  • hibernate-tools generates id-beans like times-->timesid.
    (x) check for @Id* is no standard-java-type and environment.show.id.fields is true
    (x) BeanPresentationHelper fills all id-bean fields as virtuals to the main bean
  • on export, the filtered names (like id) are given --> nullpointer
  • performance/memory: create only specific bean/beanvalue instances for changed values - use definition-instances if possible.
  • field-order of bean-def may change after new compile --> serializing/deserialings will differ, see CommonTest

  • Value class extends attributedefinition and beanvalue

  • RuleAttr --> RuleValue?
  • temp value registering through environment
  • all generic interfaces registered in environment (IAttributeDefinition, IBeanDefinition, IBeanContainer, ..) to be extendable

  • (v) refactore attribute-def-hierarchy: attributedefinition should not extend beanattribute. what to do with beanvalue?
    ** how to fill virtual beans ? default-values may be checked with errors, serializings...?

  • AttributeConfiguration with value-expression
  • Views with expression as listing output
    DirectSQL: SQL or HQL
    TableProcessor
    ** LogivView: LogicTable
  • JMeter as macro configuration
  • html-frames as perspective (left side: beans and views)
  • refactore ForwardedException. delete FormattedException. Stacktrace with member-info

  • TESTS
    ( ) test with multi values - using best id's
    (-) test on android
    no datasource for Sqlite available - apache BasicDatasource uses JavaBeans what is not usable on android
    ORMLite (4.47) not usable through persistence.xml because no EntityManagerFactory/EntityManager implementation available
    languages
    on appserver

  • extract apploader: common main, classloader, execution

[GLOSSARY]

Posted by Thomas Schneider 2014-03-21

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.