You installed Tomcat v7 within eclipse using the “Add server” wizard and the  “download and install” button.

You tried to start Tomcat and got the following error:

“Could not load the Tomcat server configuration at /Servers/Tomcat v7.0 Server at localhost-config. The configuration may be corrupt or incomplete”

How to solve:

  1. Close Eclipse
  2. Copy all files from TOMCAT_7_HOME/conf to WORKSPACE_FOLDER/Servers/Tomcat v7.0 Server at localhost-config
  3. Start Eclipse
  4. Expand the Servers project, click on the Tomcat 7 project and hit F5
  5. Start Tomcat from Eclipse
 

HTML5

On March 31, 2012, in HTML5, by lucasterdev

How to know if a web site was made with HTML5?

If its background seems monochrome, but after looking more closely, it’s actually melange, like velvet or carpet: you’ll know that web site was made with HTML5.

Like this:

 

Install JavaFX in Ubuntu

On March 25, 2012, in Java FX, Ubuntu, by lucasterdev

http://docs.oracle.com/javafx/2.0/release_notes_linux/jfxpub-release_notes_linux.htm

http://www.oracle.com/technetwork/java/javafx/downloads/devpreview-1429449.html

http://www.webupd8.org/2011/09/how-to-install-oracle-java-7-jdk-in.html

 

sudo add-apt-repository ppa:webupd8team/java

sudo apt-get update

sudo apt-get install oracle-jdk7-installer

 

JSF extensions and JQuery versions

On February 11, 2012, in JSF, PrimeFaces, RichFaces, by lucasterdev

PrimeFaces 3.1 uses JQuery 1.7.1

PrimeFaces 3.0.1 uses JQuery 1.7.1

RichFaces 4.2.0.CR1 uses JQuery 1.7.1

RichFaces 4.1.0.Final uses JQuery 1.6.4

 

 

Resin

On February 11, 2012, in Eclipse, Resin, by lucasterdev

After installing Resin and the Resin Plugin for Eclipse, here’s what I get when I start the server:

/home/luca/Software/eclipse_indigo_32bit/workspace/Servers/Resin 4.0 at localhost-config/resin.xml:38: com.caucho.config.core.ResinImport.init(): Required file '/home/luca/Software/eclipse_indigo_32bit/workspace/Servers/Resin 4.0 at localhost-config/cluster-default.xml' can not be read for resin:import.
 at com.caucho.config.xml.XmlConfigContext.error(XmlConfigContext.java:1239)
 at com.caucho.config.xml.XmlConfigContext.configureChildNode(XmlConfigContext.java:471)
 at com.caucho.config.xml.XmlConfigContext.configureNode(XmlConfigContext.java:371)
 at com.caucho.config.xml.XmlConfigContext.configureBean(XmlConfigContext.java:285)
 at com.caucho.config.xml.XmlConfigContext.configure(XmlConfigContext.java:243)
 at com.caucho.config.Config.configure(Config.java:326)
 at com.caucho.config.Config.configure(Config.java:256)
 at com.caucho.server.resin.BootConfig.configureFile(BootConfig.java:131)
 at com.caucho.server.resin.Resin.configureFile(Resin.java:849)
 at com.caucho.server.resin.Resin.<init>(Resin.java:214)
 at com.caucho.server.resin.Resin.<init>(Resin.java:172)
 at com.caucho.server.resin.Resin.main(Resin.java:1232)
Caused by: com.caucho.config.ConfigException: com.caucho.config.core.ResinImport.init(): Required file '/home/luca/Software/eclipse_indigo_32bit/workspace/Servers/Resin 4.0 at localhost-config/cluster-default.xml' can not be read for resin:import.
 at com.caucho.config.ConfigException.create(ConfigException.java:99)
 at com.caucho.config.ConfigException.create(ConfigException.java:130)
 at com.caucho.config.j2ee.PostConstructProgram.inject(PostConstructProgram.java:142)
 at com.caucho.config.type.InlineBeanType.init(InlineBeanType.java:457)
 at com.caucho.config.xml.XmlConfigContext.configureChildBean(XmlConfigContext.java:704)
 at com.caucho.config.xml.XmlConfigContext.configureBeanProperties(XmlConfigContext.java:685)
 at com.caucho.config.xml.XmlConfigContext.configureChildNode(XmlConfigContext.java:464)
 ... 10 more
Caused by: com.caucho.config.ConfigException: Required file '/home/luca/Software/eclipse_indigo_32bit/workspace/Servers/Resin 4.0 at localhost-config/cluster-default.xml' can not be read for resin:import.
 at com.caucho.config.core.ResinImport.init(ResinImport.java:115)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:616)
 at com.caucho.config.j2ee.PostConstructProgram.inject(PostConstructProgram.java:140)
 ... 14 more
/home/luca/Software/eclipse_indigo_32bit/workspace/Servers/Resin 4.0 at localhost-config/resin.xml:38: com.caucho.config.core.ResinImport.init(): Required file '/home/luca/Software/eclipse_indigo_32bit/workspace/Servers/Resin 4.0 at localhost-config/cluster-default.xml' can not be read for resin:import.

Copy cluster-default.xml from RESIN_HOME/conf to ECLIPSE_HOME/Workspace/Servers/Resin 4.0 at localhost-config.

Now Resin starts bu I get this:


[12-02-11 15:34:17.373] {http://*:8080-15} Unable to find native library 'resin_os' for com.caucho.loader.ClassEntry. Resin expects to find this library in:
 (Unix) /home/luca/Software/resin-4.0.25/libexec/libresin_os.so
 On Unix, run ./configure --prefix=`pwd`; make; make install.

 The JVM exception was: java.lang.UnsatisfiedLinkError: no resin_os in java.library.path

The server starts though…

 

[Solved] Using TestNG offline fails

On February 5, 2012, in Testing, TestNG, by lucasterdev

When your run TestNG tests and you have no Internet connection, you may get the following exception:

TestNG] Running:
  /tmp/testng-eclipse--29095373/testng-customsuite.xml

ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Parse: name=vfsfile:/home/luca/Software/eclipse_indigo_32bit/workspace/seam423ear-test/bin/ state=Not Installed mode=Manual requiredState=Parse
org.jboss.deployers.spi.DeploymentException: Error creating managed object for vfsfile:/home/luca/Software/eclipse_indigo_32bit/workspace/seam423ear-test/bin/
	at org.jboss.deployers.spi.DeploymentException.rethrowAsDeploymentException(DeploymentException.java:49)
	at org.jboss.deployers.spi.deployer.helpers.AbstractParsingDeployerWithOutput.createMetaData(AbstractParsingDeployerWithOutput.java:232)
	at org.jboss.deployers.spi.deployer.helpers.AbstractParsingDeployerWithOutput.createMetaData(AbstractParsingDeployerWithOutput.java:199)
	at org.jboss.deployers.spi.deployer.helpers.AbstractParsingDeployerWithOutput.deploy(AbstractParsingDeployerWithOutput.java:162)
	at org.jboss.deployers.plugins.deployers.DeployerWrapper.deploy(DeployerWrapper.java:169)
	at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:853)
	at org.jboss.deployers.plugins.deployers.DeployersImpl.install(DeployersImpl.java:794)
	at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:327)
	at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1309)
	at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:734)
	at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:862)
	at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:784)
	at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:622)
	at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:411)
	at org.jboss.deployers.plugins.deployers.DeployersImpl.process(DeployersImpl.java:498)
	at org.jboss.deployers.plugins.main.MainDeployerImpl.process(MainDeployerImpl.java:506)
	at org.jboss.embedded.DeploymentGroup.process(DeploymentGroup.java:127)
	at org.jboss.embedded.Bootstrap.deployResourceBases(Bootstrap.java:289)
	at org.jboss.seam.mock.EmbeddedBootstrap.startAndDeployResources(EmbeddedBootstrap.java:15)
	at org.jboss.seam.mock.AbstractSeamTest.startJbossEmbeddedIfNecessary(AbstractSeamTest.java:1034)
	at org.jboss.seam.mock.AbstractSeamTest.startSeam(AbstractSeamTest.java:925)
	at org.jboss.seam.mock.SeamTest.startSeam(SeamTest.java:69)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:616)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
	at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:543)
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:212)
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:277)
	at org.testng.SuiteRunner.run(SuiteRunner.java:240)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:87)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1142)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1067)
	at org.testng.TestNG.run(TestNG.java:979)
	at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:109)
	at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:202)
	at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:173)
Caused by: javax.xml.bind.UnmarshalException
 - with linked exception:
1
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:213)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:190)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:241)
	at org.jboss.resource.deployers.ManagedConnectionFactoryParserDeployer.parse(ManagedConnectionFactoryParserDeployer.java:121)
	at org.jboss.resource.deployers.ManagedConnectionFactoryParserDeployer.parse(ManagedConnectionFactoryParserDeployer.java:59)
	at org.jboss.deployers.vfs.spi.deployer.AbstractVFSParsingDeployer.parse(AbstractVFSParsingDeployer.java:112)
	at org.jboss.deployers.spi.deployer.helpers.AbstractParsingDeployerWithOutput.createMetaData(AbstractParsingDeployerWithOutput.java:225)
	... 38 more
Caused by: java.net.UnknownHostException: www.jboss.org
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:175)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:384)
	at java.net.Socket.connect(Socket.java:546)
	at java.net.Socket.connect(Socket.java:495)
	at sun.net.NetworkClient.doConnect(NetworkClient.java:178)
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:409)
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:530)
	at sun.net.www.http.HttpClient.<init>(HttpClient.java:240)
	at sun.net.www.http.HttpClient.New(HttpClient.java:321)
	at sun.net.www.http.HttpClient.New(HttpClient.java:338)
	at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:935)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:876)
	at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:801)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1139)
	at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
	at org.apache.xerces.impl.XMLEntityManager.startEntity(Unknown Source)
	at org.apache.xerces.impl.XMLEntityManager.startDTDEntity(Unknown Source)
	at org.apache.xerces.impl.XMLDTDScannerImpl.setInputSource(Unknown Source)
	at org.apache.xerces.impl.XMLDocumentScannerImpl$DTDDispatcher.dispatch(Unknown Source)
	at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
	at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
	at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
	at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:211)
	... 44 more
FAILED CONFIGURATION: @BeforeSuite startSeam
org.jboss.deployers.client.spi.IncompleteDeploymentException: Summary of incomplete deployments (SEE PREVIOUS ERRORS FOR DETAILS):

*** CONTEXTS MISSING DEPENDENCIES: Name -> Dependency{Required State:Actual State}

persistence.units:unitName=seam423ear
 -> <UNKNOWN>{Described:** UNRESOLVED Demands 'jboss.jca:name=seam423earDatasource,service=DataSourceBinding **}

*** CONTEXTS IN ERROR: Name -> Error

vfsfile:/home/luca/Software/eclipse_indigo_32bit/workspace/seam423ear-test/bin/ -> java.net.UnknownHostException: www.jboss.org

<UNKNOWN> -> ** UNRESOLVED Demands 'jboss.jca:name=seam423earDatasource,service=DataSourceBinding **

	at org.jboss.deployers.plugins.deployers.DeployersImpl.checkComplete(DeployersImpl.java:576)
	at org.jboss.deployers.plugins.main.MainDeployerImpl.checkComplete(MainDeployerImpl.java:559)
	at org.jboss.embedded.DeploymentGroup.process(DeploymentGroup.java:128)
	at org.jboss.embedded.Bootstrap.deployResourceBases(Bootstrap.java:289)
	at org.jboss.seam.mock.EmbeddedBootstrap.startAndDeployResources(EmbeddedBootstrap.java:15)
	at org.jboss.seam.mock.AbstractSeamTest.startJbossEmbeddedIfNecessary(AbstractSeamTest.java:1034)
	at org.jboss.seam.mock.AbstractSeamTest.startSeam(AbstractSeamTest.java:925)
	at org.jboss.seam.mock.SeamTest.startSeam(SeamTest.java:69)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:616)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
	at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:543)
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:212)
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:277)
	at org.testng.SuiteRunner.run(SuiteRunner.java:240)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:87)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1142)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1067)
	at org.testng.TestNG.run(TestNG.java:979)
	at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:109)
	at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:202)
	at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:173)

SKIPPED CONFIGURATION: @BeforeClass setupClass
SKIPPED CONFIGURATION: @BeforeMethod begin
SKIPPED CONFIGURATION: @AfterMethod end
SKIPPED CONFIGURATION: @AfterClass cleanupClass
SKIPPED: someTest

===============================================
    Default test
    Tests run: 1, Failures: 0, Skips: 1
    Configuration Failures: 1, Skips: 4
===============================================

===============================================
Default suite
Total tests run: 1, Failures: 0, Skips: 1
Configuration Failures: 1, Skips: 5
===============================================

[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@13c468a: 4 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter@1807ca8: 5 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@12ad19e: 17 ms
[TestNG] Time taken by [TestListenerAdapter] Passed:0 Failed:0 Skipped:0]: 4 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1bd7848: 8 ms

It happens because TestNG tries to validate the *-ds.xml files against their DTDs.

To solve this issue, you have to remove or comment out the DTD declaration from the *-ds.xml files in your project, including the ones in the /bin folder. You can see the /bin folder Eclipse’s Navigator view.

 

TestNG does not work with JDK 6. TestNG works only with JDK 5. So, if you have JDK 6 installed on your system, you need to apply a little shrewdness.

I will assume that you already have JBoss Tools and the TestNG Eclipse plugin installed. If you need a tutorial on that, let me know and I’ll write one. I will also assume you are deploying in JBoss AS 5.

Here’s how to create a TestNG-ready Seam 2 project in Eclipse that works with JDK6:

  1. Create a new Seam 2 Project in Eclipse with the JBoss Tools wizard.
  2. If you project is gonna have EJBs, make sure you choose “EAR” as deployment at the end of the Wizard (but choose WAR at the Maven page).
  3. If you create a mavenized project, look for the warning “Classpath entry org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER will not be exported or published. Runtime ClassNotFoundExceptions may result.”; rich-click on it, Quick Fix, Finish.
  4. Now you have the Seam 2 project and a Seam 2 test project
  5. In the test project, create a simple test class. For example:
  6. package test;
    
    import org.jboss.seam.mock.SeamTest;
    import org.testng.annotations.Test;
    
    public class Tests extends SeamTest {
    
    	@Test
    	public void myFirstTest() {
    		assert true;
    	}
    }
    
  7. Right-click on the test class and select Run As –> TestNG Test
  8. If you have JDK 6, the test will fail with a daunting stack trace, and it’s ok. It fails because TestNG does not work with JDK 6, but only with JDK 5. But now, eclipse created a run configuration for us that we can fix.
  9. Now right-click again on the test class and select Run As –> Run Configurations
  10. In “Run configurations” window, scroll down and find TesNG –> NameOfYourTestClass
  11. Select the “(x)=Arguments” tab
  12. In the “VM Arguments” field past the following: -Dsun.lang.ClassLoader.allowArraySyntax=true
  13. Click “Apply” then “Close”
  14. Right-click again on your test class and select Run As –> TestNG Test. Now the test will run.
  15. Repeat steps 6 to 12 for every test class you create. Make sure you remember to do so!
  16. Happy testing!
 
 

Activate HTTPS on JBoss AS 7

On January 14, 2012, in HTTPS, JBoss, JBoss AS 7, by lucasterdev

Open a terminal and type the following command:

keytool -genkey -keystore filename.keystore -storepass mypassword -keypass mypassword -keyalg RSA -validity 180 -alias somealias -dname "cn=Name Surname,o=MyCompany,c=US"

(change the command parameters properly ;) )

The command will create a self-signed certificate, stored in the .keystore file.

Copy the .keystore file to JBOSS_AS_7_HOME/standalone/configuration

Open JBOSS_AS_7_HOME/standalone/configuration/standalone.xml

Look for the following element:

<subsystem xmlns="urn:jboss:domain:web:1.0" default-virtual-server="default-host">
    <connector name="http" protocol="HTTP/1.1" socket-binding="http" scheme="http"/>
    <virtual-server name="default-host" enable-welcome-root="true">
        <alias name="localhost"/>
        <alias name="example.com"/>
    </virtual-server>
</subsystem>

Change it to make it look like this:

<subsystem xmlns="urn:jboss:domain:web:1.0" default-virtual-server="default-host">
	<connector name="http" protocol="HTTP/1.1" socket-binding="http" scheme="http"/>
	<connector name="https" protocol="HTTP/1.1" socket-binding="https" scheme="https" secure="true">
		<ssl key-alias="somealias" password="mypassword" certificate-key-file="../standalone/configuration/filename.keystore" cipher-suite="ALL" protocol="TLS"/>
	</connector>
	<virtual-server name="default-host" enable-welcome-root="true">
		<alias name="localhost"/>
		<alias name="example.com"/>
	</virtual-server>
</subsystem>

Restart JBoss AS 7.

Notice the following lines in the console output/log:

17:45:21,689 INFO  [org.apache.coyote.http11.Http11Protocol] (MSC service thread 1-4) Starting Coyote HTTP/1.1 on http--127.0.0.1-8080
17:45:22,138 INFO  [org.apache.coyote.http11.Http11Protocol] (MSC service thread 1-3) Starting Coyote HTTP/1.1 on http--127.0.0.1-8443

HTTPS will be running on port 8443 by default.

To change the HTTPS port, look for the socket-binding-group element in standalone.xml

 

Workspace management with CDI

On January 9, 2012, in CDI, Java EE 6, Weld, by lucasterdev

Intro

One of of  Seam 2′s coolest features was the workspace management feature. (this must me the billionth times someone says that ;-) )

With the advent of Java EE 6 & and CDI, one would expect that the implementation of such a cool feature would be top priority to the Seam 3 tem, but  – hey! – It’s JBoss we are talking about! So no, there is no conversation/workspace management in Seam 3 :-/

Andy Gibson’s solution

Andy Gibson implemented a basic workspace manager; I tested it out with JBoss AS 7.0.2.Final and it worked. Here are the pros and cons of Andy’s solution:

Pros:

  • It uses the standard CDI specification API.
  • It’s portable across different Java EE 6 application servers.
  • It’s extensible in that you can, for example, associate descriptions (i.e. use case names) to conversations.

Cons:

  • You have to clutter your CDI bean’s code with workspace management code – which is poor separation of concerns.

Here comes Weld

Weld (JBoss’ implementation of CDI) offers the possibility to implement workspace management in a different, more elegant way. Weld introduces the notion of a ManagedConversation, which extends the Conversation interface with the abilty to lock, unlock and touch (update the last used timestamp) a conversation; it also adds a method to get the timestamp of the moment when conversation was last used. Finally, all non-transient conversations in a session can be obtained from the ConversationContext, as can the current conversation.

My workspace management solution is build upon Weld’s perks. Here are its pros and cons:

Pros:

  • You don’t have to add workspace management code to your CDI bean.
  • You don’t even have to inject anything into yout CDI beans.
  • It allows for separation of concerns.

Cons:

  • It’s depends on Weld.
  • It only works with JBoss AS 6/7.
  • It’s not portable across different CDI implementations (i.e. won’t work on Glassfish, WebSphere, etc…).

My solution’s source code

package cdi;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

import org.jboss.solder.logging.Logger;
import org.jboss.weld.context.ConversationContext;
import org.jboss.weld.context.ManagedConversation;
import org.jboss.weld.context.http.Http;

import util.ManagedConversationComparator;

/**
 * This bean needs <strong>Weld</strong>.
 *
 * @author Luca
 *
 */
@Named
@RequestScoped
public class WorkspaceBean implements Serializable {

	private static final long serialVersionUID = -457959303651081423L;

	@Inject
	@Http
	private ConversationContext conversationContext;

	@Inject
	private Logger logger;

	/**
	 * Tells whether a ManagedConversation has timed out.
	 *
	 * @param conv
	 * @return <i>true</i> if it has timed out; <i>false</i> if it has not timed
	 *         out yet
	 */
	public static boolean timedOut(ManagedConversation conv) {
		return conv.getTimeout() < (new Date().getTime() - conv.getLastUsed());
	}

	/**
	 * Get the list of active (long running OR once long-running, then timed-out
	 * but still active) conversation Id's.
	 *
	 * @return a List<String> of conversation ids
	 */
	public List<String> getActiveConversationIds() {
		List<String> result = new ArrayList<String>();
		for (Iterator<ManagedConversation> i = getActiveConversations()
				.iterator(); i.hasNext();) {
			result.add(i.next().getId());
		}
		return result;
	}

	/**
	 * Get a list of the active ManagedConversation. To be in the list, a
	 * conversations must satisfy one of these two requirements:
	 * <ul>
	 * <li>It's long running and has not timed out yet;</li>
	 * <li>It was long running and has timed out.</li>
	 * </ul>
	 * The list does NOT contain transient conversations.
	 *
	 * @return a Collection of org.jboss.weld.context.ManagedConversation,
	 *         sorted by conversation id.
	 */
	public Collection<ManagedConversation> getActiveConversations() {
		List<ManagedConversation> result = new ArrayList<ManagedConversation>(
				conversationContext.getConversations());

		// Weld's documentation reads:
		// "conversations are not assigned ids until they become non-transient."
		// Actually, that's not the case! ConversationContext.getConversations()
		// lacks the current conversation even though it's already long running!
		//
		// We workaround by adding the current conversation, if it's long
		// running.
		ManagedConversation currentConversation = conversationContext
				.getCurrentConversation();
		if (!currentConversation.isTransient()) {
			if (!result.contains(currentConversation))
				result.add(currentConversation);
		}
		// Sort the conversations by conversation id in ascending order
		Collections.sort(result, new ManagedConversationComparator());
		return result;
	}

	/**
	 * Get the list of active, long running, not yet timed-out conversation
	 * Id's.
	 *
	 * @return
	 */
	public List<String> getLongRunningConversationIds() {
		List<String> result = new ArrayList<String>();
		for (Iterator<ManagedConversation> i = getLongRunningConversations()
				.iterator(); i.hasNext();) {
			result.add(i.next().getId());
		}
		return result;
	}

	/**
	 * Get all AND ONLY the <strong>long running</strong> active conversations
	 * that haven't timed out yet.
	 *
	 * @return a Collection of long running
	 *         org.jboss.weld.context.ManagedConversation, sorted by
	 *         conversation id.
	 */
	public Collection<ManagedConversation> getLongRunningConversations() {
		Collection<ManagedConversation> result = new ArrayList<ManagedConversation>();
		ManagedConversation conv;
		// Get all the active conversations
		Collection<ManagedConversation> activeConversations = getActiveConversations();
		for (Iterator<ManagedConversation> i = activeConversations.iterator(); i
				.hasNext();) {
			conv = i.next();
			// If the conversation is STILL long running, add it to the result
			if (!timedOut(conv)) {
				result.add(conv);
			}
		}
		return result;
	}

	/**
	 * Logs info about the workspace
	 */
	private void output() {
		logger.info("Current Conversation: "
				+ conversationContext.getCurrentConversation());
		logger.info("Long Running Conversations: ");
		Iterator<ManagedConversation> i = getLongRunningConversations()
				.iterator();
		while (i.hasNext()) {
			logger.info(i.next());
		}
		logger.info("Active Conversations: ");
		i = getActiveConversations().iterator();
		while (i.hasNext()) {
			logger.info(i.next());
		}
	}

	/*
	 * Life cycle methods
	 */

	@PostConstruct
	public void postConstruct() {
		logger.info("postConstruct()");
		output();
	}

	@PreDestroy
	public void preDestroy() {
		logger.info("preDestroy()");
		output();
	}
}

Here’s an .xhtml snippet that displays the workspace:

<h1>Long Running Conversations</h1>
<ui:repeat var="_conv" value="#{workspaceBean.longRunningConversations}">
	<h:link outcome="wizard2" value="Goto Conversation #{_conv.id}">
		<f:param name="cid" value="#{_conv.id}" />
	</h:link>
	<br/>
</ui:repeat>

<h1>Active</h1>
<ui:repeat var="_conv" value="#{workspaceBean.activeConversations}">
	<h:link outcome="wizard2" value="Goto Conversation #{_conv.id}">
		<h:outputText value=" (timedout)" rendered="#{workspaceBean.timedOut(_conv)}"/>
		<f:param name="cid" value="#{_conv.id}" />
	</h:link>
	<br />
</ui:repeat>

Some remarks

  • Weld’s ManagedConversation and ConversationContext are cool; however, they are not part of the CDI specification; I’d prefer them to be part of some CDI extension – Seam Solder, for instance – and not of Weld itself.
  • It would be useful if the ManagedConversation had methods to set and get the conversation description (i.e. use case name), because it’s needed by 90% of Web apps.
  • A boolean ManagedConversation.isTimedOut() method would be very useful too (we would not need to implement a Comparator)
  • It would also be very useful to be able to observe/intercept Conversation.begin(), Conversation.timeout(), Conversation.end()