Copyright © 1999-2008 UCS - unique computing solutions gmbh
Table of Contents
List of Figures
List of Tables
List of Examples
GroovyQueryBuilder
FxResultSet
getRows()
PluginFactory
in
flexive-plugins-config.xml
Managing and operating on hierarchical data structures is an issue in many projects, alongside with security concerns, versioning and querying. Till now, neither open nor closed source projects or frameworks offer possibilities to dynamically define and manipulate the structure of hierarchical data in a scope like [fleXive]. Hence the urge to provide a solution that combines flexibility, security and performance in one customizable package.
[fleXive] is a JavaEE 5 open-source (LGPL) framework for the development of complex and evolving (web-)applications. It speeds up development as it handles numerous important application issues and keeps your application flexible over the development-cycle. It is based on the lastest industry-standards like EJB 3, JSF, etc.
The [fleXive] backend application is an optional application built on top of the framework and is licensed under the GNU General Public License (GPL). It helps you to visually manage most aspects of [fleXive] - like defining data structures, building queries, manage users and security, etc.
[fleXive] concentrates on enterprise-scale content storage and retrieval, and includes comprehensive JSF support for displaying and manipulating these contents in web applications. The runtime environment can be included in existing JavaEE applications, but you can also build new applications and package them into stand-alone JavaEE applications. Our emphasis lies on the runtime environment, so if you are looking e.g. for tool-driven JSF development, take a look at the popular JBoss Seam framework and embed the [fleXive] runtime environment in that project.
The goal of [fleXive] is to relieve you from many tendious and repetitive programming tasks when building secure, data-centric (web-)applications.
If you are new to [fleXive] please use the following tools to get started:
The [fleXive] website will provide you with top-level information about [fleXive]. Have a look at the "Explore [fleXive]" section.
This reference documentation will provide all information to use [fleXive] for the development of your application.
In the [fleXive] wiki you will find more tutorials, HowTo's, samples and developer infos
For questions, use the [fleXive] forum and mailinglists. We also provide a issue trackings system for bug reports and feature requests. In case you are interested in the development of [fleXive], have a look at the Development Section on the [fleXive] website and join the developer mailinglist.
[fleXive] is a Professional Open Source project. UCS - unique computing solutions gmbh (http://www.ucs.at) offers commercial development support and training for [fleXive].
Table of Contents
Administrator privileges on your machine
The Sun Java 6 Platform, Standard Edition Development Kit
JAVA_HOME and JDK_HOME
environment variable to your JDK root directory (e.g.
JAVA_HOME=/usr/lib/jvm/java-6-sun
on Linux,
C:\Java\jdk1.6.0_03
on Windows)
An application server ( JBoss or Glassfish) with EJB3 support
${jboss.home}
denotes your JBoss installation
directory)
${glassfish.home}
denotes your Glassfish installation directory)
A database (at the moment only MySql is supported)
Download and install MySql 5.0 or later
Currently, choosing UTF-8 as the default charset causes issues with the database setup scripts. Use the default setting (Latin1) instead.
ImageMagick version 6.3.4 or later (optional)
Apache ANT 1.7 and the ant-optional package
A [fleXive] binary distribution or the [fleXive] source code, if you want to build [fleXive] from source
If you are interested in developing [fleXive], you will need the [fleXive] source code and an IDE like Eclipse or a proprietary solution.
The following sections are good starting points for future [fleXive] developers:
We provide the current generated [fleXive] API Documentation for you on our website.
The following required libraries have to be deployed:
Copy the following file from the
extlib
directory of your [fleXive] binary distribution to
${jboss.home}/server/default/lib:
mysql-connector-java-*.jar
(Alternatively you can download the latest stable
MySQL JDBC
driver)
Create and copy the datasource config file
flexive-ds.xml
to
${jboss.home}/server/default/deploy/
and adapt to your datasource(s)
or simply copy it from the [fleXive] source tree, if available.
In the
flexive-ds.xml
configure your database connections as follows:
For the
flexive
database
<!-- transactional datasource -->
<xa-datasource>
<jndi-name>jdbc/flexiveDivision1</jndi-name>
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
<!-- Note: "&" has to be used instead of "&" for parameters -->
<xa-datasource-property name="URL">jdbc:mysql://localhost:3306/flexive?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8</xa-datasource-property>
<user-name>root</user-name>
<password>a</password>
</xa-datasource>
<!-- non-transactional datasource for database structure patches, Quartz, etc. -->
<no-tx-datasource>
<jndi-name>jdbc/flexiveDivision1NoTX</jndi-name>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<!-- Note: "&" has to be used instead of "&" for parameters -->
<connection-url>jdbc:mysql://localhost:3306/flexive?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8</xa-datasource-property>
<user-name>root</user-name>
<password>a</password>
</no-tx-datasource>
For the
flexiveConfiguration
database
<xa-datasource>
<jndi-name>jdbc/flexiveConfiguration</jndi-name>
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
<!-- Note: "&" has to be used instead of "&" for parameters -->
<xa-datasource-property name="URL">jdbc:mysql://localhost:3306/flexiveConfiguration?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8</xa-datasource-property>
<user-name>root</user-name>
<password>a</password>
</xa-datasource>
flexive-ds.xml
<!--
JBoss Datasource Configuration
See http://www.redhat.com/docs/manuals/jboss/jboss-eap-4.3/doc/Server_Configuration_Guide/html/Connectors_on_JBoss-Configuring_JDBC_DataSources.html
for detailed configuration infos
-->
<datasources>
<!--
transactional datasource, as configured in the global configuration
-->
<xa-datasource>
<jndi-name>jdbc/flexiveDivision1</jndi-name>
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
<!-- Note: "&" has to be used instead of "&" for parameters -->
<xa-datasource-property name="URL">jdbc:mysql://localhost:3306/flexive?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8</xa-datasource-property>
<user-name>root</user-name>
<password>a</password>
<transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
<no-tx-separate-pools/>
<!-- This disables transaction interleaving (which BTW, most DB vendors don't support) -->
<track-connection-by-tx/>
<isSameRM-override-value>false</isSameRM-override-value>
<!--pooling parameters-->
<min-pool-size>5</min-pool-size>
<max-pool-size>20</max-pool-size>
<blocking-timeout-millis>5000</blocking-timeout-millis>
<idle-timeout-minutes>15</idle-timeout-minutes>
<!-- If you supply the usr/pw from a JAAS login module -->
<security-domain/>
<exception-sorter-class-name>
com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
</exception-sorter-class-name>
<valid-connection-checker-class-name>
com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker
</valid-connection-checker-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</xa-datasource>
<!--
non-transactional datasource for database structure patches, Quartz, etc.
As per convention, non-transactional datasources have the same name like
transactional but use the suffix "NoTX"
-->
<no-tx-datasource>
<jndi-name>jdbc/flexiveDivision1NoTX</jndi-name>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<!-- Note: "&" has to be used instead of "&" for parameters -->
<connection-url>jdbc:mysql://localhost:3306/flexive?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8</connection-url>
<user-name>root</user-name>
<password>a</password>
<!--pooling parameters-->
<min-pool-size>5</min-pool-size>
<max-pool-size>20</max-pool-size>
<blocking-timeout-millis>5000</blocking-timeout-millis>
<idle-timeout-minutes>15</idle-timeout-minutes>
<!-- If you supply the usr/pw from a JAAS login module -->
<security-domain/>
<exception-sorter-class-name>
com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
</exception-sorter-class-name>
<valid-connection-checker-class-name>
com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker
</valid-connection-checker-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</no-tx-datasource>
<xa-datasource>
<jndi-name>jdbc/flexiveConfiguration</jndi-name>
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
<!-- Note: "&" has to be used instead of "&" for parameters -->
<xa-datasource-property name="URL">jdbc:mysql://localhost:3306/flexiveConfiguration?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8</xa-datasource-property>
<user-name>root</user-name>
<password>a</password>
<transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
<no-tx-separate-pools/>
<!-- This disables transaction interleaving (which BTW, most DB vendors don't support) -->
<track-connection-by-tx/>
<isSameRM-override-value>false</isSameRM-override-value>
<!--pooling parameters-->
<min-pool-size>5</min-pool-size>
<max-pool-size>20</max-pool-size>
<blocking-timeout-millis>5000</blocking-timeout-millis>
<idle-timeout-minutes>15</idle-timeout-minutes>
<!-- If you supply the usr/pw from a JAAS login module -->
<security-domain/>
<exception-sorter-class-name>
com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
</exception-sorter-class-name>
<valid-connection-checker-class-name>
com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker
</valid-connection-checker-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</xa-datasource>
</datasources>
To set up the databases do the following
Adapt the
database.properties
file located in your
flexive-dist
directory of your [fleXive] distribution to your needs:
# This is the database configuration file used by the flexive setup tasks. # # Enter the settings for your database server connection to be used for development. # The server host or IP database.host=localhost # The server port database.port=3306 # The user name and password to be used for creating flexive database structures database.username=root database.password=a
Change to the
flexive-dist
directory of your [fleXive] distribution and run
ant db.create db.config.create
You will be prompted to enter a name for your division database (simply hit enter to keep
flexive).
Warning: Existing databases will be deleted.
Change to the
flexive-dist
directory of your [fleXive] distribution and run
ant ear. This will create the
flexive.ear
file inside the
flexive-dist
directory. Copy
flexive.ear
to
${jboss.home}/server/default/deploy.
Currently JBoss (4.2) uses the Java's default maximum heap size,
which means that [fleXive] will probably run out of memory during the
first startup. You have to set the maximum heap size using
-Xmx
to a larger value, at least 256m.
On Linux execute
export JAVA_OPTS="-Xms128m -Xmx512m"
On Windows execute
SET JAVA_OPTS=-Xms128m -Xmx512m
Change to the
${jboss.home}/bin
directory.
On Linux launch JBoss using
sh run.sh -c default -Djboss.bind.address=0.0.0.0
On Windows launch JBoss using
start run.bat -c default -Djboss.bind.address=0.0.0.0
To access the backend point your browser to http://localhost:8080/flexive/adm/
Alternatively you can specify your server's IP address, which is supported by default, too.
The default superuser's username and password for the Backend Administration are:
username: supervisor, password: supervisor
Extend
${jboss.home}/server/default/conf/jboss-log4j.xml
to configure logging:
<!-- Limit flexive -->
<category name="com.flexive">
<priority value="INFO"/>
</category>
<!-- Limit ajax4jsf -->
<category name="org.ajax4jsf">
<priority value="WARN"/>
</category>
Optional if you need JAAS support: Extend
${jboss.home}/server/default/conf/login-config.xml
with the following entry:
<application-policy name = "FxLogin">
<authentication>
<login-module code="com.flexive.core.security.FxDefaultLogin" flag="required"></login-module>
</authentication>
</application-policy>
Optional step: To use an external service deployer for JBoss Cache,
create the cache service file
99_JBossCacheJNDI42-service.xml
in
${jboss.home}/server/default/deploy/
or simply copy it from the [fleXive] source tree, if available:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<loader-repository>com.flexive:archive=flexive.ear
</loader-repository>
<!-- ========================================================== -->
<!-- Clustered SFSB cache config for use with JBoss Cache 1.4.x -->
<!-- ========================================================== -->
<mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
name="jboss.cache:service=JNDITreeCache">
<!--<depends>jboss:service=Naming</depends>-->
<!--<depends>jboss:service=TransactionManager</depends>-->
<attribute name="TransactionManagerLookupClass">org.jboss.cache.transaction.GenericTransactionManagerLookup</attribute>
<!--
Node locking scheme :
PESSIMISTIC (default)
OPTIMISTIC
-->
<attribute name="NodeLockingScheme">PESSIMISTIC</attribute>
<attribute name="ClusterName">[fleXive]-Cache-JNDI</attribute>
<!--
Node locking level : SERIALIZABLE
REPEATABLE_READ (default)
READ_COMMITTED
READ_UNCOMMITTED
NONE
-->
<attribute name="IsolationLevel">READ_COMMITTED</attribute>
<!-- Valid modes are LOCAL
REPL_ASYNC
REPL_SYNC
-->
<attribute name="CacheMode">REPL_ASYNC</attribute>
<!-- We want to activate/inactivate regions as beans are deployed -->
<attribute name="UseRegionBasedMarshalling">true</attribute>
<!-- Must match the value of "useRegionBasedMarshalling" -->
<attribute name="InactiveOnStartup">true</attribute>
<!--
JGroups protocol stack config in XML format.
If your CacheMode is set to REPL_SYNC we recommend you comment
out the FC (flow control) protocol
On Windows machines, because of the media sense feature
being broken with multicast (even after disabling media sense)
set the UDP.loopback attribute to true
-->
<attribute name="ClusterConfig">
<config>
<UDP mcast_addr="${flexive.cluster.udpGroup:229.1.2.5}"
mcast_port="${jboss.ejb3sfsbpartition.mcast_port:45557}"
tos="8"
ucast_recv_buf_size="20000000"
ucast_send_buf_size="640000"
mcast_recv_buf_size="25000000"
mcast_send_buf_size="640000"
loopback="false"
discard_incompatible_packets="true"
enable_bundling="false"
max_bundle_size="64000"
max_bundle_timeout="30"
use_incoming_packet_handler="true"
use_outgoing_packet_handler="false"
ip_ttl="${jgroups.udp.ip_ttl:2}"
down_thread="false" up_thread="false"/>
<PING timeout="2000"
down_thread="false" up_thread="false" num_initial_members="3"/>
<MERGE2 max_interval="100000"
down_thread="false" up_thread="false" min_interval="20000"/>
<FD_SOCK down_thread="false" up_thread="false"/>
<FD timeout="10000" max_tries="5" down_thread="false" up_thread="false" shun="true"/>
<VERIFY_SUSPECT timeout="1500" down_thread="false" up_thread="false"/>
<pbcast.NAKACK max_xmit_size="60000"
use_mcast_xmit="false" gc_lag="0"
retransmit_timeout="300,600,1200,2400,4800"
down_thread="false" up_thread="false"
discard_delivered_msgs="true"/>
<UNICAST timeout="300,600,1200,2400,3600"
down_thread="false" up_thread="false"/>
<pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
down_thread="false" up_thread="false"
max_bytes="400000"/>
<pbcast.GMS print_local_addr="true" join_timeout="3000"
down_thread="false" up_thread="false"
join_retry_timeout="2000" shun="true"
view_bundling="true"
view_ack_collection_timeout="5000"/>
<FC max_credits="2000000" down_thread="false" up_thread="false"
min_threshold="0.10"/>
<FRAG2 frag_size="60000" down_thread="false" up_thread="false"/>
<pbcast.STATE_TRANSFER down_thread="false" up_thread="false" use_flush="false"/>
</config>
</attribute>
<!-- The max amount of time (in milliseconds) we wait until the
initial state (ie. the contents of the cache) are retrieved from
existing members.
-->
<attribute name="InitialStateRetrievalTimeout">17500</attribute>
<!-- Number of milliseconds to wait until all responses for a
synchronous call have been received.
-->
<attribute name="SyncReplTimeout">17500</attribute>
<!-- Max number of milliseconds to wait for a lock acquisition -->
<attribute name="LockAcquisitionTimeout">15000</attribute>
<!-- Specific eviction policy configurations. -->
<attribute name="EvictionPolicyConfig">
<config>
<attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
<attribute name="wakeUpIntervalSeconds">5</attribute>
<name>flexiveMain</name>
<!-- So default region would never timeout -->
<region name="/_default_">
<attribute name="maxNodes">0</attribute>
<attribute name="timeToIdleSeconds">0</attribute>
<attribute name="timeToLiveSeconds">0</attribute>
</region>
<!-- cache region for contents -->
<region name="/Division1/FxContent">
<attribute name="maxNodes">20000</attribute>
<attribute name="timeToIdleSeconds">300</attribute>
<attribute name="timeToLiveSeconds">1000</attribute>
</region>
<!-- cache region for user configuration -->
<region name="/Division1/userConfig">
<attribute name="maxNodes">100000</attribute>
<attribute name="timeToIdleSeconds">300</attribute>
<attribute name="timeToLiveSeconds">1000</attribute>
</region>
</config>
</attribute>
</mbean>
</server>
If you want to use the external cache deplyoment you have to apply another modification:
Due to classloading issues ([fleXive] uses JBoss Cache 2.x, while
JBoss 4.2 uses JBoss Cache 1.x) you need to modify the deployment scanner in
${jboss.home}/server/default/conf/jboss-service.xml:
replace the entry
<attribute name="URLComparator">org.jboss.deployment.DeploymentSorter</attribute>with
<attribute name="URLComparator">org.jboss.deployment.scanner.AlphaNumericDeploymentSorter</attribute>This ensures that the cache service is started after flexive.ear is deployed and thus can use its cache implementation classes (this deployment scanner allows to influence the deployment order with a numeric prefix, otherwise it's the same as the default one).
Flexive needs several libraries to be deployed to the application server's internal
lib
directories. Execute these steps once glassfish has been setup.
We provide an ant task for you which copies all libraries needed to deploy [fleXive] on Glassfish V2 to the specified directory.
Change to the
flexive-dist
directory of your [fleXive] distribution and run
ant glassfish.libs.
You will be prompted to specify your
${glassfish.home}/domains/domain1/lib/ext
directory.
The
ant
task will copy all required libraries to this directory.
Copy the
jbosscache-core.jar
from the
extlib
directory of your [fleXive] binary distribution to
${glassfish.home}/lib
To set up the databases, follow these instructions.
Setting up Glassfish
Go to the target installation directory
java -Xmx256m -jar <<path-to-downloaded-jar>>
extracts the installation JAR to
./glassfish
cd glassfish
On Unix: chmod -R +x lib/ant/bin
Execute the
setup.xml
buildfile
Unix: lib/ant/bin/ant -f setup.xml
Windows: lib\ant\bin\ant -f setup.xml
Starting Glassfish
bin/asadmin start-domain domain1 starts the Glassfish server
http://localhost:4848/ and login using default credentials admin/adminadmin.
Additional information
To stop the Glassfish instance execute ${glassfish.home}/bin/asadmin stop-domain domain1
Admin UI Port: 4848
HTTP Port: 8080
HTTPS Port: 8181
Three connection pools, two for the division (transactional and non-transactional) and one for the configuration database, have to be set up.
Copy and paste the following data-source definitions to a file (e.g.
flexive-ds.xml)
and update your database connection settings:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//Sun Microsystems Inc.//DTD Application Server 9.0 Domain//EN" "sun-resources_1_3.dtd">
<resources>
<!--
Glassfish datasource configuration
To add these datasource, start Glassfish v2, and execute
${glassfish.home}/bin/asadmin add-resources /path/to/flexive-ds.xml
-->
<!-- Configure the global configuration datasource -->
<jdbc-connection-pool
name="flexiveConfiguration"
datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"
res-type="javax.sql.XADataSource">
<property name="user" value="root"/>
<property name="password" value="a"/>
<property name="url" value="jdbc:mysql://localhost:3306/flexiveConfiguration?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8"/>
</jdbc-connection-pool>
<jdbc-resource pool-name="flexiveConfiguration" jndi-name="jdbc/flexiveConfiguration" enabled="true" object-type="user"/>
<!-- Configure the first flexive division -->
<jdbc-connection-pool
name="flexiveDivision1"
datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"
res-type="javax.sql.XADataSource">
<property name="user" value="root"/>
<property name="password" value="a"/>
<property name="url" value="jdbc:mysql://localhost:3306/flexive?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8"/>
</jdbc-connection-pool>
<jdbc-resource pool-name="flexiveDivision1" jndi-name="jdbc/flexiveDivision1" enabled="true" object-type="user"/>
<!-- Configure the first flexive division non-XA datasource -->
<jdbc-connection-pool
name="flexiveDivision1NoTX"
datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
res-type="javax.sql.DataSource">
<property name="user" value="root"/>
<property name="password" value="a"/>
<property name="url" value="jdbc:mysql://localhost:3306/flexive?useUnicode=true&characterEncoding=utf8&characterResultSets=utf8"/>
</jdbc-connection-pool>
<jdbc-resource pool-name="flexiveDivision1NoTX" jndi-name="jdbc/flexiveDivision1NoTX" enabled="true" object-type="user"/>
</resources>
While Glassfish is running, execute ${glassfish.home}/bin/asadmin add-resources /path/to/flexive-ds.xml to create the connection pools and JDBC resources. You have to pass the absolute path to your XML file, otherwise Glassfish looks in its own config directory.
Should you need to edit or reset your datasources, you can do so in the Glassfish administration console under →
Change to the
flexive-dist
directory of your [fleXive] distribution and run
ant ear. This will create the
flexive.ear
file inside the
flexive-dist
directory.
Using the autodeploy directory:
Copy the
flexive.ear
to
${glassfish.home}/domains/domain1/autodeploy
Using the Admin UI:
In the Admin Console, go to →
Click
Deploy...
and upload the
flexive.ear
file.
Click
OK
To access the backend point your browser to http://localhost:8080/flexive/adm/ Alternatively you can specify your server's IP address, which is supported by default, too. The default superuser's username and password for the Backend Administration are username: supervisor, password: supervisor.
This procedure is for those building [fleXive] from the source code.
build.properties.sample
file located in the root directory of the
[fleXive] source code
to
build.properties.
jboss.home=/path/to/jboss
# path to deploy the ear
deploy.ear.path=${jboss.home}/server/all/deploy
# path to deploy needed runtime libs like emma.jar
deploy.lib.path=${jboss.home}/server/all/lib
# path to the embedded jboss ejb3 container neededfor unit testing
jboss.embedded.path=${jboss.home}/jboss-embeddable/
# (...)
ant db.update
before
ant all
in the root directory of the
[fleXive] source code,
where the
build.xml
file
resides.
This will recreate all configured databases and destroy existing data.
To deploy the ear execute
ant deploy
Don't forget to set your
${jboss.home}
variable in the
build.properties
file properly!
JDK_HOME
and
JAVA_HOME
variables accordingly as explained in section
Prerequisites.
If there are multiple JBoss installations running in your local network you need
to assign a different partition UDP group to each cluster! This can be done by adding
-Djboss.partition.udpGroup=230.2.3.4
(or any other multicast address you choose thats available)
to the start script/command shown in
Starting [fleXive].
In order to run JBossCache on Linux IPv4 needs to be defined as the preferred IP stack. In the Glassfish admin console, go to → → and add the following option:
-Djava.net.preferIPv4Stack=true
If an ant-task fails, make sure you have Apache ANT 1.7 installed.
If you get the following warning:
Problem: failed to create task or type javacc when executing ant
make sure you installed the ant-optional package.
For your first [fleXive] application, we assume you have a flexive installation up and running on
your local or on a remote machine. If not, follow the instructions in
Chapter 2, Installing [fleXive]
.
The complete source code can be found in [fleXive] source packages or in the subversion repository under
src/examples.
Our first [fleXive] application implements a very simple blogging system with an input mask and a view for the submitted entries. Looking at the source directory of the application, we find the following directory structure:
/helloworld/ | +--build.xml /helloworld/java/ /helloworld/java/com.flexive.examples.helloworld.war | +--HelloWorldBean.java /helloworld/resources/ /helloworld/resources/scripts/ /helloworld/resources/scripts/library/ /helloworld/resources/scripts/startup/ /helloworld/resources/scripts/runonce/ | +--hello001.groovy /helloworld/web/ | +--create.xhtml +--index.xhtml /helloworld/web/WEB-INF/ | +--faces-config.xml +--web.xml
java
contains the Java sources of the application.
resources/scripts
contains [fleXive] scripts that will be used to setup the data structures needed by the application.
web
contains the XHTML pages and the web configuration files.
We start with defining the data model of the application. Our blog entry consists of a
posting title and the actual text. To set up the data model when deploying the application,
we use the
run-once script
hello001.groovy
located in the
resources/scripts/runonce/
directory.
The easiest way of setting up [fleXive] structures is by using the Groovy builder for
[fleXive] types,
GroovyTypeBuilder.
import com.flexive.shared.scripting.groovy.*
import com.flexive.shared.value.*
import com.flexive.shared.structure.*
new GroovyTypeBuilder().blogEntry(description: new FxString(true, "Blog Entry"), usePermissions: false) { //
caption(assignment: "ROOT/CAPTION")
entryTitle(multiplicity: FxMultiplicity.MULT_1_1, description: new FxString(true, "Title")) //
entryText(multiplicity: FxMultiplicity.MULT_1_1, description: new FxString(true, "Text"),
multiline: true) //
}
|
The method call blogEntry(...) will create the [fleXive] type "BlogEntry" (type names are not case sensitive). For the first tutorial, we will disable [fleXive] security completely for this type by setting usePermissions to false. | |
|
Create a new property assignment for the blog entry type that is referenced with the path "/entryTitle". The multiplicity of 1..1 indicates a mandatory field, the description will be shown in the input forms. | |
|
The text property is created similar to the title, but we add a "multiline" option since we don't want to enter our blog text in a single line. |
The next step is to define a JSF bean that provides the blog postings to be shown on the front page of our application.
public class HelloWorldBean {
private DataModel blogEntries;
public DataModel getBlogEntries() throws FxApplicationException {
if (blogEntries == null) {
final FxResultSet result = new SqlQueryBuilder()
.select("@pk", "entryTitle", "entryText", "created_at") //
.type("blogEntry")
.orderBy("created_at", SortDirection.DESCENDING) //
.getResult();
blogEntries = new FxResultSetDataModel(result);
}
return blogEntries;
}
}
|
We choose the columns to be selected for the result set:
| |
|
To display the newest postings first, we order by descending creation date
( |
For the web interface of the application we use JSF 1.2, using Facelets for creating the JSF views (i.e. we use plain XHTML templates instead of JSP). [fleXive] includes components for rendering and editing [fleXive] contents in JSF applications, although you could also use other web framework like Struts or Tapestry - you'd just miss the convenient UI components that allow a rapid creation of web applications based on [fleXive].
If you are not familiar with JSF tag libraries please refer to the Tag Library Documentation or try the JSF section of the Java EE 5 Tutorial.
The main page renders all available blog entries and shows a link to a form
for creating new entries. Facelets'
<ui:repeat/>
tag is used to iterate over the rows of the datamodel returned by the JSF bean we created in the
previous
section. A row of the datamodel provides indexed access to the columns selected in the
search query of the previous section.
In this case,
#{columns[0]}
would be the content primary key
(@pk),
#{columns[1]}
returns the entry title, and so on. The source for this file can be found under
web/index.xhtml.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fx="http://www.flexive.com/jsf/core">
<head>
<fx:includes/>
</head>
<body>
<h:outputLink value="create.xhtml">Create a new entry</h:outputLink>
<!-- Render available blog postings, as returned by helloWorldBean.blogEntries -->
<!-- The Facelets ui:repeat tag is used to iterate over arrays, lists and JSF datamodels -->
<ui:repeat value="#{helloWorldBean.blogEntries}" var="column">
<h3>
<!-- Entry title. Access the value of each column through the expression language
and the column index -->
#{column[1]}
</h3>
<pre>#{column[2]} <!-- Entry text -->
<i>#{column[3]}</i> <!-- Creation date -->
</pre>
</ui:repeat>
<p><h:outputLink
onclick="window.open('http://wiki.flexive.org/confluence/display/FX/Listing+blog+entries', 'In_depth_explanation', 'width=950,height=600,left=50,top=200,scrollbars=yes,resizable=yes');"
value="#">
What happens on this page?
</h:outputLink>
</p>
</body>
</html>
The input form for creating new postings uses the
<fx:content/>
and
<fx:value/>
components provided by [fleXive] to create a simple input form for [fleXive] contents.
All you need to provide is the name of the type you want to use as template
(blogEntry)
and the references to the properties to be rendered
(entryTitle,
entryText).
Finally, a JSF command link is used to render a button for saving the entered data.
The save command is executed by a [fleXive] system bean,
fxContentViewBean.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fx="http://www.flexive.com/jsf/core">
<head>
<title>Flexive Helloworld Application</title>
<fx:includes/>
</head>
<body>
<h:form>
<!-- Display all JSF messages -->
<h:messages/>
<h:outputLink value="index.xhtml">Back to blog</h:outputLink>
<!-- The fx:content tag references our type "Blog Entry" -->
<fx:content typeName="blogEntry" var="entry">
<!-- This renders an html input field for the type's property "Entry Title" -->
<fx:value property="entryTitle"/>
<!-- This renders an html input field for the type's property "Entry Text" -->
<fx:value property="entryText"/>
<!-- Save content using the FxContentViewBean, pass the content instance
stored in component_content via f:setPropertyActionListener -->
<h:commandLink action="#{fxContentViewBean.save}">
<f:setPropertyActionListener target="#{fxContentViewBean.content}" value="#{entry_content}"/>
Publish
</h:commandLink>
</fx:content>
</h:form>
<p><h:outputLink
onclick="window.open('http://wiki.flexive.org/confluence/display/FX/Creating+a+blog+entry', 'In_depth_explanation', 'width=950,height=600,left=50,top=200,scrollbars=yes,resizable=yes');"
value="#">
What happens on this page?
</h:outputLink>
</p>
</body>
</html>
In the
web/WEB-INF
directory there are two files:
The web deployment descriptor in
web.xml.
Here we initialize the JSF runtime and add the
FxFilter
for pages handled by [fleXive].
FxFilter
is required for more advanced [fleXive] functionality, but is not required
for this application.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- Use Documents Saved as *.xhtml -->
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<!-- Configure FxFilter -->
<filter>
<filter-name>FxFilter</filter-name>
<filter-class>com.flexive.war.filter.FxFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FxFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Configure Faces servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<!--
/faces/* (or another suffix pattern) should always be the last url-pattern for the FacesServlet,
otherwise the flexive Weblets includes won't work
-->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<listener>
<listener-class>net.java.dev.weblets.WebletsContextListener</listener-class>
</listener>
<listener>
<listener-class>com.flexive.war.listener.SessionTimeoutListener</listener-class>
</listener>
</web-app>
The JSF configuration file in
faces-config.xml.
Here we register the
HelloWorldBean
and provide navigation rules between the overview and the create page.
<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<!-- Facelets View Handler Definition -->
<application>
<view-handler>
com.sun.facelets.FaceletViewHandler
</view-handler>
</application>
<!-- Definition of the managed bean which retrieves the data from database -->
<managed-bean>
<managed-bean-name>helloWorldBean</managed-bean-name>
<managed-bean-class>com.flexive.examples.helloworld.war.HelloWorldBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<!-- A navigation rule for our input mask, if everything goes right,
"success" is returned, which leads to a direct rendering and response
of the index.xhtml view. The entries made via the input mask are shown
in this view. -->
<navigation-rule>
<from-view-id>/create.xhtml</from-view-id>
<navigation-case>
<display-name>success</display-name>
<from-outcome>success</from-outcome>
<to-view-id>/index.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
To compile and deploy the framework and the example application run the following ant tasks in the given order (you need a full [fleXive] source installation for this):
ant dist
in your
${flexive.home}
directory where the
build.xml
file resides if you don't
already have a
flexive-dist
directory
ant
in the
${flexive.home}/src/examples/helloworld/
directory
ant deploy
in your
${flexive.home}
directory
Start your application server and point your browser to http://localhost:8080/helloworld/index.xhtml Congratulations! You should see a link to the input mask.
After the successful deployment of the application you can find the created datastructure in the backend administration's structure editor. Log on to the backend administration and expand the tab named "Structure". You should be able to see the type Blog Entry in the tree. Expand it and click on one of the properties. In the "Edit Property Assignment" tab in the right frame you can see the properties originally set in the hello001.groovy script.

Now that you are familiar with some basic concepts of [fleXive], we are ready to explore more features. The first tutorial application introduces
binary support in [fleXive] contents,
combined create/edit forms, as well as
a more sophisticated way of rendering results, like automatic preview images of contents.
Our task for this tutorial is to create a centralized document store that allows us to store documents, images or videos and provides a web-based user interface for it. In the first tutorial we will implement the basic functionality, and then further refine and extend the features in following tutorials. Figure 3.1, “The document store application, version 1” shows the end result of the first tutorial, with the help of some stylesheets that can be found in the tutorial source tree.
As in the
helloworld
example we start by defining our data model used for storing documents.
We assign the standard caption property
/caption
for document captions, and add a
Binary
property. We create the type in a
run-once script,
found in
resources/scripts/runonce/tutorial001.groovy:
/**
* Initialization script for the tutorial01 application.
*
* @author Daniel Lichtenberger (daniel.lichtenberger@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
* @version $Rev: 461 $
*/
import com.flexive.shared.scripting.groovy.*
import com.flexive.shared.value.*
import com.flexive.shared.structure.*
new GroovyTypeBuilder().document01(
description: new FxString(true, "Tutorial document 01"),
usePermissions: false)
{
// assign the root caption under /caption
caption(assignment: "ROOT/CAPTION")
// store the mandatory binary under /file
file(dataType: FxDataType.Binary,
multiplicity: FxMultiplicity.MULT_1_1,
description: new FxString(true, "File"))
}
The most interesting parts of this tutorial are the overview and upload pages. On the first we display all uploaded document objects, the latter allows the user to upload new files or edit existing ones.
The index page of the application renders a link to an empty upload form for uploading new document, and also renders all document objects already uploaded. Note that in the first version of the tutorial, security is completely disabled, thus every user can see and edit all document objects in the system.
Similar to the
helloworld
example application, we iterate over the rows of the result data model using
<ui:repeat>.
But this time, we render the result using the
<fx:resultValue>
tag, which essentially renders read-only
<fx:valueInput>
components for more sophisticated output formatting.
For the document browser, we select four columns in our content query:
@pk,
document01/file,
caption, and
created_at.
When we pass a value of the second column (document01/file) to the
<fx:resultValue>
component,
it actually renders an inline image that displays a preview of the uploaded file. For image
data types, this is a thumbnail, for other types like documents or presentations, it is
an icon corresponding to the document type.
So to render a list of thumbnail preview images, we write the following:
<ui:repeat var="row" value="#{tutorialBean.documents}">
<fx:resultValue value="#{row[1]}"/>
</ui:repeat>
We can still write the result values as literal JSF-EL expressions when necessary, so for example to
add the caption after each image it would be sufficient to write
#{row[2]}. However, the
<fx:resultValue>
tag adds extra functionality like date formatting or support for inline HTML
properties (otherwise HTML contained in an
FxHTML
would be escaped by Facelets), so it's generally a good idea to use
<fx:resultValue>
for any result value rendered in the response.
Below each document object, we want to provide a link that opens the object in the
edit form. We could either pass the primary key selected in the first column through
a bean property, or pass
the content instance itself through the fxContentViewBean and supply it to the
<fx:content>
component.
JSF's
setPropertyActionListener
is a convenient way of setting bean properties when a command link or button is triggered.
The Edit link looks like this:
<h:commandLink action="edit" styleClass="editButton">
<f:setPropertyActionListener target="#{fxContentViewBean.content}"
value="#{fxSystemBean.content[row[0]]}"/>
Edit...
</h:commandLink>
#{fxSystemBean.content[row[0]]}
returns the
FxContent
instance for the given primary key. Note that the JSF listener will only be fired
when the user actually clicks on the commandLink, thus the rather expensive load operation
will only be performed if the user clicks on the edit link.
The following listing includes the whole page including the main menu entry and the document browser.
It can be found in the tutorial01 directory under
web/index.xhtml.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fx="http://www.flexive.com/jsf/core">
<head>
<!-- Add flexive includes -->
<fx:includes/>
<!-- Add our own stylesheet for the result page -->
<link rel="stylesheet" type="text/css" href="css/tutorial01.css"/>
</head>
<body>
<!-- Output JSF error or info messages here -->
<h:messages globalOnly="true"/>
<p class="message">
Welcome to tutorial 1 - the first version of our document data store.
</p>
<!-- The main menu -->
<ul id="mainmenu">
<li>
<h:outputLink value="upload.xhtml">Upload document</h:outputLink>
</li>
</ul>
<!-- Render all available document objects, provided by #{tutorialBean.documents} -->
<h:form id="frm">
<ul class="documents">
<!-- Iterate over all document objects -->
<ui:repeat var="row" value="#{tutorialBean.documents}">
<li>
<!-- Render the file (preview image) -->
<fx:resultValue id="preview" value="#{row[1]}"/>
<!-- Render the document caption -->
<span class="caption">
<fx:resultValue id="caption" value="#{row[2]}"/>
</span>
<!-- Add an edit button below the image -->
<h:commandLink action="edit" styleClass="editButton">
<!--
Load the content instance of the current row and store it in
#{fxContentViewBean.content}. The edit page will then use this
content instance.
Note that this listener will only be fired when the user actually
clicks on the commandLink.
-->
<f:setPropertyActionListener target="#{fxContentViewBean.content}"
value="#{fxSystemBean.content[row[0]]}"/>
Edit...
</h:commandLink>
</li>
</ui:repeat>
</ul>
</h:form>
<p style="clear:both; padding-top:25px;"><h:outputLink
onclick="window.open('http://wiki.flexive.org/confluence/display/FX/Generating+thumbnails', 'In_depth_explanation', 'width=950,height=600,left=50,top=200,scrollbars=yes,resizable=yes');"
value="#">
What happens on this page?
</h:outputLink>
</p>
</body>
</html>
The upload form allows both to create new document objects by uploading files and editing existing ones. It works exactly as the form for entering new blog posts in the helloworld tutorial, except that we specify an explicit content instance that may be set from an edit link on the overview page:
<fx:content typeName="document01"
content="#{fxContentViewBean.content}"
var="document">