Using portlet events in JSF 2

Update the JSF 2 order portlet from the first recipe to send an event when an order is saved, and create a new portlet to display a list of active orders.

Getting ready

The following are required for this recipe:

  • Apache Maven
  • An IDE of your choice
  • GateIn-3.2.0.Final-jbossas7-preview
  • Order-JSF project from Creating a JSF 2 portlet

How to do it...

To modify the existing order portlet to fire an event:

  1. Inside the project's pom.xml, add the following dependency:
      <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <scope>provided</scope>
        <version>2.1</version>
      </dependency>
  2. Create a class named OrderEvent within a package named gatein.cookbook.chapter10 with the following content:
    @XmlRootElement
    public class OrderEvent implements Serializable {
    
      private Order order;
    
      public static final QName QNAME = new QName("urn:chapter10:jsf:order:event", "OrderEvent");
    
      public OrderEvent(Order order) {
        this.order = order;
      }
    
      public Order getOrder() {
        return order;
      }
    
    }
  3. Modify the create method of Order by adding the following code before return "orderSuccess":
      Object response = FacesContext.getCurrentInstance().getExternalContext().getResponse();
      if (response instanceof StateAwareResponse) {
        StateAwareResponse stateResponse = (StateAwareResponse) response;
        stateResponse.setEvent(OrderEvent.QNAME, new OrderEvent(this));
      }
  4. Add the following into portlet.xml just before </portlet>:
      <supported-publishing-event>
        <qname xmlns:jsf="urn:chapter10:jsf:order:event">jsf:OrderEvent</qname>
      </supported-publishing-event>
  5. Add the following into portlet.xml just before </portlet-app>:
      <event-definition>
        <qname xmlns:jsf="urn:chapter10:jsf:order:event">jsf:OrderEvent</qname>
        <value-type>gatein.cookbook.chapter10.OrderEvent</value-type>
      </event-definition>

To create a new portlet listing the active orders:

  1. Create a class named OrderManagerEvent within a package named gatein.cookbook.chapter10 with the following content:
    @ManagedBean
    @ApplicationScoped
    public class OrderManagerEvent implements Serializable {
    
      private static final long serialVersionUID = -5776345927432051634L;
    
      Set<Order> orders = new HashSet<Order>();
    
      public void addOrder(Order order) {
        orders.add(order);
      }
    
      public Set<Order> getOrders() {
        return orders;
      }
    
      public void setOrders(Set<Order> orders) {
        this.orders = orders;
      }
    }
  2. Create a class named OrderEventHandler within a package named gatein.cookbook.chapter10 with the following content:
    public class OrderEventHandler implements BridgeEventHandler {
    
      public EventNavigationResult handleEvent(FacesContext context, Event event) {
        ELResolver facesResolver = context.getELContext().getELResolver();
        OrderManagerEvent mgrBean = (OrderManagerEvent) facesResolver.getValue(context.getELContext(), null, "orderManagerEvent");
        mgrBean.addOrder(((OrderEvent)event.getValue()).getOrder());
        return new EventNavigationResult("/", "/orderList.xhtml");
      }
    }
  3. Create a class named OrderList within a package named gatein.cookbook.chapter10 with the following content:
    @ManagedBean
    @RequestScoped
    public class OrderList {
    
      @ManagedProperty(value = "#{orderManagerEvent}")
      private OrderManagerEvent orderManager;
    
      public void setOrderManager(OrderManagerEvent orderManager) {
        this.orderManager = orderManager;
      }
    
      public List<Order> getActiveOrders() {
        List<Order> active = new ArrayList<Order>();
        for (Order order : orderManager.getOrders()) {
          if (order.getStatus().equals(Status.WAITING)) {
            active.add(order);
          }
        }
        return active;
      }
    }
  4. Create orderList.xhtml in the src/main/webapp folder of the project.
  5. Add the following content into orderList.xhtml:
    <f:view xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    
    <h:body>
      <ui:composition template="/templates/layout.xhtml">
        <ui:define name="header">
          <h3>Active Orders</h3>
        </ui:define>
    
        <ui:define name="content">
          <h:outputText value="There are currently no active orders" rendered="#{empty orderList.activeOrders}" />
    
          <h:dataTable value="#{orderList.activeOrders}" var="ord" rendered="#{not empty orderList.activeOrders}" border="1" style="text-align:center">
    
            <h:column>
              <f:facet name="header">Order Type</f:facet>
              #{ord.type}
            </h:column>
            <h:column>
              <f:facet name="header">Trade Instruction</f:facet>
              #{ord.tradeInstruction}
            </h:column>
            <h:column>
              <f:facet name="header">Account Number</f:facet>
              #{ord.accountNumber}
            </h:column>
            <h:column>
              <f:facet name="header">Number of Stocks</f:facet>
              #{ord.numberStocks}
            </h:column>
            <h:column>
              <f:facet name="header">Date Entered</f:facet>
              <h:outputText value="#{ord.entryDate}">
                <f:convertDateTime pattern="hh:mm:ssa d-M-yyyy" />
              </h:outputText>
            </h:column>
            <h:column>
              <f:facet name="header">Status</f:facet>
              #{ord.status}
            </h:column>
          </h:dataTable>
        </ui:define>
      </ui:composition>
    </h:body>
    </f:view>
  6. Add the following into portlet.xml just before </portlet-app>:
      <portlet>
        <portlet-name>OrderList-JSF</portlet-name>
        <portlet-class>javax.portlet.faces.GenericFacesPortlet</portlet-class>
        <init-param>
          <name>javax.portlet.faces.defaultViewId.view</name>
          <value>/orderList.xhtml</value>
        </init-param>
        <init-param>
          <name>javax.portlet.faces.bridgeEventHandler</name>
          <value>gatein.cookbook.chapter10.OrderEventHandler</value>
        </init-param>
        <supports>
          <mime-type>text/html</mime-type>
          <portlet-mode>VIEW</portlet-mode>
        </supports>
        <portlet-info>
          <title>Order List JSF Portlet</title>
        </portlet-info>
        <supported-processing-event>
          <qname xmlns:jsf="urn:chapter10:jsf:order:event">jsf:OrderEvent</qname>
        </supported-processing-event>
      </portlet>
  7. Add the following into web.xml:
      <context-param>
        <param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name>
        <param-value>true</param-value>
      </context-param>
  8. Run the following command in the root of the project directory to build the web archive:
    >mvn clean package
    
  9. Copy the generated web archive, chapter10-jsf-1.0.0.SNAPSHOT.war, from the target folder into the deployment folder of where you unpacked the GateIn installation.
  10. Start the server and log in as an administrator.
  11. Click on the top-menu navigation and use the following path: Group | Administration | Application Registry.
  12. Click on Import Applications to make the new portlet available.
  13. Access the portal page created in the Creating a JSF 2 portlet recipe.
  14. Click on Site Editor | Edit Page and add the OrderList-JSF portlet to it below the Order-JSF portlet. The OrderList-JSF portlet can be found under the Chapter10-jsf category.
  15. Click the Finish icon to save the page.
  16. The portlet page should look like the following screenshot:
    How to do it...
  17. Enter some data into the form and click on Create Order, and the portal page will redirect you to the Order Success! page while also loading the order into the Active Orders section of the page.
    How to do it...

How it works...

The following step details relate to modifying the existing order portlet.

Step 2 created an event class that can be passed between the portlets, defining the namespace the event will reside in.

Step 3 modified the create method, called during the process of saving an order, to set the OrderEvent onto the response.

Steps 4 and 5 updated the portlet.xml to include the definition of the OrderEvent and define that as the order portlet

The following step details are for the new order list portlet.

Step 1 creates a new @ApplicationScoped bean to hold the orders that are received from the event.

Step 2 creates an event handler to process the incoming events. It uses the JSF resolver to retrieve the bean created in Step 1 and call addOrder on it passing the event Order.

Step 3 creates a @RequestScoped bean to retrieve the active orders from the @ApplicationScoped bean for the page.

Steps 4 and 5 create the page to display the list of active orders. At its simplest, there are outputText and dataTable components, with differing rendered attributes so that when there are no orders, a piece of text is displayed, but when there are orders, a table is displayed. The <f:facet> is present within <h:column> to define a column heading for display as if the code read <th>.

Step 6 defines the new portlet in portlet.xml and informs the portlet container that it can process the OrderEvent.

Step 7 informs JSF that any use of <f:convertDateTime>, such as in Step 5, should use the timezone of the machine instead of UTC for displaying time.

See also

  • The Creating a JSF 2 portlet recipe
  • The Creating a RichFaces 4 portlet recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.230.81