Feb 14 2011

Quick-Start: SEAM-Framework and Maven without seam-gen

Frank

This short tutorial gives you the needed steps to integrate SEAM into an existing WAR-project or to build such a WAR from the beginning.

1. Including Dependencies

First of all you need to add the SEAM dependencies and of course JSF, if not already present:

		<dependency>
			<groupId>javax.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>1.2_15</version>
		</dependency>
		<dependency>
			<groupId>javax.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>1.2_15</version>
		</dependency>
		<dependency>
			<groupId>com.sun.facelets</groupId>
			<artifactId>jsf-facelets</artifactId>
			<version>1.1.15.B1</version>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam</groupId>
			<artifactId>jboss-seam</artifactId>
			<version>2.2.1.Final</version>
			<exclusions>
				<exclusion>
					<groupId>javax.el</groupId>
					<artifactId>el-api</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.jboss.seam</groupId>
			<artifactId>jboss-seam-ui</artifactId>
			<version>2.2.1.Final</version>
		</dependency>

2. Modify web.xml

Here you have to add the FacesServlet for JSF, the Seam-Filter for SEAM and a Listener for SEAM. Additionally you can define some CONTEXT-variables for JSF / SEAM.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
	<!-- Context Variables -->
	<context-param>
		<param-name>facelets.SKIP_COMMENTS</param-name>
		<param-value>true</param-value>
	</context-param>
	<!-- Seam Listener -->
	<listener>
		<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
	</listener>
	<!-- Seam Filter -->
	<filter>
		<filter-name>Seam Filter</filter-name>
		<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>Seam Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<!-- JSF 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>*.html</url-pattern>
	</servlet-mapping>
	<!-- Seam Resource Servlet -->
	<servlet>
		<servlet-name>Seam Resource Servlet</servlet-name>
		<servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>Seam Resource Servlet</servlet-name>
		<url-pattern>/seam/resource/*</url-pattern>
	</servlet-mapping>
</web-app>

3. Configure JSF

Then you have to add an faces-config.xml to the WEB-INF directory.

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xi="http://www.w3.org/2001/XInclude"
 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">
</faces-config>

4. Configure SEAM
Just add some empty configuration files to enable seam for your WAR.

<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://jboss.com/products/seam/components"
	xmlns:core="http://jboss.com/products/seam/core" xmlns:transaction="http://jboss.com/products/seam/transaction"
	xmlns:web="http://jboss.com/products/seam/web" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<core:init debug="false" />
</components>

And also put an empty seam.properties to your classpath (in directory src/main/resources).


Feb 7 2011

Using MDB-Topic as cluster-wide event listener

Frank

Yesterday I had the problem that I need to send a broadcast message in an application which should be processed by every running node. This message should be the initiator to clear a local cache on each node. So I had the idea to use JMS as API using a topic and every node will listen on that topic. I am using this on JBoss 5.1.0.GA.

First of all the need to define an Topic. This could be done in an own service.xml, which is located directly in the deploy directory or (my preferred way) in the ear.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
< ?xml version="1.0" encoding="UTF-8"?>
<server>
	<mbean code="org.jboss.jms.server.destination.TopicService"
		name="jboss.messaging.destination:service=Topic,name=MyEvents"
		xmbean-dd="xmdesc/Topic-xmbean.xml">
		<depends optional-attribute-name="ServerPeer">
			jboss.messaging:service=ServerPeer
		 </depends>
		<depends>
			jboss.messaging:service=PostOffice</depends>
		<attribute name="Clustered">true</attribute>
	</mbean>
 
</server>

Especially the attribute “Clustered” is important. Otherwise you would only have a local topic and not a cluster-wide.

Next we have to define our listener:

1
2
3
4
5
6
7
8
9
10
11
12
@MessageDriven(activationConfig = {
		@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
		@ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/MyEvents") }, messageListenerInterface = MessageListener.class)
@Depends(value = { "jboss.messaging:service=PostOffice",
		"jboss.messaging.destination:name=MyEvents,service=Topic" })
public class ClusterEventsListener implements MessageListener {
 
	public void onMessage(Message message) {
              //do some stuff
              System.out.println("received an event");
	}
}

That’s all, now you can easily send some events using standard JMS commands, for example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Stateless
public class SendEventImpl implements SendEvent {
 
	@Resource(mappedName = "topic/MyEvents")
	private Topic eventTopic;
 
	@Resource(mappedName = "ConnectionFactory")
	private TopicConnectionFactory eventQueueFactory;
 
	public void sendEvent() {
		try {
			TopicConnection cnn = null;
			TopicSession sess = null;
			TopicPublisher publisher = null;
			try {
				cnn = eventQueueFactory.createTopicConnection();
				sess = cnn.createTopicSession(false,
						TopicSession.AUTO_ACKNOWLEDGE);
 
				publisher = sess.createPublisher(eventTopic);
				TextMessage message = sess.createTextMessage("hello world");
				publisher.send(message);
			} finally {
				try {
					if (publisher != null)
						publisher.close();
				} catch (Throwable e) {
					log.error("closing sender", e);
				}
				try {
					if (sess != null)
						sess.close();
				} catch (Throwable e) {
					log.error("closing session", e);
				}
				try {
					if (cnn != null)
						cnn.close();
				} catch (Throwable e) {
					log.error("closing connection", e);
				}
			}
		} catch (JMSException e) {
			throw new RuntimeException(e);
		}
	}
}