Seam SVN: r9194 - tags.
by seam-commits@lists.jboss.org
Author: manaRH
Date: 2008-10-05 06:57:15 -0400 (Sun, 05 Oct 2008)
New Revision: 9194
Added:
tags/JBPAPP_CP05_CP03/
Log:
Tag for EAP 4.2 CP05 a EAP 4.3 CP03
Copied: tags/JBPAPP_CP05_CP03 (from rev 9193, branches/enterprise/JBPAPP_4_2_CP01)
16 years, 1 month
Seam SVN: r9193 - trunk/doc/Seam_Reference_Guide/en-US.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2008-10-05 02:49:45 -0400 (Sun, 05 Oct 2008)
New Revision: 9193
Modified:
trunk/doc/Seam_Reference_Guide/en-US/Security.xml
Log:
JBSEAM-3446
Modified: trunk/doc/Seam_Reference_Guide/en-US/Security.xml
===================================================================
--- trunk/doc/Seam_Reference_Guide/en-US/Security.xml 2008-10-04 16:04:51 UTC (rev 9192)
+++ trunk/doc/Seam_Reference_Guide/en-US/Security.xml 2008-10-05 06:49:45 UTC (rev 9193)
@@ -133,9 +133,10 @@
to authenticate users. This method takes no parameters, and is expected to return a boolean, which indicates
whether authentication is successful or not. The user's username and password can be obtained from
<literal>Credentials.getUsername()</literal> and <literal>Credentials.getPassword()</literal>,
- respectively. Any roles that the user is a member of should be assigned using
- <literal>Identity.addRole()</literal>. Here's a complete example of an authentication method
- inside a POJO component:
+ respectively (you can get a reference to the <literal>credentials</literal> component via
+ <literal>Identity.instance().getCredentials()</literal>). Any roles that the user is a member of
+ should be assigned using <literal>Identity.addRole()</literal>. Here's a complete example of an
+ authentication method inside a POJO component:
</para>
<programlisting role="JAVA"><![CDATA[@Name("authenticator")
@@ -2824,10 +2825,9 @@
<para>
If no expression is specified in the <literal>@Restrict</literal> annotation, the default security check
- that is performed is a permission check of <literal>entityName:action</literal>,
- where <literal>entityName</literal> is the Seam component name of the entity (or the fully-qualified class name if no @Name is
- specified), and the <literal>action</literal> is either <literal>read</literal>,
- <literal>insert</literal>, <literal>update</literal> or <literal>delete</literal>.
+ that is performed is a permission check of <literal>entity:action</literal>, where the permission target
+ is the entity instance, and the <literal>action</literal> is either <literal>read</literal>, <literal>insert</literal>,
+ <literal>update</literal> or <literal>delete</literal>.
</para>
<para>
16 years, 1 month
Seam SVN: r9192 - trunk/ui/src/main/java/org/jboss/seam/ui/util.
by seam-commits@lists.jboss.org
Author: pete.muir(a)jboss.org
Date: 2008-10-04 12:04:51 -0400 (Sat, 04 Oct 2008)
New Revision: 9192
Modified:
trunk/ui/src/main/java/org/jboss/seam/ui/util/Decoration.java
Log:
Add comments
Modified: trunk/ui/src/main/java/org/jboss/seam/ui/util/Decoration.java
===================================================================
--- trunk/ui/src/main/java/org/jboss/seam/ui/util/Decoration.java 2008-10-04 15:23:25 UTC (rev 9191)
+++ trunk/ui/src/main/java/org/jboss/seam/ui/util/Decoration.java 2008-10-04 16:04:51 UTC (rev 9192)
@@ -10,11 +10,19 @@
public static boolean hasMessage(UIComponent component, FacesContext context)
{
+
+ // If the component isn't to be rendered, then ignore
if ( !component.isRendered() ) return false;
+
if ( component instanceof EditableValueHolder )
{
+
+ // If the component has failed validation, then it's invalid
if ( ! ( (EditableValueHolder) component ).isValid() ) return true;
+
+ // If the component has a faces message attached, return true.
+ // TODO enhance this to only consider ERROR and WARN messages probably
if ( context.getMessages( component.getClientId(context) ).hasNext() ) return true; //TODO: put this outside the if???
}
16 years, 1 month
Seam SVN: r9191 - in trunk: src/main/org/jboss/seam and 2 other directories.
by seam-commits@lists.jboss.org
Author: pete.muir(a)jboss.org
Date: 2008-10-04 11:23:25 -0400 (Sat, 04 Oct 2008)
New Revision: 9191
Modified:
trunk/doc/Seam_Reference_Guide/en-US/Xml.xml
trunk/src/main/org/jboss/seam/Component.java
trunk/src/main/org/jboss/seam/components-2.1.xsd
trunk/src/main/org/jboss/seam/init/Initialization.java
trunk/src/main/org/jboss/seam/util/Conversions.java
Log:
JBSEAM-3460
Modified: trunk/doc/Seam_Reference_Guide/en-US/Xml.xml
===================================================================
--- trunk/doc/Seam_Reference_Guide/en-US/Xml.xml 2008-10-04 14:46:32 UTC (rev 9190)
+++ trunk/doc/Seam_Reference_Guide/en-US/Xml.xml 2008-10-04 15:23:25 UTC (rev 9191)
@@ -333,6 +333,24 @@
</component>]]></programlisting>
<para>
+ When configuring multi-valued properties, by default, Seam will preserve the order in which you place the attributes
+ in <literal>components.xml</literal> (unless you use a <literal>SortedSet</literal>/<literal>SortedMap</literal>
+ then Seam will use <literal>TreeMap</literal>/<literal>TreeSet</literal>). If the property has a concrete type (for
+ example <literal>LinkedList</literal> Seam will use that type.
+ </para>
+ <para>
+ You can also override the type by specifying a fully qualified class name:
+ </para>
+
+ <programlisting role="XML"><![CDATA[<component name="issueEditor">
+ <property name="issueStatusOptions" type="java.util.LinkedHashMap">
+ <key>open</key> <value>open issue</value>
+ <key>resolved</key> <value>issue resolved by developer</value>
+ <key>closed</key> <value>resolution accepted by user</value>
+ </property>
+</component>]]></programlisting>
+
+ <para>
Finally, you may wire together components using a value-binding expression. Note that this is quite
different to injection using <literal>@In</literal>, since it happens at component instantiation time
instead of invocation time. It is therefore much more similar to the dependency injection facilities
Modified: trunk/src/main/org/jboss/seam/Component.java
===================================================================
--- trunk/src/main/org/jboss/seam/Component.java 2008-10-04 14:46:32 UTC (rev 9190)
+++ trunk/src/main/org/jboss/seam/Component.java 2008-10-04 15:23:25 UTC (rev 9191)
@@ -41,9 +41,15 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
@@ -2450,7 +2456,7 @@
}
else if (converter!=null && value instanceof String[])
{
- return converter.toObject( new Conversions.MultiPropertyValue( (String[]) value ), parameterType );
+ return converter.toObject( new Conversions.MultiPropertyValue( (String[]) value, null), parameterType );
}
else
{
@@ -2480,12 +2486,21 @@
{
private InitialValue[] initialValues;
private Class elementType;
-
+ private Class collectionClass;
+
public SetInitialValue(PropertyValue propertyValue, Class collectionClass, Type collectionType)
{
String[] expressions = propertyValue.getMultiValues();
initialValues = new InitialValue[expressions.length];
elementType = Reflections.getCollectionElementType(collectionType);
+ if (propertyValue.getType() != null)
+ {
+ this.collectionClass = propertyValue.getType();
+ }
+ else
+ {
+ this.collectionClass = collectionClass;
+ }
for ( int i=0; i<expressions.length; i++ )
{
PropertyValue elementValue = new Conversions.FlatPropertyValue( expressions[i] );
@@ -2495,10 +2510,43 @@
public Object getValue(Class type)
{
- Set set = new HashSet(initialValues.length);
- for (InitialValue iv: initialValues) {
- set.add( iv.getValue(elementType) );
+ Set set;
+ //if no configuration has been specified then we first see if
+ //the property is an abstract type, if so we create it using newInstance
+ if (Modifier.isAbstract(collectionClass.getModifiers()) || Modifier.isInterface(collectionClass.getModifiers()))
+ {
+ if(collectionClass == SortedSet.class)
+ {
+ set = new TreeSet();
+ }
+ else
+ {
+ set = new LinkedHashSet(initialValues.length);
+ }
}
+ else
+ {
+ try
+ {
+ set = (Set) collectionClass.newInstance();
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new IllegalArgumentException("Cannot instantiate a set of type " + collectionClass + "; try specifying type type in components.xml");
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException("Cannot cast " + collectionClass + " to java.util.Set");
+ }
+ catch (java.lang.InstantiationException e)
+ {
+ throw new IllegalArgumentException("Cannot instantiate a set of type " + collectionClass + "; try specifying type type in components.xml");
+ }
+ }
+ for (InitialValue iv: initialValues)
+ {
+ set.add( iv.getValue(elementType) );
+ }
return set;
}
@@ -2514,6 +2562,7 @@
private InitialValue[] initialValues;
private Class elementType;
private boolean isArray;
+ private Class collectionClass;
public ListInitialValue(PropertyValue propertyValue, Class collectionClass, Type collectionType)
{
@@ -2523,6 +2572,14 @@
elementType = isArray ?
collectionClass.getComponentType() :
Reflections.getCollectionElementType(collectionType);
+ if (propertyValue.getType() != null)
+ {
+ this.collectionClass = propertyValue.getType();
+ }
+ else
+ {
+ this.collectionClass = collectionClass;
+ }
for ( int i=0; i<expressions.length; i++ )
{
PropertyValue elementValue = new Conversions.FlatPropertyValue( expressions[i] );
@@ -2543,7 +2600,32 @@
}
else
{
- List list = new ArrayList(initialValues.length);
+ List list;
+ //if no configuration has been specified then we first see if
+ //the property is an abstract type, if so we create it using newInstance
+ if (Modifier.isAbstract(collectionClass.getModifiers()) || Modifier.isInterface(collectionClass.getModifiers()))
+ {
+ list = new ArrayList(initialValues.length);
+ }
+ else
+ {
+ try
+ {
+ list = (List) collectionClass.newInstance();
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new IllegalArgumentException("Cannot instantiate a list of type " + collectionClass + "; try specifying type type in components.xml");
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException("Cannot cast " + collectionClass + " to java.util.List");
+ }
+ catch (java.lang.InstantiationException e)
+ {
+ throw new IllegalArgumentException("Cannot instantiate a list of type " + collectionClass + "; try specifying type type in components.xml");
+ }
+ }
for (InitialValue iv: initialValues)
{
list.add( iv.getValue(elementType) );
@@ -2565,13 +2647,22 @@
private Map<InitialValue, InitialValue> initialValues;
private Class elementType;
private Class keyType;
-
+ private Class collectionClass;
+
public MapInitialValue(PropertyValue propertyValue, Class collectionClass, Type collectionType)
{
Map<String, String> expressions = propertyValue.getKeyedValues();
- initialValues = new HashMap<InitialValue, InitialValue>(expressions.size());
+ initialValues = new LinkedHashMap<InitialValue, InitialValue>(expressions.size());
elementType = Reflections.getCollectionElementType(collectionType);
keyType = Reflections.getMapKeyType(collectionType);
+ if (propertyValue.getType() != null )
+ {
+ this.collectionClass = propertyValue.getType();
+ }
+ else
+ {
+ this.collectionClass = collectionClass;
+ }
for ( Map.Entry<String, String> me: expressions.entrySet() )
{
PropertyValue keyValue = new Conversions.FlatPropertyValue( me.getKey() );
@@ -2582,7 +2673,38 @@
public Object getValue(Class type)
{
- Map result = new HashMap(initialValues.size());
+ Map result;
+ if (Modifier.isAbstract(collectionClass.getModifiers()) || Modifier.isInterface(collectionClass.getModifiers()))
+ {
+ if (collectionClass == SortedMap.class)
+ {
+ result = new TreeMap();
+ }
+ else
+ {
+ result = new LinkedHashMap(initialValues.size());
+ }
+ }
+ else
+ {
+ try
+ {
+ result = (Map) collectionClass.newInstance();
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new IllegalArgumentException("Cannot instantiate a map of type " + collectionClass + "; try specifying type type in components.xml");
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException("Cannot cast " + collectionClass + " to java.util.Map");
+ }
+ catch (java.lang.InstantiationException e)
+ {
+ throw new IllegalArgumentException("Cannot instantiate a map of type " + collectionClass + "; try specifying type type in components.xml");
+ }
+ }
+
for ( Map.Entry<InitialValue, InitialValue> me : initialValues.entrySet() )
{
result.put( me.getKey().getValue(keyType), me.getValue().getValue(elementType) );
Modified: trunk/src/main/org/jboss/seam/components-2.1.xsd
===================================================================
--- trunk/src/main/org/jboss/seam/components-2.1.xsd 2008-10-04 14:46:32 UTC (rev 9190)
+++ trunk/src/main/org/jboss/seam/components-2.1.xsd 2008-10-04 15:23:25 UTC (rev 9191)
@@ -219,6 +219,11 @@
<xs:documentation>The property name</xs:documentation>
</xs:annotation>
</xs:attribute>
+ <xs:attribute name="type" type="components:string" >
+ <xs:annotation>
+ <xs:documentation>Concrete type to use if the property is multi-valued</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:attributeGroup>
@@ -344,7 +349,16 @@
<xs:enumeration value="APPLICATION"/>
</xs:restriction>
</xs:simpleType>
-
+ <xs:simpleType name="implementationType">
+ <xs:restriction base="xs:token">
+ <xs:enumeration value="hash"/>
+ <xs:enumeration value="linked"/>
+ <xs:enumeration value="tree"/>
+ <xs:enumeration value="HASH"/>
+ <xs:enumeration value="LINKED"/>
+ <xs:enumeration value="TREE"/>
+ </xs:restriction>
+ </xs:simpleType>
<xs:simpleType name="precedenceType">
<xs:restriction base="xs:int">
<xs:enumeration value="0"/>
Modified: trunk/src/main/org/jboss/seam/init/Initialization.java
===================================================================
--- trunk/src/main/org/jboss/seam/init/Initialization.java 2008-10-04 14:46:32 UTC (rev 9190)
+++ trunk/src/main/org/jboss/seam/init/Initialization.java 2008-10-04 15:23:25 UTC (rev 9191)
@@ -15,6 +15,7 @@
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -594,6 +595,21 @@
private Conversions.PropertyValue getPropertyValue(Element prop, String propName,
Properties replacements)
{
+ String typeName = prop.attributeValue("type");
+ Class type = null;
+ try
+ {
+ if(typeName != null )
+ {
+ type = Class.forName(typeName);
+ }
+ }
+ catch(ClassNotFoundException e)
+ {
+ throw new RuntimeException("Cannot find class " + typeName + " when setting up property " + propName);
+ }
+
+
List<Element> keyElements = prop.elements("key");
List<Element> valueElements = prop.elements("value");
@@ -611,7 +627,7 @@
{
values[i] = trimmedText(valueElements.get(i), propName, replacements);
}
- return new Conversions.MultiPropertyValue(values);
+ return new Conversions.MultiPropertyValue(values, type);
}
else
{
@@ -621,14 +637,14 @@
throw new IllegalArgumentException("value elements must match key elements: "
+ propName);
}
- Map<String, String> keyedValues = new HashMap<String, String>();
+ Map<String, String> keyedValues = new LinkedHashMap<String, String>();
for (int i = 0; i < keyElements.size(); i++)
{
String key = trimmedText(keyElements.get(i), propName, replacements);
String value = trimmedText(valueElements.get(i), propName, replacements);
keyedValues.put(key, value);
}
- return new Conversions.AssociativePropertyValue(keyedValues);
+ return new Conversions.AssociativePropertyValue(keyedValues, type);
}
}
Modified: trunk/src/main/org/jboss/seam/util/Conversions.java
===================================================================
--- trunk/src/main/org/jboss/seam/util/Conversions.java 2008-10-04 14:46:32 UTC (rev 9190)
+++ trunk/src/main/org/jboss/seam/util/Conversions.java 2008-10-04 15:23:25 UTC (rev 9191)
@@ -277,6 +277,7 @@
boolean isExpression();
boolean isMultiValued();
boolean isAssociativeValued();
+ Class getType();
}
public static class FlatPropertyValue implements PropertyValue
@@ -342,16 +343,24 @@
return string;
}
+ public Class getType()
+ {
+ return null;
+ }
+
}
public static class MultiPropertyValue implements PropertyValue
{
private String[] strings;
- public MultiPropertyValue(String[] strings)
+ private Class type;
+
+ public MultiPropertyValue(String[] strings, Class type)
{
if (strings==null) throw new IllegalArgumentException();
this.strings = strings;
+ this.type = type;
}
public String[] getMultiValues()
@@ -390,16 +399,23 @@
return Strings.toString( ", ", (Object[]) strings );
}
+ public Class getType()
+ {
+ return type;
+ }
}
public static class AssociativePropertyValue implements PropertyValue
{
private Map<String, String> keyedValues;
- public AssociativePropertyValue(Map<String, String> keyedValues)
+ private Class type;
+
+ public AssociativePropertyValue(Map<String, String> keyedValues, Class type)
{
if (keyedValues==null) throw new IllegalArgumentException();
this.keyedValues = keyedValues;
+ this.type = type;
}
public String[] getMultiValues()
@@ -438,6 +454,12 @@
return keyedValues.toString();
}
+
+ public Class getType()
+ {
+ return type;
+ }
+
}
}
16 years, 1 month
Seam SVN: r9190 - trunk/src/main/META-INF.
by seam-commits@lists.jboss.org
Author: pete.muir(a)jboss.org
Date: 2008-10-04 10:46:32 -0400 (Sat, 04 Oct 2008)
New Revision: 9190
Modified:
trunk/src/main/META-INF/seam-deployment.properties
Log:
Oops, part of the capital letter bug fix
Modified: trunk/src/main/META-INF/seam-deployment.properties
===================================================================
--- trunk/src/main/META-INF/seam-deployment.properties 2008-10-04 14:04:33 UTC (rev 9189)
+++ trunk/src/main/META-INF/seam-deployment.properties 2008-10-04 14:46:32 UTC (rev 9190)
@@ -1 +1,2 @@
org.jboss.seam.deployment.deploymentHandlers=org.jboss.seam.bpm.PageflowDeploymentHandler
+org.jboss.seam.init.duplicateJarsPatterns=^tmp\\d+(\\S*.jar)
16 years, 1 month
Seam SVN: r9189 - in trunk: src/main/org/jboss/seam/init and 1 other directory.
by seam-commits@lists.jboss.org
Author: pete.muir(a)jboss.org
Date: 2008-10-04 10:04:33 -0400 (Sat, 04 Oct 2008)
New Revision: 9189
Modified:
trunk/seam-gen/build-scripts/build-war.xml
trunk/seam-gen/build-scripts/build.xml
trunk/src/main/org/jboss/seam/init/Initialization.java
Log:
JBSEAM-3499
Modified: trunk/seam-gen/build-scripts/build-war.xml
===================================================================
--- trunk/seam-gen/build-scripts/build-war.xml 2008-10-04 12:32:59 UTC (rev 9188)
+++ trunk/seam-gen/build-scripts/build-war.xml 2008-10-04 14:04:33 UTC (rev 9189)
@@ -146,7 +146,7 @@
</fileset>
</copy>
- <copy tofile="${war.dir}/components.properties"
+ <copy tofile="${war.dir}/WEB-INF/classes/components.properties"
file="${basedir}/resources/components-${profile}.properties"
overwrite="true"/>
Modified: trunk/seam-gen/build-scripts/build.xml
===================================================================
--- trunk/seam-gen/build-scripts/build.xml 2008-10-04 12:32:59 UTC (rev 9188)
+++ trunk/seam-gen/build-scripts/build.xml 2008-10-04 14:04:33 UTC (rev 9189)
@@ -103,7 +103,7 @@
<copy todir="${war.dir}">
<fileset dir="${basedir}/view" />
</copy>
- <copy tofile="${war.dir}/components.properties"
+ <copy tofile="${war.dir}/WEB-INF/classes/components.properties"
file="${basedir}/resources/components-${profile}.properties"
overwrite="true"/>
<copy todir="${war.dir}/WEB-INF">
Modified: trunk/src/main/org/jboss/seam/init/Initialization.java
===================================================================
--- trunk/src/main/org/jboss/seam/init/Initialization.java 2008-10-04 12:32:59 UTC (rev 9188)
+++ trunk/src/main/org/jboss/seam/init/Initialization.java 2008-10-04 14:04:33 UTC (rev 9189)
@@ -227,7 +227,7 @@
try
{
Properties replacements = new Properties();
- InputStream replaceStream = Resources.getResourceAsStream("components.properties", servletContext);
+ InputStream replaceStream = Resources.getResourceAsStream("/components.properties", servletContext);
if (replaceStream != null) replacements.load(replaceStream);
return replacements;
}
16 years, 1 month
Seam SVN: r9188 - trunk.
by seam-commits@lists.jboss.org
Author: pete.muir(a)jboss.org
Date: 2008-10-04 08:32:59 -0400 (Sat, 04 Oct 2008)
New Revision: 9188
Modified:
trunk/seam21migration.txt
Log:
Add a note on cache changes
Modified: trunk/seam21migration.txt
===================================================================
--- trunk/seam21migration.txt 2008-10-04 00:33:27 UTC (rev 9187)
+++ trunk/seam21migration.txt 2008-10-04 12:32:59 UTC (rev 9188)
@@ -140,4 +140,26 @@
--------
The org.jboss.seam.postInitialization event is no longer called on redeploy,
-instead org.jboss.seam.postReInitialization is called.
\ No newline at end of file
+instead org.jboss.seam.postReInitialization is called.
+
+
+Cache Support
+-------------
+
+Cache support has be rewritten to support JBoss Cache, JBoss POJO Cache, JBoss
+Cache 2 and EHCache. If you are running on JBoss AS 4.2.x JBoss Cache 1.x will
+be used or on JBoss 5.x JBoss Cache 2 will be installed. You can find more about
+how to configure the cache provider in the reference manual.
+
+The use <s:cache /> is unchanged, but you can no longer inject the pojoCache
+component. Instead you should configure JBoss POJO cache as your cache provider
+in components.xml:
+
+<cache:jboss-pojo-cache-provider />
+
+and inject it using
+
+@In CacheProvider<PojoCache> cacheProvider;
+
+The CacheProvider provides a Map like interface, and the getDelegate() method
+can be used to retrieve the underling cache.
\ No newline at end of file
16 years, 1 month
Seam SVN: r9187 - trunk/doc/Seam_Reference_Guide/en-US.
by seam-commits@lists.jboss.org
Author: norman.richards(a)jboss.com
Date: 2008-10-03 20:33:27 -0400 (Fri, 03 Oct 2008)
New Revision: 9187
Modified:
trunk/doc/Seam_Reference_Guide/en-US/Tutorial.xml
Log:
JBSEAM-3026
Modified: trunk/doc/Seam_Reference_Guide/en-US/Tutorial.xml
===================================================================
--- trunk/doc/Seam_Reference_Guide/en-US/Tutorial.xml 2008-10-03 20:05:13 UTC (rev 9186)
+++ trunk/doc/Seam_Reference_Guide/en-US/Tutorial.xml 2008-10-04 00:33:27 UTC (rev 9187)
@@ -526,10 +526,7 @@
<programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://jboss.com/products/seam/components"
xmlns:core="http://jboss.com/products/seam/core"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation=
- "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.1.xsd
- http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.1.xsd">
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<core:init jndi-pattern="@jndiPattern@"/>
@@ -1187,8 +1184,8 @@
task is complete, the business process ends. </para>
<para> The first JavaBean handles the login screen <literal>login.jsp</literal>. Its job is just to
- initialize the jBPM actor id using the <literal>actor</literal> component. (In a real application, it
- would also need to authenticate the user.) </para>
+ initialize the jBPM actor id using the <literal>actor</literal> component. In a real application, it
+ would also need to authenticate the user.</para>
<example>
<title>Login.java</title>
<programlisting role="JAVA"><![CDATA[@Name("login")
@@ -1299,7 +1296,7 @@
appear on the same method, because there is usually work to be done using the application in order to
complete the task. </para>
- <para> Finally, the meat of the application is in <literal>todo.jsp</literal>: </para>
+ <para> Finally, the core of the application is in <literal>todo.jsp</literal>: </para>
<example>
<title>todo.jsp</title>
<programlisting role="XHTML"><![CDATA[<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
@@ -1445,14 +1442,53 @@
</div>
</h:form>]]></programlisting>
- <para> There are several other files needed for the example, but they are just standard jBPM and Seam
- configuration and not very interesting. </para>
+
</section>
<section>
<title>How it works</title>
- <para>TODO</para>
+ <para>After logging in, todo.jsp uses the <literal>taskInstanceList</literal> component to display a table
+ of outstanding todo items for a the current user. Initially there are none. It
+ also presents a form to enter a new entry. When the user types the todo item and
+ hits the "Create New Item" button, <literal>#{todoList.createTodo}</literal> is called. This starts
+ the todo process, as defined in <literal>todo.jpdl.xml</literal>. </para>
+
+ <para>The process instance is created, starting in the start state and immediately transition to
+ the <literal>todo</literal> state, where a new task is created. The task description is set
+ based on the user's
+ input, which was saved to <literal>#{todoList.description}</literal>. Then, the task is
+ assigned to
+ the current user, which was stored in the seam actor component. Note that in
+ this example, the process has no extra process state. All the state in this example
+ is stored in the task definition. The process and task information is stored in the database
+ at the end of the request.
+ </para>
+
+ <para>
+ When <literal>todo.jsp</literal> is redisplayed, <literal>taskInstanceList</literal> now finds
+ the task that was just created.
+ The task is shown in an <literal>h:dataTable</literal>. The internal state of the task is
+ displayed in
+ each column: <literal>#{task.description}</literal>, <literal>#{task.priority}</literal>,
+ <literal>#{task.dueDate}</literal>, etc... These fields
+ can all be edited and saved back to the database.
+ </para>
+
+ <para>Each todo item also has "Done" button, which calls <literal>#{todoList.done}</literal>. The
+ <literal>todoList</literal> component
+ knows which task the button is for because each s:button specificies
+ <literal>taskInstance="#{task}"</literal>, referring
+ to the task for that particular line of of the table. The <literal>@StartTast</literal> and
+ <literal>@EndTask</literal> annotations
+ cause seam to make the task active and immediately complete the task. The original process then
+ transitions into the <literal>done</literal> state, according to the process definition, where it ends.
+ The state of the task and process are both updated in the database.
+ </para>
+
+ <para>When <literal>todo.jsp</literal> is displayed again, the now-completed task is no longer
+ displayed in the
+ <literal>taskInstanceList</literal>, since that component only display active tasks for the user.</para>
</section>
</section>
@@ -1849,7 +1885,55 @@
<section>
<title>How it works</title>
- <para>TODO</para>
+ <para>We'll step through basic flow of the application. The game starts with the
+ <literal>numberGuess.jspx</literal> view. When the page is first displayed, the
+ <literal>pages.xml</literal> configuration causes conversation to begin and associates
+ the <literal>numberGuess</literal> pageflow
+ with that conversation. The pageflow starts with a <literal>start-page</literal> tag,
+ which is a wait state, so the <literal>numberGuess.xhtml</literal> is rendered.
+ </para>
+
+ <para>The view references the <literal>numberGuess</literal> component, causing a new
+ instance to be created and stored in the conversation. The <literal>@Create</literal> method
+ is called, initializing the state of the game. The view displays an <literal>h:form</literal>
+ that allows the user to edit <literal>#{numberGuess.currentGuess}</literal>.
+ </para>
+
+ <para>The "Guess" button triggers the <literal>guess</literal> action. Seam defers to the pageflow
+ to handle the action, which says that the pageflow should transition to the <literal>evaluateGuess</literal>
+ state, first invoking <literal>#{numberGuess.guess}</literal>, which updates the guess count
+ and highest/lowest suggestions in the <literal>numberGuess</literal> component.
+ </para>
+
+ <para> The <literal>evaluateGuess</literal> state checks the value of <literal>#{numberGuess.correctGuess}</literal>
+ and transitions either to the <literal>win</literal> or <literal>evaluatingRemainingGuesses</literal>
+ state. We'll assume the number was incorrect, in which case the pageflow transitions to
+ <literal>evaluatingRemainingGuesses</literal>. That is also a decision state, which
+ tests the <literal>#{numberGuess.lastGuess}</literal> state to determine whether or not the user has
+ more guesses. If there are more guesses (<literal>lastGuess</literal> is <literal>false</literal>),
+ we transition back to the original <literal>displayGuess</literal> state. Finally we've
+ reached a page state, so the associated page <literal>/numberGuess.jspx</literal> is displayed.
+ Since the page has a redirect element, Seam sends a redirect to the the user's browser,
+ starting the process over.
+ </para>
+
+ <para>
+ We won't follow the state any more except to note that if on a future request either the
+ <literal>win</literal> or the <literal>lose</literal> transition were taken, the user would
+ be taken to either the <literal>/win.jspx</literal> or <literal>/lose.jspx</literal>.
+ Both states specify that Seam should end the conversation, tossing away all the game state and
+ pageflow state, before redirecting the user to the
+ final page.
+
+ </para>
+
+ <para>The numberguess example also contains Giveup and Cheat buttons. You should be able to
+ trace the pageflow state for both actions relatively easily. Pay particular attention
+ to the <literal>cheat</literal> transtition, which loads a sub-process to handle that flow.
+ Although it's
+ overkill for this application, it does demonstrate how complex pageflows can be broken down into
+ smaller parts to make them easier to understand.
+ </para>
</section>
</section>
@@ -1930,21 +2014,27 @@
</ulink>
</para>
- <para> Just nine classes (plus six session beans local interfaces) where used to implement this application.
- Six session bean action listeners contain all the business logic for the listed features. </para>
+ <para>The application uses six session beans for to implement the business logic for the listed features. </para>
<itemizedlist>
<listitem>
+ <para><literal>AuthenticatorAction</literal> provides the login authentication logic.</para>
+ </listitem>
+ <listitem>
<para><literal>BookingListAction</literal> retrieves existing bookings for the currently logged in user. </para>
</listitem>
<listitem>
<para><literal>ChangePasswordAction</literal> updates the password of the currently logged in user.</para>
</listitem>
<listitem>
- <para><literal>HotelBookingAction</literal> implements the core functionality of the application: hotel
- room searching, selection, booking and booking confirmation. This functionality is implemented as a
- <emphasis>conversation</emphasis>, so this is the most interesting class in the application. </para></listitem>
+ <para><literal>HotelBookingAction</literal> implements booking and confirmation
+ functionality. This functionality is implemented as a
+ <emphasis>conversation</emphasis>, so this is one of the most interesting classes in the
+ application.</para></listitem>
<listitem>
+ <para><literal>HotelSearchingAction</literal> implements the hotel search functionality.
+ </para></listitem>
+ <listitem>
<para><literal>RegisterAction</literal> registers a new system user.</para>
</listitem>
</itemizedlist>
@@ -1972,9 +2062,10 @@
conversation. The user can select multiple hotels from the same search results page, in different
browser tabs. </para>
<para> Most web application architectures have no first class construct to represent a conversation. This
- causes enormous problems managing state associated with the conversation. Usually, Java web applications
- use a combination of two techniques: first, some state is thrown into the
- <literal>HttpSession</literal>; second, persistable state is flushed to the database after every
+ causes enormous problems managing conversational state. Usually, Java web applications
+ use a combination of several techniques. Some state can be transfered in the URL.
+ What can't is either thrown into the
+ <literal>HttpSession</literal> or flushed to the database after every
request, and reconstructed from the database at the beginning of each new request. </para>
<para> Since the database is the least scalable tier, this often results in an utterly unacceptable lack of
scalability. Added latency is also a problem, due to the extra traffic to and from the database on every
@@ -1984,36 +2075,42 @@
with the data. Furthermore, because the cache is shared between many concurrent transactions, we've
introduced a whole raft of problem's associated with keeping the cached state consistent with the
database. </para>
- <para> Now consider the state held in the <literal>HttpSession</literal>. By very careful programming, we
- might be able to control the size of the session data. This is a lot more difficult than it sounds,
- since web browsers permit ad hoc non-linear navigation. But suppose we suddenly discover a system
- requirement that says that a user is allowed to have <emphasis>mutiple concurrent
- conversations</emphasis>, halfway through the development of the system (this has happened to me).
- Developing mechanisms to isolate session state associated with different concurrent conversations, and
- incorporating failsafes to ensure that conversation state is destroyed when the user aborts one of the
- conversations by closing a browser window or tab is not for the faint hearted (I've implemented this
- stuff twice so far, once for a client application, once for Seam, but I'm famously psychotic). </para>
- <para> Now there is a better way. </para>
+ <para> Now consider the state held in the <literal>HttpSession</literal>. The HttpSession is great
+ place for true session data, data that is common to all requests that the user has with the application.
+ However, it's a bad place to store data related to individual series of requests. Using the session of
+ conversational quickly breaks down when dealing with the back button and multiple windows.
+ On top of that, without careful
+ programming, data in the HTTP Session can grow quite large, making the HTTP session difficult
+ to cluster. Developing mechanisms to isolate session state associated with different concurrent
+ conversations, and incorporating failsafes to ensure that conversation state is destroyed when
+ the user aborts one of the
+ conversations by closing a browser window or tab is not for the faint hearted. Fortunately, with Seam,
+ you don't have to worry about that.
+ </para>
+
<para> Seam introduces the <emphasis>conversation context</emphasis> as a first class construct. You can
safely keep conversational state in this context, and be assured that it will have a well-defined
lifecycle. Even better, you won't need to be continually pushing data back and forth between the
application server and the database, since the conversation context is a natural cache of data that the
user is currently working with. </para>
- <para> Usually, the components we keep in the conversation context are stateful session beans. (We can also
- keep entity beans and JavaBeans in the conversation context.) There is an ancient canard in the Java
- community that stateful session beans are a scalability killer. This may have been true in 1998 when
- WebFoobar 1.0 was released. It is no longer true today. Application servers like JBoss AS have extremely
- sophisticated mechanisms for stateful session bean state replication. (For example, the JBoss EJB3
- container performs fine-grained replication, replicating only those bean attribute values which actually
- changed.) Note that all the traditional technical arguments for why stateful beans are inefficient apply
+ <para> In this application, we'll use the conversation context to store stateful session beans.
+ There is an ancient canard in the Java
+ community that stateful session beans are a scalability killer. This may have been true in the
+ early days of enterprise Java, but it is no longer true today. Modern application servers have
+ extremely
+ sophisticated mechanisms for stateful session bean state replication. JBoss AS, for example, performs
+ fine-grained replication, replicating only those bean attribute values which actually
+ changed. Note that all the traditional technical arguments for why stateful beans are inefficient apply
equally to the <literal>HttpSession</literal>, so the practice of shifting state from business tier
stateful session bean components to the web session to try and improve performance is unbelievably
misguided. It is certainly possible to write unscalable applications using stateful session beans, by
using stateful beans incorrectly, or by using them for the wrong thing. But that doesn't mean you should
- <emphasis>never</emphasis> use them. Anyway, Seam guides you toward a safe usage model. Welcome to
- 2005. </para>
- <para> OK, I'll stop ranting now, and get back to the tutorial. </para>
+ <emphasis>never</emphasis> use them.
+ If you remain unconvinced, Seam allows the use of POJOs instead of stateful session beans.
+ With Seam, the choice is yours.
+ </para>
+
<para> The booking example application shows how stateful components with different scopes can collaborate
together to achieve complex behaviors. The main page of the booking application allows the user to
search for hotels. The search results are kept in the Seam session scope. When the user navigates to one
@@ -2024,10 +2121,10 @@
the use of handwritten JavaScript. </para>
<para> The search functionality is implemented using a session-scope stateful session bean, similar to the
- one we saw in the message list example above. </para>
+ one we saw in the message list example. </para>
<example>
- <title></title>
+ <title>HotelSearchingAction.java</title>
<!-- Can't use code hightlighting with callouts -->
<programlistingco>
<areaspec>
@@ -2144,7 +2241,7 @@
<para> The main page of the application is a Facelets page. Let's look at the fragment which relates to
searching for hotels: </para>
<example>
- <title></title>
+ <title>main.xhtml</title>
<!-- Can't use code hightlighting with callouts -->
<programlistingco>
<areaspec>
@@ -2230,8 +2327,8 @@
perform a partial page update when the asynchronous response is received. </para>
</callout>
<callout arearefs="booking-status-element">
- <para> The RichFaces Ajax <literal><a:status></literal> tag lets us display a cheesy
- annimated image while we wait for asynchronous requests to return. </para>
+ <para> The RichFaces Ajax <literal><a:status></literal> tag lets us display an
+ animated image while we wait for asynchronous requests to return. </para>
</callout>
<callout arearefs="booking-outputpanel-element">
<para> The RichFaces Ajax <literal><a:outputPanel></literal> tag defines a region of
@@ -2264,7 +2361,7 @@
pretty long. But if you think of it as a list of scripted actions that implement the various steps of
the conversation, it's understandable. Read the class from top to bottom, as if it were a story. </para>
<example>
- <title></title>
+ <title>HotelBookingAction.java</title>
<!-- Can't use code hightlighting with callouts -->
<programlistingco>
<areaspec>
@@ -2416,28 +2513,6 @@
</section>
<section>
- <title>The Seam UI control library</title>
- <para> If you check inside the WAR file for the booking application, you'll find
- <literal>seam-ui.jar</literal> in the <literal>WEB-INF/lib</literal> directory. This package contains a
- number of JSF custom controls that integrate with Seam. The booking application uses the
- <literal><s:link></literal> control for navigation from the search screen to the hotel
- page: </para>
-
- <programlisting role="JAVA"><![CDATA[<s:link value="View Hotel" action="#{hotelBooking.selectHotel(hot)}"/>]]></programlisting>
-
- <para> The use of <literal><s:link></literal> here allows us to attach an action listener to a
- HTML link without breaking the browser's "open in new window" feature. The standard JSF
- <literal><h:commandLink></literal> does not work with "open in new window". We'll see
- later that <literal><s:link></literal> also offers a number of other useful features,
- including conversation propagation rules. </para>
-
- <para> The booking application uses some other Seam and RichFaces Ajax controls, especially on the
- <literal>/book.xhtml</literal> page. We won't get into the details of those controls here, but if
- you want to understand this code, please refer to the chapter covering Seam's functionality for JSF form
- validation. </para>
- </section>
-
- <section>
<title>The Seam Debug Page</title>
<para> The WAR also includes <literal>seam-debug.jar</literal>. The Seam debug page will be availabled
16 years, 1 month
Seam SVN: r9186 - trunk/src/excel/org/jboss/seam/excel/jxl.
by seam-commits@lists.jboss.org
Author: nickarls
Date: 2008-10-03 16:05:13 -0400 (Fri, 03 Oct 2008)
New Revision: 9186
Modified:
trunk/src/excel/org/jboss/seam/excel/jxl/JXLExcelWorkbook.java
Log:
Fix ratio problem with images
Modified: trunk/src/excel/org/jboss/seam/excel/jxl/JXLExcelWorkbook.java
===================================================================
--- trunk/src/excel/org/jboss/seam/excel/jxl/JXLExcelWorkbook.java 2008-10-03 19:57:11 UTC (rev 9185)
+++ trunk/src/excel/org/jboss/seam/excel/jxl/JXLExcelWorkbook.java 2008-10-03 20:05:13 UTC (rev 9186)
@@ -449,8 +449,10 @@
int useStartColumn = uiImage.getStartColumn() == null ? currentColumnIndex : uiImage.getStartRow();
int useStartRow = uiImage.getStartRow() == null ? currentRowIndex : uiImage.getStartRow();
- double useColumnSpan = uiImage.getColumnSpan() == null ? ((double)(image.getWidth() / CELL_DEFAULT_WIDTH)) : uiImage.getColumnSpan();
- double useRowSpan = uiImage.getRowSpan() == null ? ((double)(image.getWidth() / CELL_DEFAULT_HEIGHT)) : uiImage.getRowSpan();
+ double estimatedRowSpan = (double)image.getHeight() / (double)CELL_DEFAULT_HEIGHT;
+ double estimatedColSpan = (double)image.getWidth() / (double)CELL_DEFAULT_WIDTH;
+ double useColumnSpan = uiImage.getColumnSpan() == null ? estimatedRowSpan : uiImage.getColumnSpan();
+ double useRowSpan = uiImage.getRowSpan() == null ? estimatedColSpan : uiImage.getRowSpan();
worksheet.addImage(new WritableImage(useStartColumn, useStartRow, useColumnSpan, useRowSpan, pngStream.toByteArray()));
}
16 years, 1 month
Seam SVN: r9185 - trunk/doc/Seam_Reference_Guide/en-US.
by seam-commits@lists.jboss.org
Author: norman.richards(a)jboss.com
Date: 2008-10-03 15:57:11 -0400 (Fri, 03 Oct 2008)
New Revision: 9185
Modified:
trunk/doc/Seam_Reference_Guide/en-US/Tutorial.xml
Log:
JBSEAM-3026
Modified: trunk/doc/Seam_Reference_Guide/en-US/Tutorial.xml
===================================================================
--- trunk/doc/Seam_Reference_Guide/en-US/Tutorial.xml 2008-10-03 16:24:02 UTC (rev 9184)
+++ trunk/doc/Seam_Reference_Guide/en-US/Tutorial.xml 2008-10-03 19:57:11 UTC (rev 9185)
@@ -4,82 +4,83 @@
<title>Seam Tutorial</title>
<section id="try-examples">
- <title>Try the examples</title>
+ <title>Using the Seam examples</title>
- <para> In this tutorial, we'll assume that you have downloaded JBoss AS 4.2. You should also have a copy of
- Seam downloaded and extracted to a work directory. </para>
+ <para>Seam provides a number of example applications demonstrating how to use the various features
+ of Seam. This tutorial will guide you through a few of those examples to help you get started
+ learning Seam. The Seam examples are located in the <filename>examples</filename> subdirectory
+ of the Seam distribution. The registration example, which will be the first example we look at,
+ is in the <filename>examples/registration</filename> directory.</para>
- <para> The directory structure of each example in Seam follows this pattern: </para>
+ <para>Each example has the same directory structure:</para>
<itemizedlist>
<listitem>
- <para> Web pages, images and stylesheets may be found in
- <filename>examples/<replaceable>registration</replaceable>/view</filename>
+ <para> The <filename>view</filename> directory contains view-related files such as
+ web page templates, images and stylesheets.
+
</para>
</listitem>
<listitem>
- <para> Resources such as deployment descriptors and data import scripts may be found in
- <filename>examples/<replaceable>registration</replaceable>/resources</filename>
+ <para> The <filename>resources</filename> directory contains deployment descriptors and
+ other configuration files.
</para>
</listitem>
<listitem>
- <para> Java source code may be found in
- <filename>examples/<replaceable>registration</replaceable>/src</filename>
- </para>
+ <para> The <filename>src</filename> directory contains the application source code. </para>
</listitem>
- <listitem>
- <para> The Ant build script is
- <filename>examples/<replaceable>registration</replaceable>/build.xml</filename>
- </para>
- </listitem>
+
</itemizedlist>
+ <para>
+ The example applications run both on JBoss AS and Tomcat with no additional configuration.
+ The following sections will explain the procedure in both cases. Note that all the examples
+ are built and run from the Ant <filename>build.xml</filename>, so you'll need a recent version
+ of Ant installed before you get started.
+ </para>
+
+
+
<section>
<title>Running the examples on JBoss AS</title>
- <para> First, make sure you have Ant correctly installed, with <literal>$ANT_HOME</literal> and
- <literal>$JAVA_HOME</literal> set correctly. Next, make sure you set the location of your JBoss AS
- 4.2 installation in the <literal>build.properties</literal> file in the root folder of your Seam
- installation. If you haven't already done so, start JBoss AS now by typing <literal>bin/run.sh</literal>
- or <literal>bin/run.bat</literal> in the root directory of your JBoss installation. </para>
+ <para>The examples are configured for use on JBoss 4.2. You'll need to set <literal>jboss.home</literal>,
+ in the shared <literal>build.properties</literal> file in the root folder of your Seam
+ installation, to the location of your JBoss AS installation . </para>
- <para> Now, build and deploy the example by typing <literal>ant deploy</literal> in the
- <filename>examples/<replaceable>registration</replaceable></filename> directory. </para>
+ <para> Once you've done that and started the application server, you can build
+ and deploy any example by typing <literal>ant deploy</literal> in the
+ the directory for that example. The examples all deploy to a URL
+ like <literal>/seam-<replaceable>example</replaceable></literal>.
+ For the registration example, the URL would be <ulink url="http://localhost:8080/seam-registration/">
+ <literal>http://localhost:8080/seam-registration/</literal></ulink>. </para>
- <para> Try it out by accessing <ulink url="http://localhost:8080/seam-registration/">
- <literal>http://localhost:8080/seam-registration/</literal>
- </ulink> with your web browser. </para>
-
</section>
<section>
<title>Running the examples on Tomcat</title>
- <para>
- First, make sure you have Ant correctly installed, with <literal>$ANT_HOME</literal> and
- <literal>$JAVA_HOME</literal> set correctly. Next, make sure you set the location of your Tomcat
- 6.0 installation in the <literal>build.properties</literal> file in the root folder of your Seam
- installation. You will need to follow the instructions in <xref linkend="config.install.embedded"/>
- for installing JBoss Embedded on Tomcat 6.0. JBoss Embedded is required to run the Seam demo
- applications on Tomcat. (However, it is possible to use Seam on Tomcat without JBoss Embedded.)
+ <para>The examples are also configured for use on Tomcat 6.0. You will need to follow the
+ instructions in <xref linkend="config.install.embedded"/>
+ for installing JBoss Embedded on Tomcat 6.0. JBoss Embedded is only required to run the Seam
+ demos that use EJB3 components on Tomcat. There are also examples of non-EJB3 applications that
+ can be run on Tomcat without the use of JBoss Embedded.
</para>
-
- <para>
- Now, build and deploy the example by typing <literal>ant tomcat.deploy</literal> in the
- <filename>examples/<replaceable>registration</replaceable></filename> directory.
+ <para>You'll need to
+ set <literal>tomcat.home</literal>, in the shared <literal>build.properties</literal> file in
+ the root folder of your Seam installation, to the location of your Tomcat installation.
+ make sure you set the location of your Tomcat.
</para>
- <para>Finally, start Tomcat.</para>
-
- <para>
- Try it out by accessing <ulink url="http://localhost:8080/jboss-seam-registration/">
- <literal>http://localhost:8080/jboss-seam-registration/</literal>
- </ulink> with your web browser.
+ <para>You'll need to use a different Ant target when using Tomcat. Use
+ <literal>ant tomcat.deploy</literal> in example subdirectory to build and deploy
+ any example for Tomcat.
</para>
- <para>
- When you deploy the example to Tomcat, any EJB3 components will run inside the JBoss Embeddable EJB3
- container, a complete standalone EJB3 container environment.
+ <para>On Tomcat, the examples deploy to URLs like
+ <literal>/jboss-seam-<replaceable>example</replaceable></literal>, so for the registration
+ example the URL would be <ulink url="http://localhost:8080/jboss-seam-registration/">
+ <literal>http://localhost:8080/jboss-seam-registration/</literal></ulink>.
</para>
</section>
@@ -87,9 +88,9 @@
<section>
<title>Running the example tests</title>
<para>
- Most of the examples come with a suite of TestNG integration tests. The easiest way to run the tests
- is to run <literal>ant testexample</literal> inside the
- <filename>examples/<replaceable>registration</replaceable></filename> directory. It is also possible
+ Most of the examples come with a suite of TestNG integration tests. The easiest way to
+ run the tests
+ is to run <literal>ant test</literal>. It is also possible
to run the tests inside your IDE using the TestNG plugin.
</para>
</section>
@@ -99,7 +100,7 @@
<section id="registration-example">
<title>Your first Seam application: the registration example</title>
- <para> The registration example is a fairly trivial application that lets a new user store his username, real
+ <para> The registration example is a simple application that lets a new user store his username, real
name and password in the database. The example isn't intended to show off all of the cool functionality of
Seam. However, it demonstrates the use of an EJB3 session bean as a JSF action listener, and basic
configuration of Seam. </para>
@@ -121,7 +122,8 @@
<section>
<title>Understanding the code</title>
- <para> The example is implemented with two JSP pages, one entity bean and one stateless session bean. </para>
+ <para> The example is implemented with two Facelets templates, one entity bean and one
+ stateless session bean. </para>
<mediaobject>
<imageobject role="fo">
@@ -142,7 +144,7 @@
annotations that define the class as a Seam component. </para>
<!-- Can't use code hightlighting with callouts -->
<example>
- <title></title>
+ <title>User.java</title>
<programlistingco>
<areaspec>
<area id="registration-entity-annotation" coords="1"/>
@@ -286,7 +288,7 @@
<para> This is the only really interesting code in the example! </para>
<!-- Can't use code hightlighting with callouts -->
<example>
- <title></title>
+ <title>RegisterAction.java</title>
<programlistingco>
<areaspec>
<area id="registration-stateless-annotation" coords="1"/>
@@ -336,7 +338,7 @@
<calloutlist>
<callout arearefs="registration-stateless-annotation">
- <para> The EJB standard <literal>@Stateless</literal> annotation marks this class as
+ <para> The EJB <literal>@Stateless</literal> annotation marks this class as
a stateless session bean. </para>
</callout>
<callout arearefs="registration-in-annotation">
@@ -395,20 +397,19 @@
<para> Note that we did not explicitly specify a <literal>@Scope</literal> this time. Each Seam
component type has a default scope if not explicitly specified. For stateless session beans, the
- default scope is the stateless context. Actually, <emphasis>all</emphasis> stateless session
- beans belong in the stateless context. </para>
+ default scope is the stateless context, which is the only sensible value.</para>
<para> Our session bean action listener performs the business and persistence logic for our
- mini-application. In more complex applications, we might need to layer the code and refactor
- persistence logic into a dedicated data access component. That's perfectly trivial to do. But
- notice that Seam does not force you into any particular strategy for application layering. </para>
-
- <para> Furthermore, notice that our session bean has simultaneous access to context associated with
- the web request (the form values in the <literal>User</literal> object, for example), and state
- held in transactional resources (the <literal>EntityManager</literal> object). This is a break
- from traditional J2EE architectures. Again, if you are more comfortable with the traditional
- J2EE layering, you can certainly implement that in a Seam application. But for many
- applications, it's simply not very useful. </para>
+ mini-application. In more complex applications, we might need require a separate service
+ layer. This is easy to achieve with Seam, but it's overkill for most web applications.
+ Seam does not force you into any particular strategy for application layering, allowing
+ your application to be as simple, or as complex, as you want.
+ </para>
+ <para>Note that in this simple
+ application, we've actually made it far more complex than it needs to be. If we had
+ used the Seam application framework controllers, we would have eliminated all of our
+ application code. However, then we wouldn't have had much of an application to explain.
+ </para>
</section>
@@ -417,7 +418,7 @@
<para>Naturally, our session bean needs a local interface.</para>
- <example><title></title>
+ <example><title>Register.java</title>
<programlisting role="JAVA"><![CDATA[@Local
public interface Register
{
@@ -425,13 +426,89 @@
}]]></programlisting></example>
- <para> That's the end of the Java code. Now onto the deployment descriptors. </para>
+ <para> That's the end of the Java code. Now we'll look at the view.</para>
</section>
<section>
+ <title>The view: <literal>register.xhtml</literal> and <literal>registered.xhtml</literal></title>
+
+ <para> The view pages for a Seam application could be implemented using any technology that supports
+ JSF. In this example we use Facelets, because we think it's better than JSP.</para>
+
+ <example>
+ <title>register.xhtml</title>
+ <programlisting role="XHTML"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
+<!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:s="http://jboss.com/products/seam/taglib"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core">
+
+ <head>
+ <title>Register New User</title>
+ </head>
+ <body>
+ <f:view>
+ <h:form>
+ <s:validateAll>
+ <h:panelGrid columns="2">
+ Username: <h:inputText value="#{user.username}" required="true"/>
+ Real Name: <h:inputText value="#{user.name}" required="true"/>
+ Password: <h:inputSecret value="#{user.password}" required="true"/>
+ </h:panelGrid>
+ </s:validateAll>
+ <h:messages/>
+ <h:commandButton value="Register" action="#{register.register}"/>
+ </h:form>
+ </f:view>
+ </body>
+
+</html>]]></programlisting></example>
+
+
+ <para> The only thing here that is specific to Seam is the
+ <literal><s:validateAll></literal> tag. This JSF component tells JSF to validate all
+ the contained input fields against the Hibernate Validator annotations specified on the entity bean. </para>
+
+ <example>
+ <title>registered.xhtml</title>
+ <programlisting role="XHTML"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
+<!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:f="http://java.sun.com/jsf/core">
+
+ <head>
+ <title>Successfully Registered New User</title>
+ </head>
+ <body>
+ <f:view>
+ Welcome, #{user.name}, you are successfully registered as #{user.username}.
+ </f:view>
+ </body>
+
+</html>
+]]></programlisting>
+ </example>
+
+
+ <para> This is a simple Facelets page using some embedded EL. There is nothing specific to Seam
+ here. </para>
+
+ </section>
+
+ <section>
<title>The Seam component deployment descriptor: <literal>components.xml</literal></title>
+ <para>Since this is the first Seam app we've seen, we'll take a look at the deployment
+ descriptors. Before we get into them, it is worth noting that Seam strongly values
+ minimal configuration. These configuration files will be created for you when you create a Seam
+ application. You'll never need to touch most of these files. We're presenting them
+ now only to help you understand what all the pieces in the example are doing.
+ </para>
+
<para> If you've used many Java frameworks before, you'll be used to having to declare all your
component classes in some kind of XML file that gradually grows more and more unmanageable as your
project matures. You'll be relieved to know that Seam does not require that application components
@@ -445,7 +522,7 @@
<literal>WEB-INF</literal> directory. We'll use the <literal>components.xml</literal> file to tell
Seam how to find our EJB components in JNDI: </para>
<example>
- <title></title>
+ <title>components.xml</title>
<programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://jboss.com/products/seam/components"
xmlns:core="http://jboss.com/products/seam/core"
@@ -469,7 +546,8 @@
<para> The presentation layer for our mini-application will be deployed in a WAR. So we'll need a web
deployment descriptor. </para>
- <example><title></title>
+ <example>
+ <title>web.xml</title>
<programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
@@ -525,7 +603,7 @@
defining our views, so we need to tell JSF to use Facelets as its templating engine. </para>
<example>
- <title></title>
+ <title>faces-config.xml</title>
<programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee"
@@ -611,75 +689,6 @@
</section>
<section>
- <title>The view: <literal>register.xhtml</literal> and <literal>registered.xhtml</literal></title>
-
- <para> The view pages for a Seam application could be implemented using any technology that supports
- JSF. In this example we use Facelets, because we think it's better than JSP.</para>
-
- <example>
- <title></title>
- <programlisting role="XHTML"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
-<!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:s="http://jboss.com/products/seam/taglib"
- xmlns:h="http://java.sun.com/jsf/html"
- xmlns:f="http://java.sun.com/jsf/core">
-
- <head>
- <title>Register New User</title>
- </head>
- <body>
- <f:view>
- <h:form>
- <s:validateAll>
- <h:panelGrid columns="2">
- Username: <h:inputText value="#{user.username}" required="true"/>
- Real Name: <h:inputText value="#{user.name}" required="true"/>
- Password: <h:inputSecret value="#{user.password}" required="true"/>
- </h:panelGrid>
- </s:validateAll>
- <h:messages/>
- <h:commandButton value="Register" action="#{register.register}"/>
- </h:form>
- </f:view>
- </body>
-
-</html>]]></programlisting></example>
-
-
- <para> The only thing here that is specific to Seam is the
- <literal><s:validateAll></literal> tag. This JSF component tells JSF to validate all
- the contained input fields against the Hibernate Validator annotations specified on the entity bean. </para>
-
- <example>
- <title></title>
- <programlisting role="XHTML"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
-<!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:f="http://java.sun.com/jsf/core">
-
- <head>
- <title>Successfully Registered New User</title>
- </head>
- <body>
- <f:view>
- Welcome, #{user.name}, you are successfully registered as #{user.username}.
- </f:view>
- </body>
-
-</html>
-]]></programlisting>
- </example>
-
-
- <para> This is a boring old Facelets page using some embedded EL. There is nothing specific to Seam
- here. </para>
-
- </section>
-
- <section>
<title>The EAR deployment descriptor: <literal>application.xml</literal></title>
<para> Finally, since our application is deployed as an EAR, we need a deployment descriptor there, too. </para>
@@ -779,7 +788,7 @@
flag indicating whether the message has been read: </para>
<example>
- <title></title>
+ <title>Message.java</title>
<programlisting role="JAVA"><![CDATA[@Entity
@Name("message")
@Scope(EVENT)
@@ -855,7 +864,7 @@
stateful session bean. </para>
<!-- Can't use code hightlighting with callouts -->
<example>
- <title></title>
+ <title>MessageManagerBean.java</title>
<programlistingco>
<areaspec>
<area id="messages-datamodel" coords="7"/>
@@ -886,7 +895,7 @@
@Factory("messageList")
public void findMessages()
{
- messageList = em.createQuery("from Message msg order by msg.datetime desc")
+ messageList = em.createQuery("select msg from Message msg order by msg.datetime desc")
.getResultList();
}
@@ -968,7 +977,9 @@
<title>The session bean local interface: <literal>MessageManager.java</literal></title>
<para> All session beans have a business interface, of course. </para>
-
+ <example>
+ <title>MessageManager.java</title>
+
<programlisting role="JAVA"><![CDATA[@Local
public interface MessageManager
{
@@ -976,7 +987,7 @@
public void select();
public void delete();
public void destroy();
-}]]></programlisting>
+}]]></programlisting></example>
<para> From now on, we won't show local interfaces in our code examples. </para>
@@ -993,7 +1004,7 @@
<para> The JSP page is a straightforward use of the JSF <literal><h:dataTable></literal>
component. Again, nothing specific to Seam. </para>
<example>
- <title></title>
+ <title>messages.jsp</title>
<programlisting role="XHTML"><![CDATA[<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<html>
@@ -1048,8 +1059,7 @@
<section>
<title>How it works</title>
- <para> The first time we navigate to the <literal>messages.jsp</literal> page, whether by a JSF postback
- (faces request) or a direct browser GET request (non-faces request), the page will try to resolve the
+ <para> The first time we navigate to the <literal>messages.jsp</literal> page, the page will try to resolve the
<literal>messageList</literal> context variable. Since this context variable is not initialized,
Seam will call the factory method <literal>findMessages()</literal>, which performs a query against the
database and results in a <literal>DataModel</literal> being outjected. This
@@ -1102,7 +1112,7 @@
other transactional behavior). Let's start with the process definition: </para>
<!-- Can't use code hightlighting with callouts -->
<example>
- <title></title>
+ <title>todo.jpdl.xml</title>
<programlistingco>
<areaspec>
<area id="todo-startstate" coords="3"/>
@@ -1180,7 +1190,7 @@
initialize the jBPM actor id using the <literal>actor</literal> component. (In a real application, it
would also need to authenticate the user.) </para>
<example>
- <title></title>
+ <title>Login.java</title>
<programlisting role="JAVA"><![CDATA[@Name("login")
public class Login {
@@ -1211,7 +1221,9 @@
<para> The JSP itself is trivial: </para>
- <programlisting role="XHTML"><![CDATA[<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
+ <example>
+ <title>login.jsp</title>
+ <programlisting role="XHTML"><![CDATA[<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html>
<head>
@@ -1228,7 +1240,7 @@
</h:form>
</f:view>
</body>
-</html>]]></programlisting>
+</html>]]></programlisting></example>
@@ -1236,7 +1248,7 @@
<!-- Can't use code hightlighting with callouts -->
<example>
- <title></title>
+ <title>TodoList.java</title>
<programlistingco>
<areaspec>
<area id="todo-description" coords="6"/>
@@ -1289,7 +1301,7 @@
<para> Finally, the meat of the application is in <literal>todo.jsp</literal>: </para>
<example>
- <title></title>
+ <title>todo.jsp</title>
<programlisting role="XHTML"><![CDATA[<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://jboss.com/products/seam/taglib" prefix="s" %>
@@ -1363,7 +1375,7 @@
<para> The page renders a list of tasks, which it gets from a built-in Seam component named
<literal>taskInstanceList</literal>. The list is defined inside a JSF form. </para>
<example>
- <title></title>
+ <title>todo.jsp</title>
<programlisting role="XHTML"><![CDATA[<h:form id="list">
<div>
<h:outputText value="There are no todo items." rendered="#{empty taskInstanceList}"/>
@@ -1416,12 +1428,11 @@
<s:button value="Done" action="#{todoList.done}" taskInstance="#{task}"/>
</h:column>]]></programlisting>
- <para> (Note that this is using a Seam <literal><s:button></literal> JSF control from the
- <literal>seam-ui.jar</literal> package.) </para>
+ <para> Note that this is using a Seam <literal><s:button></literal> JSF control from the
+ <literal>seam-ui.jar</literal> package. This button is used to update the properties of the
+ tasks. When the form is submitted, Seam and jBPM will make any changes to the tasks persistent.
+ There is no need for any action listener method: </para>
- <para> This button is used to update the properties of the tasks. When the form is submitted, Seam and jBPM
- will make any changes to the tasks persistent. There is no need for any action listener method: </para>
-
<programlisting role="XHTML"><![CDATA[<h:commandButton value="Update Items" action="update"/>]]></programlisting>
<para> A second form on the page is used to create new items, by calling the action method annotated
@@ -1438,6 +1449,7 @@
configuration and not very interesting. </para>
</section>
+
<section>
<title>How it works</title>
<para>TODO</para>
@@ -1472,7 +1484,7 @@
begin with the pageflow: </para>
<!-- Can't use code hightlighting with callouts -->
<example>
- <title></title>
+ <title>pageflow.jpdl.xml</title>
<programlistingco>
<areaspec>
<area id="numberguess-page" coords="8"/>
@@ -1493,6 +1505,7 @@
<action expression="#{numberGuess.guess}"/>
</transition>
<transition name="giveup" to="giveup"/>
+ <transition name="cheat" to="cheat"/>
</start-page>
<decision name="evaluateGuess" expression="#{numberGuess.correctGuess}">
@@ -1511,6 +1524,11 @@
<transition name="no" to="displayGuess"/>
</page>
+ <process-state name="cheat">
+ <sub-process name="cheat"/>
+ <transition to="displayGuess"/>
+ </process-state>
+
<page name="win" view-id="/win.jspx">
<redirect/>
<end-conversation/>
@@ -1566,7 +1584,7 @@
<para> Here is the main page of the application, <literal>numberGuess.jspx</literal>: </para>
<example>
- <title></title>
+ <title>numberGuess.jspx</title>
<programlisting role="XHTML"><![CDATA[<<?xml version="1.0"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:h="http://java.sun.com/jsf/html"
@@ -1645,7 +1663,7 @@
<para> The <literal>win.jspx</literal> page is predictable: </para>
<example>
- <title></title>
+ <title>win.jspx</title>
<programlisting role="JSP"><![CDATA[<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
@@ -1676,11 +1694,12 @@
</example>
- <para> As is <literal>lose.jspx</literal> (which I can't be bothered copy/pasting). Finally, the JavaBean
- Seam component: </para>
+ <para>The <literal>lose.jspx</literal> looks roughly the same, so we'll skip over it.</para>
+
+ <para>Finally, we'll look at the actual application code: </para>
<!-- Can't use code hightlighting with callouts -->
<example>
- <title></title>
+ <title>NumberGuess.java</title>
<programlistingco>
<areaspec>
<area id="numberguess-create" coords="13"/>
@@ -1805,7 +1824,10 @@
pageflow definition to use for the conversation's page flow.
</para>
+ <example>
+ <title>pages.xml</title>
+
<programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -1815,12 +1837,9 @@
<begin-conversation join="true" pageflow="numberGuess"/>
</page>
- <page view-id="/confirm.jspx">
- <begin-conversation nested="true" pageflow="cheat"/>
- </page>
-
</pages>
-]]></programlisting>
+]]></programlisting>
+ </example>
<para> As you can see, this Seam component is pure business logic! It doesn't need to know anything at all
16 years, 1 month