Help

My wife has delivered our daughter and JBoss has delivered a snapshot of the AS 6 that can do most of the stuff we set out to do, so let's move on!

The good, the bad and our daily workarounds

So, since we're living on the edge here, head over to JBoss Hudson and grab the latest successful build (#1750 or later). Install the envers.jar in the server and change the http listener port like we did in the end of part II. Remember to update your JBOSS_HOME environment variable if you use one.

There is a slight regression with the auto-registration of the faces servlet so add this to your web.xml

<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>/faces/*</url-pattern>
</servlet-mapping>

The ZipException is gone so clear out your faces-config.xml from the merged ICEfaces stuff and delete the icefaces directory from your local repository so you can pick up fresh copies of the original jars.

There is also another regression that has something to do with redirects and the ICEfaces PushRenderer (perhaps). If you go straight to the /Greetings context root, the PushRenderer is not that pushy, you'll have to use the full /Greetings/faces/greetings.xhtml for now.

Look mama, no EARs

We're going EJB and let's do some refactorings while we're at it. Remove the GreetingBean and create the following classes

package com.acme.greetings;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;

import javax.annotation.PostConstruct;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Stateful;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.inject.Named;

import org.icefaces.application.PushRenderer;

@Stateful
@ApplicationScoped
@Named
public class GreetingServer implements Serializable
{
   private static final long serialVersionUID = 1L;

   List<Greeting> greetings = new ArrayList<Greeting>();
   
   @Inject
   @Added
   Event<Greeting> greetingAddedEvent;

   @Inject
   GreetingArchiver greetingArchiver;
   
   @Inject
   GreetingEcho greetingEcho;
   
   @PostConstruct
   public void init()
   {
      greetings = greetingArchiver.loadGreetings();
   }

   @Lock(LockType.WRITE)
   public void addGreeting(Greeting greeting)
   {
      greetings.add(greeting);
      PushRenderer.render("greetings");
      greetingAddedEvent.fire(greeting);
      Future<Boolean> result = greetingEcho.echo(greeting);
   }

   @Lock(LockType.READ)
   public List<Greeting> getGreetings()
   {
      return greetings;
   }
}

and

package com.acme.greetings;

import javax.annotation.PostConstruct;
import javax.ejb.Stateful;
import javax.enterprise.inject.Model;
import javax.inject.Inject;

import org.icefaces.application.PushRenderer;

import com.icesoft.faces.context.effects.Appear;
import com.icesoft.faces.context.effects.Effect;

@Stateful
@Model
public class GreetingClient
{
   Greeting greeting = new Greeting();

   @Inject
   GreetingServer greetingServer;

   @PostConstruct
   public void init()
   {
      PushRenderer.addCurrentSession("greetings");
   }
   
   public Effect getAppear()
   {
      return new Appear();
   }

   public Greeting getGreeting()
   {
      return greeting;
   }

   public void setGreeting(Greeting greeting)
   {
      this.greeting = greeting;
   }

   public void addGreeting()
   {
      greetingServer.addGreeting(greeting);
   }
}

The GreetingServer keeps the greetings and the client has injected the server and interacts with it (we've thrown in some annotations for concurrency control to the greeting list). You might notice we also have a new injection

@Inject
GreetingEcho greetingEcho;

which is called like

Future<Boolean> result = greetingEcho.echo(greeting);

This is an asynchronous call to GreetingEcho that looks like

package com.acme.greetings;

import java.util.concurrent.Future;

import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.Stateless;

@Stateless
public class GreetingEcho
{

   @Asynchronous
   public Future<Boolean> echo(Greeting greeting)
   {
      System.out.println(String.format("Got a new greeting: %s", greeting.getText()));
      return new AsyncResult<Boolean>(true);
   }
}

This is kind of funny EE 6 construct since it really exits the @Asynchronous method immedeately, returning a handle to the task. Well, good luck trying to cancel that output before it finished. This is kind of JMS-light. And yes, it's obviously used just for show-off here.

You'll also notice that our DB bean has gotten a new look

package com.acme.greetings;

import java.util.Date;
import java.util.List;

import javax.ejb.Stateless;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Root;

@Stateless
public class GreetingArchiver
{
   @Inject
   @GreetingDB
   EntityManager db;

   CriteriaQuery<Greeting> loadQuery;
   ParameterExpression<Date> timestampParam;

   @Inject
   public void initQuery(@GreetingDB EntityManagerFactory emf)
   {
      CriteriaBuilder cb = emf.getCriteriaBuilder();
      timestampParam = cb.parameter(Date.class);
      loadQuery = cb.createQuery(Greeting.class);
      Root<Greeting> greeting = loadQuery.from(Greeting.class);
      loadQuery.select(greeting);
      loadQuery.where(cb.greaterThan(greeting.get(Greeting_.created), timestampParam));
   }

   public void saveGreeting(@Observes @Added Greeting greeting)
   {
      db.persist(greeting);
   }

   public List<Greeting> loadGreetings()
   {
      Date tenMinutesAgo = new Date();
      tenMinutesAgo.setTime(tenMinutesAgo.getTime() - 10 * 60 * 1000);
      return db.createQuery(loadQuery).setParameter(timestampParam, tenMinutesAgo).getResultList();
   }
}

The persistence has been much simplified thanks to CMT.

And finally the view to use them

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:ui="http://java.sun.com/jsf/facelets">
	<h:head>
		<title>
			Greetings
		</title>
	</h:head>

	<h:body>
		<h:form>
			<ice:inputText id="feedback" value="#{greetingClient.greeting.text}" effect="#{greetingClient.appear}"/>
			<h:message for="feedback" />
			<h:commandButton value="Add" action="#{greetingClient.addGreeting}" />
			<h:dataTable value="#{greetingServer.greetings}" var="greeting">
				<h:column>
					<h:outputText value="#{greeting.text}"/>
				</h:column>
			</h:dataTable>
		</h:form>
	</h:body>
</html>

JMS and JavaMail

Speaking of JMS, let's add a MDB

package com.acme.greetings;

import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/GreetingTopic"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic") })
public class GreetingMailer implements MessageListener
{
   @Resource(mappedName = "java:/Mail")
   Session mailSession;

   @Override
   public void onMessage(Message message)
   {
      TextMessage textMessage = (TextMessage) message;
      try
      {
         mail(textMessage.getText());
      }
      catch (Exception e)
      {
         // Forgive me, for I have sinned
         System.out.println(String.format("No mailing: %s", e.getMessage()));
      }
   }

   private void mail(String greeting) throws MessagingException
   {
      MimeMessage message = new MimeMessage(mailSession);
      message.setFrom(new InternetAddress("greetingmaster@nowhere.org"));
      message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress("you@yourplace.com"));
      message.setSubject("New greeting has arrived!");
      message.setText(greeting);
      Transport.send(message);
   }
}

This is a message driven bean that listens to the topic /topic/GreetingTopic and when a message is recieved, it grabs the default Mail session from the application server and send off a notification, configure it in the mail-service.xml in the deploy directory. You should also add the topic to the deploy/hornetq/hornetq-jms.xml like

<topic name="GreetingTopic">
   <entry name="/topic/GreetingTopic"/>
</topic>

There are probably better ways of deploying topics but I'm not writing a JBoss AS tutorial here. This MDB isn't going to see any action unless someone actually send it messages. Let's add a

package com.acme.greetings;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.enterprise.event.Observes;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

@Stateless
public class JMSDispatcher
{
   @Resource(mappedName = "/ConnectionFactory")
   ConnectionFactory connectionFactory;

   @Resource(mappedName = "/topic/GreetingTopic")
   Topic topic;

   public void broadcast(@Observes @Added Greeting greeting) throws JMSException
   {
      Session session = null;
      MessageProducer producer = null;
      Connection connection = null;
      try
      {
         connection = connectionFactory.createConnection();
         session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
         producer = session.createProducer(topic);
         TextMessage message = session.createTextMessage(greeting.getText());
         producer.send(message);
      }
      finally
      {
         if (producer != null)
         {
            producer.close();
         }
         if (session != null)
         {
            session.close();
         }
         if (connection != null)
         {
            connection.close();
         }

      }
   }
}

This bean observers the same added greeting as the GreetingArchiver and sends the greeting of to our topic. There are probably better ways of writing this but I'm not writing a JMS tutorial (either). Hmm, I forget what kind of tutorial I'm actually writing.

Something for the future

This snapshot doesn't have everyting yet, I'd like to have @Scheduled greetings so we don't get lonely. This doesn't actually work yet, but let's add it and keep upgrading our snapshots so perhaps one day we'll get lucky.

package com.acme.greetings;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.inject.Inject;

@Singleton
public class ArbiBean
{
   static final List<String> comments = new ArrayList<String>()
   {
      private static final long serialVersionUID = 1L;
      {
         add("Tried the new JRebel? I heard it can read your thoughts?");
         add("Where can I find the specs?");
         add("Shouldn't you be using RichFaces 4 instead?");
         add("How is the Seam 3 performance compared to Seam 2?");
         add("PIGBOMB!");
      }
   };

   @Inject
   GreetingServer greetingServer;

   @Schedule(second = "*/15")
   public void comment()
   {
      greetingServer.addGreeting(new Greeting(getRandomComment()));
   }

   private String getRandomComment()
   {
      return comments.get(new Random(comments.size()).nextInt());
   }
}

This one should start up and send comments to the server every 15 seconds. But like I said, not yet.

Conclusion

This ends part IV. In part V we'll add JAX-RS and JAX-WS to share our greetings with the world. If you haven't noticed it by now, developing against snapshots and alpha-releases require a fair amount of workarounds. But as a developer you can choose - do you want to sit around and wait for the final product or do you want to join the round and get first-hand knowledge on things to come (filing JIRAs as you encounter issues).

11 comments:
 
22. Jun 2010, 13:36 CET | Link

Hahahaha I loved the name ArbiBean and that it keeps spamming comments every 15 minutes. No pun intented of course Arbi. You know I love you! :-)

ReplyQuote
 
22. Jun 2010, 16:43 CET | Link
Shervin Asgari wrote on Jun 22, 2010 07:36:
Hahahaha I loved the name ArbiBean and that it keeps spamming comments every 15 minutes. No pun intented of course Arbi. You know I love you! :-)

Actually the truth is worse than that, there was a typo in the article, the code says every 15 seconds ;-)

 
23. Jun 2010, 10:16 CET | Link

Hi Nicklas, I'm having difficulties to understand the use o @Model together with @Stateful. If I understood @Model is request scoped, but @Stateful is meant to last a little more, isn't? It would be nice some guidance about the use of annotations from javax.ejb and cdi together, like when to use which combinations.

Thank you very much.

 
23. Jun 2010, 11:41 CET | Link
junico wrote on Jun 23, 2010 04:16:
but @Stateful is meant to last a little more, isn't?

Says who? ;-) A stateless EJB is just that - a bean with state unique to the caller (which means it can't be pooled or re-used like the stateless ones). A session can last a second or a request can last a minute, your choice of scope should be dictated by your requirements. Start with a narrow scope (request), if your application develops amnesia (your state doesn't last long enough) move up the scope to conversation or session. If your app has too long memory (cluttering), narrow stuff down to conversation or request.

 
23. Jun 2010, 16:11 CET | Link
request or session

I'm sorry for my dumb questions, but I can't remember the last time I used a Stateful EJB, Stateless all the way :-). It is difficult because I always associate Stateful to Session and Stateless to Request.

So in the case of:

@Stateful @Model

GreetingClient will live only in the request or stay in the session?

thanks

 
23. Jun 2010, 16:24 CET | Link
request or session wrote on Jun 23, 2010 10:11:
I'm sorry for my dumb questions, but I can't remember the last time I used a Stateful EJB, Stateless all the way :-). It is difficult because I always associate Stateful to Session and Stateless to Request. So in the case of: @Stateful @Model GreetingClient will live only in the request or stay in the session? thanks

@Model is a stereotype which expands to @Named @RequestScoped so we end up with

@Stateful
@Named
@RequestScoped

of which only @RequestScoped tell scope.

Like I said, @Stateful has nothing to do with scope. I think the misconception of session comes from the fact that both stateful and stateless EJBs are (still?) called session EJBs even if that does not indicate scope.

 
30. Aug 2014, 03:45 CET | Link
polo

Walking on the way home, Nike Air Jordan, suddenly a scenery touched, Ralph Outlet, stopped to savor, MCM Outlet Online, to put a camera gesture, Polo Outlet Online, to leave a shallow spring, Gucci Shoes UK, of negatives here, Michael Kors Outlet, deep in her heart extended spring scenery, Marc Jacobs Bags Outlet, etc, returned home, Canada Goose Jackets, using bamboo memo box, Ralph Lauren Outlet, to do with pen, Michael Kors USA, and ink painting, North Jackets Outlet Online, the intention to write, a sweet words, Beats By Dre, do a recall album, wait until old age, Coach Bags Black Friday, come to appreciate slowly, North Clearace Outlet Online, walked with light, Burberry Bags Outlet, footsteps walked on, the King, Monster Headphones Outlet, or the original scene, Longchamp Pairs, people are still the original person, Prada Outlet Online, just change a mood, Michael Kors Outlet Online, all plain people, Cheap Oakley Sunglaases, things, Coach Factory Shop, and it was better together.

 
08. Sep 2014, 07:37 CET | Link
Koman

Before going to bed, rub your eyebrows with Vaseline. By putting Vaseline on your eyes before you go to bed, they will become shinier and better looking. Try not to get vaseline on the surrounding skin, as it can clog pores and cause acne breakouts. penis advantage review

 
08. Sep 2014, 11:01 CET | Link
Jaman

If you're fond of wearing your hair back in a ponytail, be sure not to tie your hair back in the same place on your head each time. Even fabric-covered, soft scrunchies might result in repeated stress and may result in breakage. Even if you have to wear your hair up at work, let it down whenever possible to give it a break from the constant stress. revitol hair removal cream

 
08. Sep 2014, 11:37 CET | Link
muscle

Are you trying to add muscle mass to your body? If you are eating calorie-dense foods and are performing muscle build workouts but are still not seeing the results that you desire, you might want to consider adding creatine supplements to boost the growth of your somanabolic muscle maximizer. Creatine aids in building muscle mass. Not only is this supplement popular with many professional bodybuilders, it is also popular with many elite athletes in other sports.

 
18. Sep 2014, 13:03 CET | Link
Hasan

Use online resources to study at home. Popular study aids include Quizlet and Memrise. You can use these websites to create flashcards for your class. Often, someone else has already made flashcards for your class or subject of study. In this case, you can use what is already available to study.

Do not get involved with the tao of badass pdf people that want to party all the time. Having fun during college is important, but there is a time and a place. If you allow yourself to fall into those bad habits, your grades will surely suffer. Only have fun when you have done everything you need to do..

Post Comment