Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Application Development

357 Articles
article-image-solving-many-many-relationship-dimensional-modeling
Packt
28 Dec 2009
3 min read
Save for later

Solving Many-to-Many Relationship in Dimensional Modeling

Packt
28 Dec 2009
3 min read
Bridge table solution We will use a simplified book sales dimensional model as an example to demonstrate our bridge solution. Our book sales model initially has the SALES_FACT fact table and two dimension tables: BOOK_DIM and DATE_DIM. The granularity of the model is sales amount by date (daily) and by book. Assume the BOOK_DIM table has five rows: BOOK_SK TITLE AUTHOR 1 Programming in Java King, Chan 3 Learning Python Simpson 2 Introduction to BIRT Chan, Gupta, Simpson (Editor) 4 Advanced Java King, Chan 5 Beginning XML King, Chan (Foreword) The DATE_DIM has two rows: DATE_SK DT 1 11-DEC-2009 2 12-DEC-2009 3 13-DEC-2009 And, the SALES_FACT table has ten rows: DATE_SK BOOK_SK SALES_AMT 1 1 1000 1 2 2000 1 3 3000 1 4 4000 2 2 2500 2 3 3500 2 4 4500 2 5 5500 3 3 8000 3 4 8500 Note that:The columns with _sk suffixes in the dimension tables are surrogate keys of the dimension tables; these surrogate keys relate the rows of the fact table to the rows in the dimension tables.King and Chan have collaborated in three books; two as co-authors, while in the “Beginning XML” Chan’s contribution is writing its foreword. Chan also co-authors the “Introduction to BIRT”.Simpson singly writes the “Learning Python” and is an editor for “Introduction to BIRT”. To analyze daily book sales, you simply run a query, joining the dimension tables to the fact table: SELECT dt, title, sales_amt FROM sales_fact s, date_dim d, book_dim bWHERE s.date_sk = d.date_skAND s.book_sk = b.book_sk This query produces the result showing the daily sales amount of every book that has a sale: DT TITLE SALES_AMT 11-DEC-09 Advanced Java 4000 11-DEC-09 Introduction to BIRT 2000 11-DEC-09 Learning Python 3000 11-DEC-09 Programming in Java 1000 12-DEC-09 Advanced Java 4500 12-DEC-09 Beginning XML 5500 12-DEC-09 Introduction to BIRT 2500 12-DEC-09 Learning Python 3500 13-DEC-09 Advanced Java 8500 13-DEC-09 Learning Python 8000 You will notice that the model does not allow you to readily analyze the sales by individual writer—the AUTHOR column is multi-value, not normalized, which violates the dimension modeling rule (we can resolve this by creating a view to “bundle” the AUTHOR_DIM with the SALES_FACT tables such that the AUTHORtable connects to the view as a normal dimension. We will create the view a bit later in this section). We can solve this issue by adding an AUTHOR_DIM and its AUTHOR_GROUP bridge table. The AUTHOR_DIM must contain all individual contributors, which you will have to extract from the books and enter into the table. In our example we have four authors. AUTHOR_SK NAME 1 Chan 2 King 3 Gupta 4 Simpson The weighting_factor column in the AUTHOR_GROUP bridge table contains a fractional numeric value that determines the contribution of an author to a book. Typically the authors have equal contribution to the book they write, but you might want to have different weighting_factor for different roles; for example, an editor and a foreword writer have smaller weighting_factors than that of an author. The total weighting_factors for a book must always equal to 1. The AUTHOR_GROUP bridge table has one surrogate key for every group of authors (a single author is considered a group that has one author only), and as many rows with that surrogate key for every contributor in the group.
Read more
  • 0
  • 0
  • 7787

article-image-seam-conversation-management-using-jboss-seam-components-part-2
Packt
24 Dec 2009
4 min read
Save for later

Seam Conversation Management using JBoss Seam Components: Part 2

Packt
24 Dec 2009
4 min read
The introductory page of the order process The first view in our page flow is an introductory page that simply navigates to the first step in our ordering process. Notice that we use the Seam tag to render a hyperlink that includes the conversation ID as a query string parameter. This is called conversation propagation. Seam conversation propagation using hyperlinks Seam automatically propagates the conversation during JSF form submissions using the HTTP POST method. For any GET requests (for instance, clicking on a hyperlink), we are responsible for including the current conversation ID as a request parameter to ensure that the request is handled properly. Seam provides a hyperlink control rendered by the tag that automatically includes the current conversation ID on the query string. We can also include the conversation ID as a query string parameter by nesting the Seam tag inside the standard JSF tag. Conversation ID propagation is automatic when a JSF form is submitted using POST. The markup for the introductory screen in our order process is as follows: <h1>Product Order Form</h1> <a4j:form> <rich:panel> <f:facet name="header"> <h:outputText value="Welcome to our Store" /> </f:facet> <p>Welcome to our store. Our step-by-step forms will guide you through the ordering process.</p> <s:link view="/order/step1.jsf" value="Place an order" /> </rich:panel> </a4j:form> } The following screenshot shows the introductory screen of our ordering process. Notice in the status bar of the browser window that the URL generated by the Seam JSF hyperlink control contains a query string parameter named cid with a value of one. As long as we pass this parameter from page to page, all the requests will be handled as a part of the same conversation. The conversation ID is automatically  submitted during JSF postback requests. When a new conversation is started, Seam will increment the conversation ID automatically. The customer registration screen (Step 1) The first screen, our page flow, requires the user to provide customer information before placing an order. This view is basically identical to the example used in the Seam validation section of this article. Therefore, much of the JSF markup has been removed for simplification purposes. Notice that the action has been hardcoded in the <a4j:commandButton> tag and corresponds to a navigation rule declaration in faces-config.xml. No additional work is required for the Seam conversation ID to be propagated to the server when the form is submitted; this happens automatically. <h1>Step 1. Customer Registration</h1> <a4j:form id="customerForm" styleClass="customer-form"> ... <a4j:commandButton value="Next Step" action="next" reRender="customerForm" /> ... </a4j:form> The following screenshot shows the customer registration step in the online ordering page flow of our application. The shipping information screen (Step 2) The following screen requires the user to select a product and a shipping destination before clicking on the Next Step button. Once again, Seam conversation propagation happens automatically when the form is submitted. The order details confirmation screen (Step 3) The next screen requires the user to confirm the order details before submitting the order for processing. Once again, the JSF markup has been omitted for brevity. Notice that the command button invokes the submitOrder backing bean method to submit the order. As noted earlier, this method is annotated with the Seam framework @End annotation, indicating that the long-running conversation ends after the method is invoked. When the method returns, Seam demotes the long-running conversation to a temporary conversation and destroys it after the view is rendered. Any references to conversation-scoped beans are released when the Seam conversation is destroyed, efficiently freeing up server resources in a more fine-grained way than by invalidating the session. <h:form> ... <a4j:commandButton action="#{orderBean.submitOrder}" value="Submit Order" /> ... </h:form> The following screenshot shows the order details confirmation screen.
Read more
  • 0
  • 0
  • 1308

article-image-seam-conversation-management-using-jboss-seam-components-part-1
Packt
24 Dec 2009
8 min read
Save for later

Seam Conversation Management using JBoss Seam Components: Part 1

Packt
24 Dec 2009
8 min read
The JBoss Seam framework provides elegant solutions to a number of problems. One of these problems is the concept of conversation management. Traditional web applications have a limited number of scopes (or container-managed memory regions) in which they can store data needed by the application at runtime. In a typical Java web application, these scopes are the application scope, the session scope, and the request scope. JSP-based Java web applications also have a page scope. Application scope is typically used to store stateless components or long-term read-only application data. Session scope provides a convenient, medium-term storage for per-user application state, such as user credentials, application preferences, and the contents of a shopping cart. Request scope is short-term storage for per-request information, such as search keywords, data table sort direction, and so on. Seam introduces another scope for JSF applications: the conversation scope. The conversation scope can be as short-term as the request scope, or as long-term as the session scope. Seam conversations come in two types: temporary conversations and long-running conversations. A temporary Seam conversation typically lasts as  long as a single HTTP request. A long-running Seam conversation typically spans several screens and can be tied to more elaborate use cases and workflows within the application, for example, booking a hotel, renting a car, or placing an order for computer hardware. There are some important implications for Seam's conversation management when using Ajax capabilities of RichFaces and Ajax4jsf. As an Ajax-enabled JSF form may involve many Ajax requests before the form is "submitted" by the user at the end of a  use case, some subtle side effects can impact our application if we are not careful. Let's look at an example of how to use Seam conversations effectively with Ajax. Temporary conversations When a Seam-enabled conversation-scoped JSF backing bean is accessed for the first time, through a value expression or method expression from the JSF page for instance, the Seam framework creates a temporary conversation if a conversation does not already exist and stores the component instance in that scope. If a long-running conversation already exists, and the component invocation requires a long-running conversation, for example by associating the view with a long-running conversation in pages.xml, by annotating the bean class or method with Seam's @Conversational annotation, by annotating a method with Seam's @Begin annotation, or by using the conversationPropagation request parameter, then Seam stores the component instance in the existing long-running conversation. ShippingCalculatorBean.java The following source code demonstrates how to declare a conversation-scoped backing being using Seam annotations. In this example, we declare the ShippingCalculatorBean as a Seam-managed conversation-scoped component named shippingCalculatorBeanSeam. @Scope(ScopeType.CONVERSATION) public class ShippingCalculatorBean implements Serializable { /** * */ private static final long serialVersionUID = 1L; private Country country; private Product product; public Country getCountry() { return country; } public Product getProduct() { return product; } public Double getTotal() { Double total = 0d; if (country != null && product != null) { total = product.getPrice(); if (country.getName().equals("USA")) { total = +5d; } else { total = +10d; } } return total; } public void setCountry(Country country) { this.country = country; } public void setProduct(Product product) { this.product = product; } } faces-config.xml We also declare the same ShippingCalculatorBean class as a request-scoped backing bean named shippingCalculaorBean in faces-config.xml. Keep in mind that the JSF framework manages this instance of the class, so none of the Seam annotations are effective for instances of this managed bean. <managed-bean> <description>Shipping calculator bean.</description> <managed-bean-name>shippingCalculatorBean</managed-bean-name> <managed-bean-class>chapter5.bean.ShippingCalculatorBean </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> pages.xml The pages.xml file is an important Seam configuration file. When a Seam-enabled web application is deployed, the Seam framework looks for and processes a file in the WEB-INF directory named pages.xml. This file contains important information about the pages in the JSF application, and enables us to indicate if a long-running conversation should be started automatically when a view is first accessed. In this example, we declare two pages in pages.xml, one that does not start a long-running conversation, and one that does. <?xml version="1.0" encoding="utf-8"?> <pages xsi_schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.1.xsd"> <page view-id="/conversation01.jsf" /> <page view-id="/conversation02.jsf"> <begin-conversation join="true"/> </page> … </pages> conversation01.jsf Let's look at the source code for our first Seam conversation test page. In this page, we render two forms side-by-side in an HTML panel grid. The first form is bound to the JSF-managed request-scoped ShippingCalculatorBean, and the second form is bound to the Seam-managed conversation-scoped ShippingCalculatorBean. The form allows the user to select a product and a shipping destination, and then calculates the shipping cost when the command button is clicked. When the user tabs through the fields in a form, an Ajax request is sent, submitting the form data and re-rendering the button. The button is in a disabled state until the user has selected a value in both the fields. The Ajax request creates a new HTTP request on the server, so for the first form JSF creates a new request-scoped instance of our ShippingCalculatorBean for every Ajax request. As the view is not configured to use a long-running conversation, Seam creates a new temporary conversation and stores a new instance of our ShippingCalculatorBean class in that scope for each Ajax request. Therefore, the behavior that can be observed when running this page in the browser is that the calculation simply does not work. The value is always zero. This is because the model state is being lost due to the incorrect scoping of our backing beans. <h:panelGrid columns="2" cellpadding="10"> <h:form> <rich:panel> <f:facet name="header"> <h:outputText value="Shipping Calculator (No Conversation)" /> </f:facet> <h:panelGrid columns="1" width="100%"> <h:outputLabel value="Select Product: " for="product" /> <h:selectOneMenu id="product" value="#{shippingCalculatorBean.product}"> <s:selectItems var="product" value="#{productBean.products}" label="#{product.name}" noSelectionLabel="Select" /> <a4j:support event="onchange" reRender="button" /> <s:convertEntity /> </h:selectOneMenu> <h:outputLabel value="Select Shipping Destination: " for="country" /> <h:selectOneMenu id="country" value="#{shippingCalculatorBean.country}"> <s:selectItems var="country" value="#{customerBean.countries}" label="#{country.name}" noSelectionLabel="Select" /> <a4j:support event="onchange" reRender="button"/> <s:convertEntity /> </h:selectOneMenu> <h:panelGrid columns="1" columnClasses="centered" width="100%"> <a4j:commandButton id="button" value="Calculate" disabled="#{shippingCalculatorBean.country eq null or shippingCalculatorBean.product eq null}" reRender="total" /> <h:panelGroup> <h:outputText value="Total Shipping Cost: " /> <h:outputText id="total" value="#{shippingCalculatorBean.total}"> <f:convertNumber type="currency" currencySymbol="$" maxFractionDigits="0" /> </h:outputText> </h:panelGroup> </h:panelGrid> </h:panelGrid> </rich:panel> </h:form> <h:form> <rich:panel> <f:facet name="header"> <h:outputText value="Shipping Calculator (with Temporary Conversation)" /> </f:facet> <h:panelGrid columns="1"> <h:outputLabel value="Select Product: " for="product" /> <h:selectOneMenu id="product" value="#{shippingCalculatorBeanSeam.product}"> <s:selectItems var="product" value="#{productBean.products}" label="#{product.name}" noSelectionLabel="Select" /> <a4j:support event="onchange" reRender="button" /> <s:convertEntity /> </h:selectOneMenu> <h:outputLabel value="Select Shipping Destination: " for="country" /> <h:selectOneMenu id="country" value="#{shippingCalculatorBeanSeam.country}"> <s:selectItems var="country" value="#{customerBean.countries}" label="#{country.name}" noSelectionLabel="Select" /> <a4j:support event="onchange" reRender="button" /> <s:convertEntity /> </h:selectOneMenu> <h:panelGrid columns="1" columnClasses="centered" width="100%"> <a4j:commandButton id="button" value="Calculate" disabled="#{shippingCalculatorBeanSeam.country eq null or shippingCalculatorBeanSeam.product eq null}" reRender="total" /> <h:panelGroup> <h:outputText value="Total Shipping Cost: " /> <h:outputText id="total" value="#{shippingCalculatorBeanSeam.total}"> <f:convertNumber type="currency" currencySymbol="$" maxFractionDigits="0" /> </h:outputText> </h:panelGroup> </h:panelGrid> </h:panelGrid> </rich:panel> </h:form> </h:panelGrid> The following screenshot demonstrates the problem of using request-scoped or temporary conversation-scoped backing beans in an Ajax-enabled JSF application. As an Ajax request is simply an asynchronous HTTP request marshalled by client-side code executed by the browser's JavaScript interpreter, the request-scoped backing beans are recreated with every Ajax request. The model state is lost and the behavior of the components in the view is incorrect.
Read more
  • 0
  • 0
  • 1811
Banner background image

article-image-skin-customization-jboss-richfaces-33
Packt
30 Nov 2009
5 min read
Save for later

Skin Customization in JBoss RichFaces 3.3

Packt
30 Nov 2009
5 min read
Skinnability Every RichFaces component gives the support for skinnability and it means that just by changing the skin, we change the look for all of the components. That's very good for giving our application a consistent look and not repeating the same CSS values for each component every time. RichFaces still uses CSS, but it also enhances it in order to make it simpler to manage and maintain. Customize skin parameters A skin file contains the basic settings (such as font, colors, and so on) that we'll use for all the components—just by changing those settings, we can customize the basic look and feel for the RichFaces framework. As you might know, RichFaces comes with some built-in skins (and other external plug 'n' skin ones)—you can start with those skins in order to create your own custom skin. The built-in skins are: Plain emeraldTown blueSky wine japanCherry ruby classic deepMarine The plug 'n' skin ones are: laguna darkX glassX The plug 'n' skin skins are packaged in external jar files (that you can download from the same location as that of the RichFaces framework) that must be added into the project in order to be able to use them. Remember that the skin used by the application can be set as context-param in the web.xml file: <context-param> <param-name>org.richfaces.SKIN</param-name> <param-value>emeraldTown</param-value></context-param> This is an example with the emeralTown skin set: If we change the skin to japanCherry, we have the following screenshot: That's without changing a single line of CSS or XHTML! Edit a basic skin Now let's start creating our own basic skin. In order to do that, we are going to reuse one of the built-in skin files and change it. You can find the skin files in the richfaces-impl-3.x.x.jar file inside the META-INF/skins directory. Let's open the file and then open, for example, the emeraldTown.skin.properties file that looks like this (yes, the skin file is a .properties file!): #ColorsheaderBackgroundColor=#005000headerGradientColor=#70BA70headerTextColor=#FFFFFFheaderWeightFont=boldgeneralBackgroundColor=#f1f1f1generalTextColor=#000000generalSizeFont=18pxgeneralFamilyFont=Arial, Verdana, sans-serifcontrolTextColor=#000000controlBackgroundColor=#ffffffadditionalBackgroundColor=#E2F6E2shadowBackgroundColor=#000000shadowOpacity=1panelBorderColor=#C0C0C0subBorderColor=#fffffftabBackgroundColor=#ADCDADtabDisabledTextColor=#67AA67trimColor=#BBECBBtipBackgroundColor=#FAE6B0tipBorderColor=#E5973EselectControlColor=#FF9409generalLinkColor=#43BD43hoverLinkColor=#FF9409visitedLinkColor=#43BD43# FontsheaderSizeFont=18pxheaderFamilyFont=Arial, Verdana, sans-seriftabSizeFont=11tabFamilyFont=Arial, Verdana, sans-serifbuttonSizeFont=18buttonFamilyFont=Arial, Verdana, sans-seriftableBackgroundColor=#FFFFFFtableFooterBackgroundColor=#cccccctableSubfooterBackgroundColor=#f1f1f1tableBorderColor=#C0C0C0tableBorderWidth=2px#Calendar colorscalendarWeekBackgroundColor=#f5f5f5calendarHolidaysBackgroundColor=#FFEBDAcalendarHolidaysTextColor=#FF7800calendarCurrentBackgroundColor=#FF7800calendarCurrentTextColor=#FFEBDAcalendarSpecBackgroundColor=#E2F6E2calendarSpecTextColor=#000000warningColor=#FFE6E6warningBackgroundColor=#FF0000editorBackgroundColor=#F1F1F1editBackgroundColor=#FEFFDA#GradientsgradientType=plain In order to test it, let's open our application project, create a file called mySkin.skin.properties inside the directory /resources/WEB-INF/, and add the above text. Then, let's open the build.xml file and edit it, and add the following code into the war target: <copy tofile="${war.dir}/WEB-INF/classes/mySkin.skin.properties"file="${basedir}/resources/WEB-INF/mySkin.skin.properties"overwrite="true"/> Also, as our application supports multiple skins, let's open the components.xml file and add support to it: <property name="defaultSkin">mySkin</property><property name="availableSkins"> <value>mySkin</value> <value>laguna</value> <value>darkX</value> <value>glassX</value> <value>blueSky</value> <value>classic</value> <value>ruby</value> <value>wine</value> <value>deepMarine</value> <value>emeraldTown</value> <value>japanCherry</value></property> If you just want to select the new skin as the fixed skin, you would just edit the web.xml file and select the new skin by inserting the name into the context parameter (as explained before). Just to make an (bad looking, but understandable) example, let's change some parameters in the skin file: #ColorsheaderBackgroundColor=#005000headerGradientColor=#70BA70headerTextColor=#FFFFFFheaderWeightFont=boldgeneralBackgroundColor=#f1f1f1generalTextColor=#000000generalSizeFont=18pxgeneralFamilyFont=Arial, Verdana, sans-serifcontrolTextColor=#000000controlBackgroundColor=#ffffffadditionalBackgroundColor=#E2F6E2shadowBackgroundColor=#000000shadowOpacity=1panelBorderColor=#C0C0C0subBorderColor=#fffffftabBackgroundColor=#ADCDADtabDisabledTextColor=#67AA67trimColor=#BBECBBtipBackgroundColor=#FAE6B0tipBorderColor=#E5973EselectControlColor=#FF9409generalLinkColor=#43BD43hoverLinkColor=#FF9409visitedLinkColor=#43BD43# FontsheaderSizeFont=18pxheaderFamilyFont=Arial, Verdana, sans-seriftabSizeFont=11tabFamilyFont=Arial, Verdana, sans-serifbuttonSizeFont=18buttonFamilyFont=Arial, Verdana, sans-seriftableBackgroundColor=#FFFFFFtableFooterBackgroundColor=#cccccctableSubfooterBackgroundColor=#f1f1f1tableBorderColor=#C0C0C0tableBorderWidth=2px#Calendar colorscalendarWeekBackgroundColor=#f5f5f5calendarHolidaysBackgroundColor=#FFEBDAcalendarHolidaysTextColor=#FF7800calendarCurrentBackgroundColor=#FF7800calendarCurrentTextColor=#FFEBDAcalendarSpecBackgroundColor=#E2F6E2calendarSpecTextColor=#000000warningColor=#FFE6E6warningBackgroundColor=#FF0000editorBackgroundColor=#F1F1F1editBackgroundColor=#FEFFDA#GradientsgradientType=plain Here is the screenshot of what happened with the new skin: How do I know which parameters to change? The official RichFaces Developer Guide contains, for every component, a table with the correspondences between the skin parameters and the CSS properties they are connected to.
Read more
  • 0
  • 0
  • 2610

article-image-facelets-components-jsf-12
Packt
30 Nov 2009
12 min read
Save for later

Facelets Components in JSF 1.2

Packt
30 Nov 2009
12 min read
One of the more advanced features of the Facelets framework is the ability to define complex templates containing dynamic nested content. What is a template?The Merriam-Webster dictionary defines the word "template" as "a gauge, pattern, or mold (as a thin plate or board) used as a guide to the form of a piece being made" and as "something that establishes or serves as a pattern." In the context of user interface design for the Web, a template can be thought of as an abstraction of a set of pages in the web application.A template does not define content, but rather it defines placeholders for content, and provides the layout, orientation, flow, structure, and logical organization of the elements on the page. We can also think of templates as documents with "blanks" that will be filled in with real data and user interface controls at request time. One of the benefits of templating is the separation of content from presentation, making the maintenance of the views in our web application much easier. The <ui:insert> tag has a name attribute that is used to specify a dynamic content region that will be inserted by the template client. When Facelets renders a UI composition template, it attempts to substitute any <ui:insert> tags in the Facelets template document with corresponding <ui:define> tags from the Facelets template client document. Conceptually, the Facelets composition template transformation process can be visualized as follows: In this scenario, the browser requests a Facelets template client document in our JSF application. This document contains two <ui:define> tags that specify named content elements and references a Facelets template document using the <ui:composition> tag's template attribute. The Facelets template document contains two <ui:insert> tags that have the same names as the <ui:define> tags in the client document, and three <ui:include> tags for the header, footer, and navigation menu. This is a good example of the excellent support that Facelets provides for the Composite View design pattern. Facelets transforms the template client document by merging any content it defines using <ui:define> tags with the content insertion points specified in the Facelets template document using the <ui:insert> tag. The result of merging the Facelets template client document with the Facelets template document is rendered in the browser as a composite view. While this concept may seem a bit complicated at first, it is actually a powerful feature of the Facelets view defi nition framework that can greatly simplify user interface templating in a web application. In fact, the Facelets composition template document can itself be a template client by referencing another composition template. In this way, a complex hierarchy of templates can be used to construct a flexible, multi-layered presentation tier for a JSF application. Without the Facelets templating system, we would have to copy and paste view elements such as headers, footers, and menus from one page to the next to achieve a consistent look and feel across our web application. Facelets templating enables us to define our look and feel in one document and to reuse it across multiple pages. Therefore, if we decide to change the look and feel, we only have to update one document and the change is immediately propagated to all the views of the JSF application. Let's look at some examples of how to use the Facelets templating feature. A simple Facelets template The following is an example of a simple Facelets template. It simply renders a message within an HTML <h2> element. Facelets will replace the "unnamed" <ui:insert> tag (without the name attribute) in the template document with the content of the <ui:composition> tag from the template client document. template01.jsf<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Facelets template example</title><link rel="stylesheet" type="text/css" href="/css/style.css" /></head><body><h2><ui:insert /></h2></body></html> A simple Facelets template client Let's look at a simple example of Facelets templating. The following page is a Facelets template client document. (Remember: you can identify a Facelets template client by looking for the existence of the template attribute on the <ui:composition> tag.) The <ui:composition> tag simply contains the text Hello World. templateClient01.jsf<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>ui:composition example</title></head><body><ui:composition template="/WEB-INF/templates/template01.jsf">Hello World</ui:composition><ui:debug /></body></html> The following screenshot displays the result of the Facelets UI composition template transformation when the browser requests templateClient01.jsf. Another simple Facelets template client The following Facelets template client example demonstrates how a template can be reused across multiple pages in the JSF application: templateClient01a.jsf<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>ui:composition example</title></head><body><ui:composition template="/WEB-INF/templates/template01.jsf">How are you today?</ui:composition><ui:debug /></body></html> The following screenshot displays the result of the Facelets UI composition template transformation when the browser requests templateClient01a.jsf: A more complex Facelets template The Facelets template in the previous example is quite simple and does not demonstrate some of the more advanced capabilities of Facelets templating. In particular, the template in the previous example only has a single <ui:insert> tag, with no name attribute specified. The behavior of the unnamed <ui:insert> tag is to include any content in the referencing template client page. In more complex templates, multiple <ui:insert> tags can be used to enable template client documents to defi ne several custom content elements that will be inserted throughout the template. The following Facelets template document declares three named <ui:insert> elements. Notice carefully where these tags are located. template02.jsf<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title><ui:insert name="title" /></title><link rel="stylesheet" type="text/css" href="/css/style.css" /></head><body><ui:include src="/WEB-INF/includes/header.jsf" /><h2><ui:insert name="header" /></h2><ui:insert name="content" /><ui:include src="/WEB-INF/includes/footer.jsf" /></body></html> In the following example, the template client document defines three content elements named title, header, and content using the <ui:define> tag. Their position in the client document is not important because the template document determines where this content will be positioned. templateClient02.jsf<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>ui:composition example</title></head><body><ui:composition template="/WEB-INF/templates/template02.jsf"><ui:define name="title">Facelet template example</ui:define><ui:define name="header">Hello World</ui:define><ui:define name="content">Page content goes here.</ui:define></ui:composition><ui:debug /></body></html> The following screenshot displays the result of a more complex Facelets UI composition template transformation when the browser requests the page named templateClient02.jsf. The next example demonstrates reusing a more advanced Facelets UI composition template. At this stage, we should have a good understanding of the basic concepts of Facelets templating and reuse. templateClient02a.jsf<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>ui:composition example</title></head><body>Facelets Components[ 78 ]<ui:composition template="/WEB-INF/templates/template02.jsf"><ui:define name="title">Facelet template example</ui:define><ui:define name="header">Thanks for visiting!</ui:define><ui:define name="content">We hope you enjoyed our site.</ui:define></ui:composition><ui:debug /></body></html> The next screenshot displays the result of the Facelets UI composition transformation when the browser requests templateClient02a.jsf. We can follow this pattern to make a number of JSF pages reuse the template in this manner to achieve a consistent look and feel across our web application. Decorating the user interface The Facelets framework supports the definition of smaller, reusable view elements that can be combined at runtime using the Facelets UI tag library. Some of these tags, such as the <ui:composition> and <ui:component> tags, trim their surrounding content. This behavior is desirable when including content from one complete XHTML document within another complete XHTML document. There are cases, however, when we do not want Facelets to trim the content outside the Facelets tag, such as when we are decorating content on one page with additional JSF or HTML markup defi ned in another page. For example, suppose there is a section of content in our XHTML document that we want to wrap or "decorate" with an HTML <div> element defined in another Facelets page. In this scenario, we want all the content on the page to be displayed, and we are simply surrounding part of the content with additional markup defined in another Facelets template. Facelets provides the <ui:decoration> tag for this purpose. Decorating content on a Facelets page The following example demonstrates how to decorate content on a Facelets page with markup from another Facelets page using the <ui:decoration> tag. The <ui:decoration> tag has a template attribute and behaves like the <ui:composition> tag. Facelets templating typically uses the <ui:composition>. It references a Facelets template document that contains markup to be included in the current document. The main difference between the <ui:composition> tag and the <ui:decoration> tag is that Facelets trims the content outside the <ui:composition> tag but does not trim the content outside the <ui:decoration> tag. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>ui:decorate example</title><link rel="stylesheet" type="text/css" href="css/style.css" /></head><body>Text before will stay.<ui:decorate template="/WEB-INF/templates/box.jsf"><span class="header">Information Box</span><p>This is the first line of information.</p><p>This is the second line of information.</p><p>This is the third line of information.</p></ui:decorate>Text after will stay.<ui:debug /></body></html> Creating a Facelets decoration Let's examine the Facelets decoration template referenced by the previous example. The following source code demonstrates how to create a Facelets template to provide the decoration that will surround the content on another page. As we are using a <ui:composition> tag, only the content inside this tag will be used. In this example, we declare an HTML <div> element with the "box" CSS style class that contains a single Facelets <ui:insert> tag. When Facelets renders the above Facelets page, it encounters the <ui:decorate> tag that references the box.jsf page. The <ui:decorate> tag will be merged together with the associated decoration template and then rendered in the view. In this scenario, Facelets will insert the child content of the <ui:decorate> tag into the Facelets decoration template where the <ui:insert> tag is declared. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html ><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Box</title></head><body><ui:composition><div class="box"><ui:insert /></div></ui:composition></body></html> The result is that our content is surrounded or "decorated" by the <div> element. Any text before or after the <ui:decoration> is still rendered on the page, as shown in the next screenshot: The included decoration is rendered as is, and is not nested inside a UI component as demonstrated in the following Facelets debug page:
Read more
  • 0
  • 0
  • 2524

article-image-hibernate-types
Packt
27 Nov 2009
3 min read
Save for later

Hibernate Types

Packt
27 Nov 2009
3 min read
Hibernate allows transparent persistence, which means the application is absolutely isolated from the underlying database storage format. Three players in the Hibernate scene implement this feature: Hibernate dialect, Hibernate types, and HQL. The Hibernate dialect allows us to use a range of different databases, supporting different, proprietary variants of SQL and column types. In addition, HQL allows us to query persisted objects, regardless of their relational persisted form in the database. Hibernate types are a representation of databases SQL types, provide an abstraction of the underlying database types, and prevent the application from getting involved with the actual database column types. They allow us to develop the application without worrying about the target database and the column types that the database supports. Instead, we get involved with mapping Java types to Hibernate types. The database dialect, as part of Hibernate, is responsible for transforming Java types to SQL types, based on the target database. This gives us the flexibility to change the database to one that may support different column types or SQL without changing the application code. Built-in types Hibernate includes a rich and powerful range of built-in types. These types satisfy most needs of a typical application, providing a bridge between basic Java types and common SQL types. Java types mapped with these types range from basic, simple types, such as long and int, to large and complex types, such as Blob and Clob. The following table categorizes Hibernate built-in types with corresponding Java and SQL types: Java Type Hibernate Type Name SQL Type Primitives Boolean or boolean boolean BIT true_false CHAR(1)('T'or'F') yes_no CHAR(1)('Y'or'N') Byte or byte byte TINYINT char or Character character CHAR double or Double double DOUBLE float or float float FLOAT int or Integer integer INTEGER long or Long long BIGINT short or Short short SMALLINT String java.lang.String string VARCHAR character CHAR(1) text CLOB Arbitrary Precision Numeric java.math.BigDecimal big_decimal NUMERIC Byte Array byte[] or Byte[] binary VARBINARY   Time and Date java.util.Date date DATE time TIME timestamp TIMESTAMP java.util.Calendar calendar TIMESTAMP calendar_date DATE java.sql.Date date DATE java.sql.Time time TIME java.sql.Timestamp timestamp TIMESTAMP Localization java.util.Locale locale VARCHAR java.util.TimeZone timezone java.util.Currency currency Class Names java.lang.Class class VARCHAR Any Serializable Object java.io.Serializable Serializable VARBINARY JDBC Large Objects java.sql.Blob blob BLOB java.sql.Clob clob CLOB
Read more
  • 0
  • 0
  • 2391
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $15.99/month. Cancel anytime
article-image-build-advanced-contact-manager-using-jboss-richfaces-33-part-1
Packt
18 Nov 2009
11 min read
Save for later

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

Packt
18 Nov 2009
11 min read
The main layout Let's start preparing the space for the core features of the application. We want a three-column layout for groups, contacts list, and contact detail. Let's open the home.xhtml file and add a three-column panel grid inside the body: <h:panelGrid columns="3" width="100%" columnClasses="main-group-column, main-contacts-list-column,  main-contact-detail-column"></h:panelGrid> We are using three new CSS classes (one for every column). Let's open the /view/stylesheet/theme.css file and add the following code: .main-group-column { width: 20%; vertical-align: top;}.main-contacts-list-column { width: 40%; vertical-align: top;}.main-contact-detail-column { width: 40%; vertical-align: top;} The main columns are ready; now we want to split the content of every column in a separate file (so we don't have a large and difficult file to read) by using the Facelets templating capabilities—let's create a new folder inside the/view folder called main, and let's create the following empty files inside it: contactsGroups.xhtml contactsList.xhtml contactEdit.xhtml contactView.xhtml Now let's open them and put the standard code for an empty (included) file: <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><ui:composition ><!-- my code here --></ui:composition> Now, we have all of the pieces ready to be included into the home.xhtml file, let's open it and start adding the first column inside h:panelGrid: <a:outputPanel id="contactsGroups"> <ui:include src="main/contactsGroups.xhtml"/></a:outputPanel> As you can see, we surrounded the include with an a:outputPanel that will be used as a placeholder for the re-rendering purpose. Include a Facelets tag (ui:include) into the a:outputPanel that we used in order to include the page at that point. Ajax placeholders A very important concept to keep in mind while developing is that the Ajax framework can't add or delete, but can only replace existing elements in the page.For this reason, if you want to append some code, you need to use a placeholder. RichFaces has a component that can be used as a placeholder—a4j:outputPanel. Inside a4j:outputPanel, you can put other components that use the "rendered" attribute in order to decide if they are visible or not. When you want to re-render all the included components, just re-render the outputPanel, and all will work without any problem. Here is a non-working code snippet: <h:form> <h:inputText value="#{aBean.myText}"> <a4j:support event="onkeyup" reRender="out1" /> </h:inputText></h:form><h:outputText id="out1" value="#{aBean.myText}" rendered="#{not empty aBean.myText}"/> This code seems the same as that of the a4j:support example, but it won't work. The problem is that we added the rendered attribute to outputText, so initially, out1 will not be rendered (because the text property is initially empty and rendered will be equal to false). After the Ajax response, the JavaScript Engine will not find the out1 element (it is not in the page because of rendered="false"), and it will not be able to update it (remember that you can't add or delete elements, only replace them). It is very simple to make the code work: <h:form> <h:inputText value="#{aBean.myText}"> <a4j:support event="onkeyup" reRender="out2" /> </h:inputText></h:form><a4j:outputPanel id="out2"> <h:outputText id="out1" rendered="#{not empty aBean.myText}" value="#{aBean.myText}" /></a4j:outputPanel> As you can see, you just have to put the out1 component inside a4j:outputPanel (called out2) and tell a4j:support to re-render out2 instead of out1. Initially, out2 will be rendered but empty (because out1 will not be rendered). After the Ajax response, the empty out2 will be replaced with markup elements that also contain the out1 component (that is now visible, because the myText property is not empty after the Ajax update and the rendered property is true). A very important concept to keep in mind while developing is that the Ajax framework can't add or delete, but can only replace existing elements of the page. For this reason, if you want to append some code, you need to use a placeholder. The groups box This box will contain all the contacts groups, so the user will be able to organize contacts in different groups in a better way. We will not implement the group box features in this article. Therefore, by now the group column is just a rich:panel with a link to refresh the contact list. Let's open the contactsGroups.xhtml file and insert the following code: <h:form> <rich:panel> <f:facet name="header"> <h:outputText value="#{messages['groups']}" /> </f:facet> <h:panelGrid columns="1"> <a:commandLink value="#{messages['allContacts']}" ajaxSingle="true" reRender="contactsList"> <f:setPropertyActionListener value="#{null}" target="#{homeContactsListHelper.contactsList}" /> </a:commandLink> </h:panelGrid> </rich:panel></h:form> As you can see, we've put a three-column h:panelGrid (to be used in the future) and a:commandLink, which just sets the contactsList property of the homeContactListHelper bean (that we will see in the next section) to null, in order to make the list be read again. At the end of the Ajax interaction, it will re-render the contactsList column in order to show the new data. Also, notice that we are still supporting i18n for every text using the messages property; the task to fill the messages_XX.properties file is left as an exercise for the user. The contacts list The second column inside h:panelGrid of home.xhtml looks like: <a:outputPanel id="contactsList"> <ui:include src="main/contactsList.xhtml"/></a:outputPanel> As for groups, we used a placeholder surrounding the ui:include tag. Now let's focus on creating the data table—open the /view/main/contactsList.xhtml file and add the first snippet of code for dataTable: <h:form> <rich:dataTable id="contactsTable" reRender="contactsTableDS" rows="20" value="#{homeContactsListHelper.contactsList}" var="contact"> <rich:column width="45%"> <h:outputText value="#{contact.name}"/> </rich:column> <rich:column width="45%"> <h:outputText value="#{contact.surname}"/> </rich:column> <f:facet name="footer"> <rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"/> </f:facet> </rich:dataTable> <h:outputText value="#{messages['noContactsInList']}" rendered="#{homeContactsListHelper.contactsList.size()==0}"/></h:form> We just added the rich:dataTable component with some columns and an Ajax data scroller at the end. Differences between h:dataTable and rich:dataTable RichFaces provides its own version of h:dataTable, which contains more features and is better integrated with the RichFaces framework. The first important additional feature, in fact, is the skinnability support following the RichFaces standards. Other features are row and column spans support (we will discuss it in the Columns and column groups section), out-of-the-box filter and sorting (discussed in the Filtering and sorting section), more JavaScript event handlers (such as onRowClick, onRowContextMenu, onRowDblClick, and so on) and the reRender attribute. Like other data iteration components of the RichFaces framework, it also supports the partial-row update. Data pagination Implementing Ajax data pagination using RichFaces is really simple—just decide how many rows must be shown in every page by setting the rows attribute of dataTable (in our case, we've chosen 20 rows per page), and then "attach" the rich:datascroller component to it by filling the for attribute with the dataTable id: <rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"/> Here you can see another very useful attribute (renderIfSinglePage) that makes the component hidden when there is just a single page in the list (it means the list contains a number of items that is less than or equal to the value of the rows attribute). A thing to keep in mind is that the rich:datascroller component must stay inside a form component (h:form or a:form) in order to work. Customizing rich:datascroller is possible not only by using CSS classes (as usual), but also by personalizing our own parts using the following facets: pages controlsSeparator first, first_disabled last, last_disabled next, next_disabled previous, previous_disabled fastforward, fastforward_disabled fastrewind, fastrewinf_disabled Here is an example with some customized facets (using strings): <rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"> <f:facet name="first"> <h:outputText value="First" /> </f:facet> <f:facet name="last"> <h:outputText value="Last" /> </f:facet></rich:datascroller> Here is the result: You can use an image (or another component) instead of text, in order to create your own customized scroller. Another interesting example is: <rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"> <f:facet name="first"> <h:outputText value="First"/> </f:facet> <f:facet name="last"> <h:outputText value="Last"/> </f:facet> <f:attribute name="pageIndexVar" value="pageIndexVar"/> <f:attribute name="pagesVar" value="pagesVar"/> <f:facet name="pages"> <h:panelGroup> <h:outputText value="Page #{pageIndexVar} / #{pagesVar}"/> </h:panelGroup> </f:facet></rich:datascroller> The result is: By setting the pageIndexVar and pagesVar attributes, we are able to use them in an outputText component, as we've done in the example. A useful attribute of the component is maxPages that sets the maximum number of page links (the numbers in the middle), which the scroller shows—therefore, we can control the size of it. The page attribute could be bound to a property of a bean, in order to switch to a page giving the number—a simple use-case could be using an inputText and a commandButton, in order to let the client insert the page number that he/she wants to go to. Here is the code that shows how to implement it: <rich:datascroller for="contactsList" maxPages="20" fastControls="hide" page="#{customDataScrollerExampleHelper.scrollerPage}" pagesVar="pages" id="ds"> <f:facet name="first"> <h:outputText value="First" /> </f:facet> <f:facet name="first_disabled"> <h:outputText value="First" /> </f:facet> <f:facet name="last"> <h:outputText value="Last" /> </f:facet> <f:facet name="last_disabled"> <h:outputText value="Last" /> </f:facet> <f:facet name="previous"> <h:outputText value="Previous" /> </f:facet> <f:facet name="previous_disabled"> <h:outputText value="Previous" /> </f:facet> <f:facet name="next"> <h:outputText value="Next" /> </f:facet> <f:facet name="next_disabled"> <h:outputText value="Next" /> </f:facet> <f:facet name="pages"> <h:panelGroup> <h:outputText value="Page "/> <h:inputText value="#{customDataScrollerExampleHelper. scrollerPage}" size="4"> <f:validateLongRange minimum="0" /> <a:support event="onkeyup" timeout="500" oncomplete="#{rich:component('ds')}. switchToPage(this.value)" /> </h:inputText> <h:outputText value=" of #{pages}"/> </h:panelGroup> </f:facet></rich:datascroller> As you can see, besides customizing the text of the First, Last, Previous, and Next sections, we defined a pages facet by inserting h:inputText connected with an integer value inside a backing bean. We also added the a:support tag, in order to trim the page change after the keyup event is completed. We've also set the timeout attribute, in order to call the server every 500 ms and not every time the user types. You can see a screenshot of the feature here:
Read more
  • 0
  • 0
  • 1026

article-image-build-advanced-contact-manager-using-jboss-richfaces-33-part-3
Packt
18 Nov 2009
11 min read
Save for later

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 3

Packt
18 Nov 2009
11 min read
  The ajaxSingle and the process attributes The ajaxSingle property is very useful to control the form submission when ajaxSingle is set to true—the form is not submitted and, just the Ajax component data is sent. This attribute is available in every Ajax action component and we can use it to call an action from a button, skipping the form validation (like the JSF immediate property does), or to send the value of just an input into a form without validation and submitting the other ones. The second use case can be used, for example, when we need an input menu that dynamically changes the value of other inputs without submitting the entire form: <h:form> <!-- other input controls --> <h:selectOneMenu id="country" value="#{myBean.selectedCountry}"> <f:selectItems value="#{myBean.myCountries}"> <a:support event="onchange" ajaxSingle="true" reRender="city" /> </h:selectOneMenu> <h:selectOneMenu id="city" value="#{myBean.selectedCity}"> <f:selectItems value="#{myBean.myCities}"> </h:selectOneMenu> <!-- other input controls --></h:form> In this example, every time the user selects a new country, the value is submitted to the bean that recalculates the myCities property for the new country, after that the city menu will be re-rendered to show the new cities. All that without submitting the form or blocking the changes because of some validation problem. What if you would like to send more than one value, but still not the entire form? We can use Ajax regions (we will see in the next sections), or we can use the process attribute. It contains a list of components to process while submitting the Ajax action: <h:form> <!-- other input controls --> <h:inputText id="input1" ... /> <h:selectOneMenu id="country" value="#{myBean.selectedCountry}"> <f:selectItems value="#{myBean.myCountries}"> <a:support event="onchange" ajaxSingle="true" process="input2, input3" reRender="city" /> </h:selectOneMenu> <h:inputText id="input2" ... /> <h:inputText id="input3" ... /> <h:selectOneMenu id="city" value="#{myBean.selectedCity}"> <f:selectItems value="#{myBean.myCities}"> </h:selectOneMenu> <!-- other input controls --></h:form> In this example, we also wanted to submit the input2 and the input3 values together with the new country, because they are useful for retrieving the new cities list—just by setting the process attribute with the id list and during the submission, they will be processed. Thus input1 will not be sent. Also, for action components such as buttons, you can decide what to send using the ajaxSingle and process attributes. Form submission and processingWe speak about form "submission" to simplify the concept and make things more understandable. In reality, for every request, all of the form is submitted, but only the selected components (using ajaxSingle and/or process attributes) will be "processed". By "processed" we mean "pass through" the JSF phases (decoding, conversion, validation, and model updating). More Ajax! For every contact, we would like to add more customizable fields, so let's use the ContactField entity connected to every Contact instance. First of all, let's create a support bean called HomeSelectedContactOtherFieldsHelper inside the book.richfaces.advcm.modules.main package. It might look like this: @Name("homeSelectedContactOtherFieldsHelper")@Scope(ScopeType.CONVERSATION)public class HomeSelectedContactOtherFieldsHelper { @In(create = true) EntityManager entityManager; @In(required = true) Contact loggedUser; @In FacesMessages facesMessages; @In(required = true) HomeSelectedContactHelper homeSelectedContactHelper; // my code} A notable thing is highlighted—we injected the homeSelectedContactHelper component, because to get the list of the customized fields from the database, we need the contact owner. We also set the required attribute to true, because this bean can't live without the existence of homeSelectedContactHelper in the context. Now, let's add the property containing the list of personalized fields for the selected contact: private List<ContactField> contactFieldsList;public List<ContactField> getContactFieldsList() { if (contactFieldsList == null) { // Getting the list of all the contact fields String query = "from ContactField cf where cf.contact.id=:idContactOwner order by cf.id"; contactFieldsList = (List<ContactField>) entityManager.createQuery(query) .setParameter("idContactOwner", homeSelectedContactHelper.getSelectedContact() .getId()).getResultList(); } return contactFieldsList;}public void setContactFieldsList(List<ContactField> contactFieldsList) { this.contactFieldsList = contactFieldsList;} As you can see, it is a normal property lazy initialized using the getter. This queries the database to retrieve the list of customized fields for the selected contact. We have to put into the bean some other method useful to manage the customized field (adding and deleting field to and from the database), let's add those methods: public void createNewContactFieldInstance() { // Adding the new instance as last field (for inserting a new field) getContactFieldsList().add(new ContactField());}public void persistNewContactField(ContactField field) { // Attaching the owner of the contact field.setContact(homeSelectedContactHelper.getSelectedContact()); entityManager.persist(field);}public void deleteContactField(ContactField field) { // If it is in the database, delete it if (isContactFieldManaged(field)) { entityManager.remove(field); } // Removing the field from the list getContactFieldsList().remove(field);}public boolean isContactFieldManaged(ContactField field) { return field != null && entityManager.contains(field);} The createNewContactFieldInstance() method will just add a new (not yet persisted), empty instance of the ContactField class into the list. After the user has filled the values in, he/she will press a button that calls the persistNewContactField() method to save the new data into the database. In order to delete it, we are going to use the deleteContactField() method, and to determine if an instance is persisted into the database or not, we are going to use the isContactFieldManaged() method. Now, let's open the /view/main/contactView.xhtml file and add the code to show the personalized fields after h:panelGrid— i shows the standard ones: <a:repeat value="#{homeSelectedContactOtherFieldsHelper.contactFieldsList}" var="field"> <h:panelGrid columns="2" rowClasses="prop" columnClasses="name,value"> <h:outputText value="#{field.type} (#{field.label}):"/> <h:outputText value="#{field.value}"/> </h:panelGrid></a:repeat> We are using a new RichFaces data iteration component that permits us to iterate over a collection and put the data we want (the rich:dataTable component would instead create a table for the elements list). In our case, the h:panelGrid block will be repeated for every element of the collection (so for every customized field). Now, let's open the /view/main/contactEdit.xhtml file and add the code for editing the customized fields into the list: <a:region> <a:outputPanel id="otherFieldsList"> <a:repeat value="#{homeSelectedContactOtherFieldsHelper. contactFieldsList}" var="field"> <h:panelGrid columns="3" rowClasses="prop" columnClasses="name,value,validatormsg"> <h:panelGroup> <h:inputText id="scOtherFieldType" value="#{field.type}" required="true" size="5"> <a:support event="onblur" ajaxSingle="true"/> </h:inputText> <h:outputText value=" ("/> <h:inputText id="scOtherFieldLabel" value="#{field.label}" size="5"> <a:support event="onblur" ajaxSingle="true"/> </h:inputText> <h:outputText value=")"/><br/> <rich:message for="scOtherFieldType" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> </h:panelGroup> <h:panelGroup> <h:inputText id="scOtherFieldValue" value="#{field.value}" required="true"> <a:support event="onblur" ajaxSingle="true"/> </h:inputText><br/> <rich:message for="scOtherFieldValue" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> </h:panelGroup> <h:panelGroup> <a:commandButton image="/img/add.png" reRender="otherFieldsList" action="#{homeSelectedContactOtherFieldsHelper. persistNewContactField(field)}" rendered="#{!homeSelectedContactOtherFieldsHelper. isContactFieldManaged(field)}"> </a:commandButton> <a:commandButton image="/img/remove.png" reRender="otherFieldsList" ajaxSingle="true" action="#{homeSelectedContactOtherFieldsHelper. deleteContactField(field)}"> </a:commandButton> </h:panelGroup> </h:panelGrid> </a:repeat> <a:commandLink reRender="otherFieldsList" ajaxSingle="true" action="#{homeSelectedContactOtherFieldsHelper. createNewContactFieldInstance}" rendered="#{homeSelectedContactHelper. selectedContactManaged}" styleClass="image-command-link"> <h:graphicImage value="/img/add.png"/> <h:outputText value="#{messages['addNewField']}"/> </a:commandLink> </a:outputPanel></a:region> The code looks very similar to the one in the view box, except for the action buttons (to add a new instance, persist, save, or delete) and, for the presence of the surrounding tag a:region (highlighted). This is very important in order to make sure the form works correctly; we will see why in the next section. Also, notice that every input component has the a:support tag as a child that will update the bean with the edited value at the onblur event (which means that every time you switch the focus to another component, the value of the last one is submitted). So, if you delete or add a field, you will now loose the edited values for other fields. It is also used for Ajax validation, as the user is informed that the value is not valid when it moves the cursor to another input. Here is a screenshot with the new feature in the edit box: Using a:support only for Ajax validation If you want to use the a:support tag only for validation purpose, remember to set its bypassUpdates attribute to true, so the process would be faster as the JSF Update Model and Invoke Application phases will not be invoked. Ajax containers While developing a web application with RichFaces, it's very useful to know how to use Ajax containers (such as the a:region component) in order to optimize Ajax requests. In this section, we'll discuss about the a:region component. It is a very important component of the framework—it can define Ajax areas to limit the part of the component tree to be processed during an Ajax request. Regions can be nested during an Ajax request and the closest one will be used. By setting to true the a:region attribute called regionRenderOnly, you can use this component to limit the elements' update—In this way, in fact, only the components inside the region can be updated. Another important attribute is selfRendered; setting this to true tells the framework to render the response basing on component tree without referring to the page code—it is faster, but all of the transient elements that are not saved in the tree (such as f:verbatim or HTML code written directly without using JSF components) will be lost at the first refresh, so you can't use them in this case. To summarize, it is very useful to control the rendering process and optimize it, in order to limit the elements of a form to send during an Ajax request without validation problems, to show different indicators for Ajax status. Example of using a:region: <h:form> <a:region> <h:inputText id="it1" value="#{aBean.text1}"> <a:support event="onkeyup" reRender="text1" /> </h:inputText> <h:inputText id="it2" value="#{aBean.text2}" /> </a:region> <h:inputText id="it3" value="#{aBean.text3}" /> <a:commandButton action="#{aBean.saveTexts}" reRender="text1,text2" /></h:form><h:outputText id="text1" value="#{aBean.text1}" /><h:outputText id="text2" value="#{aBean.text2}" /> In this example, while the user is typing in the text1 value of inputText, a:support sends an Ajax request containing only the it1 and it2 values of inputText. In this case, in fact, a:region limits the components sent by every Ajax request originated from inside the region. So, the Ajax request will only update aBean.text1 and aBean.text2. Wrapping only a component inside an Ajax region is the equivalent of using the ajaxSingle property set to true. If the user clicks on the a:commandButton aBean.text1, the aBean.text2 and aBean.text3 values will be updated by the Ajax request. Coming back to our application, as all the customized fields are inside the same form component, we surround each one with the a:region tag. In this way, the single field is submitted regardless of the other ones. For example, without using a:region, if the user empties the name input value and then tries to insert a new customized field, the process will fail because the name input is not validated. If we use the a:region component, the name field will not be processed and a new field will be inserted. Now that we know how to use the a:region tag, we can combine it with ajaxSingle and process in order to decide what to send at every request, and to better optimize Ajax interactions into the application.
Read more
  • 0
  • 0
  • 882

article-image-create-quick-application-cakephp-part-2
Packt
18 Nov 2009
7 min read
Save for later

Create a Quick Application in CakePHP: Part 2

Packt
18 Nov 2009
7 min read
Editing a Task Now that we can add tasks to CakeTooDoo, the next thing that we will be doing is to have the ability to edit tasks. This is necessary because the users should be able to tick on a task when it has been completed. Also, if the users are not happy with the title of the task, they can change it. To have these features in CakeTooDoo, we will need to add another action to our Tasks Controller and also add a view for this action. Time for Action: Creating the Edit Task Form Open the file tasks_controller.php and add a new action named edit as shown in the following code: function edit($id = null) { if (!$id) { $this->Session->setFlash('Invalid Task'); $this->redirect(array('action'=>'index'), null, true); } if (empty($this->data)) { $this->data = $this->Task->find(array('id' => $id)); } else { if ($this->Task->save($this->data)) { $this->Session->setFlash('The Task has been saved'); $this->redirect(array('action'=>'index'), null, true); } else { $this->Session->setFlash('The Task could not be saved. Please, try again.'); } } } Inside the directory /CakeTooDoo/app/views/tasks, create a new file named edit.ctp and add the following code to it: <?php echo $form->create('Task');?> <fieldset> <legend>Edit Task</legend> <?php echo $form->hidden('id'); echo $form->input('title'); echo $form->input('done'); ?> </fieldset> <?php echo $form->end('Save');?> We will be accessing the Task Edit Form from the List All Task page. So, let's add a link from the List All Tasks page to the Edit Task page. Open the index.ctp file in /CakeTooDoo/app/views directory, and replace the HTML comment <!-- different actions on tasks will be added here later --> with the following code: <?php echo $html->link('Edit', array('action'=>'edit', $task['Task']['id'])); ?> Now open the List All Tasks page in the browser by pointing it to http://localhost/CakeTooDoo/tasks/index and we will see an edit link beside all the tasks. Click on the edit link of the task you want to edit, and this will take you to do the Edit Task form, as shown below: Now let us add links in the Edit Task Form page to the List All Tasks and Add New Task page. Add the following code to the end of edit.ctp in /CakeTooDoo/app/views: <?php echo $html->link('List All Tasks', array('action'=>'index')); ?><br /> <?php echo $html->link('Add Task', array('action'=>'add')); ?> What Just Happened? We added a new action named edit in the Tasks controller. Then we went on to add the view file edit.ctp for this action. Lastly, we linked the other pages to the Edit Task page using the HTML helper. When accessing this page, we need to tell the action which task we are interested to edit. This is done by passing the task id in the URL. So, if we want to edit the task with the id of 2, we need to point our browser to http://localhost/CakeTooDoo/tasks/edit/2. When such a request is made, Cake forwards this request to the Tasks controller's edit action, and passes the value of the id to the first parameter of the edit action. If we check the edit action, we will notice that it accepts a parameter named $id. The task id passed in the URL is stored in this parameter. When a request is made to the edit action, the first thing that it does is to check if any id has been supplied or not. To let users edit a task, it needs to know which task the user wants to edit. It cannot continue if there is no id supplied. So, if $id is undefined, it stores an error message to the session and redirects to the index action that will show the list of current tasks along with the error message. If $id is defined, the edit action then checks whether there is any data stored in $this->data. If no data is stored in $this->data, it means that the user has not yet edited. And so, the desired task is fetched from the Task model, and stored in $this->data in the line: $this->data = $this->Task->find(array('id' => $id)); Once that is done, the view of the edit action is then rendered, displaying the task information. The view fetches the task information to be displayed from $this->data. The view of the edit action is very similar to that of the add action with a single difference. It has an extra line with echo $form->hidden('id');. This creates an HTML hidden input with the value of the task id that is being edited. Once the user edits the task and clicks on the Save button, the edited data is resent to the edit action and saved in $this->data. Having data in $this->data confirms that the user has edited and submitted the changed data. Thus, if $this->data is not empty, the edit action then tries to save the data by calling the Task Model's save() function: $this->Task->save($this->data). This is the same function that we used to add a new task in the add action. You may ask how does the save() function of model knows when to add a new record and when to edit an existing one? If the form data has a hidden id field, the function knows that it needs to edit an existing record with that id. If no id field is found, the function adds a new record. Once the data has been successfully updated, a success message is stored in the session and it redirects to the index action. Of course the index page will show the success message. Adding Data Validation If you have come this far, by now you should have a working CakeTooDoo. It has the ability to add a task, list all the tasks with their statuses, and edit a task to change its status and title. But, we are still not happy with it. We want the CakeTooDoo to be a quality application, and making a quality application with CakePHP is as easy as eating a cake. A very important aspect of any web application (or software in general), is to make sure that the users do not enter inputs that are invalid. For example, suppose a user mistakenly adds a task with an empty title, this is not desirable because without a title we cannot identify a task. We would want our application to check whether the user enters title. If they do not enter a title, CakeTooDoo should not allow the user to add or edit a task, and should show the user a message stating the problem. Adding these checks is what we call Data Validation. No matter how big or small our applications are, it is very important that we have proper data validation in place. But adding data validation can be a painful and time consuming task. This is especially true, if we have a complex application with lots of forms. Thankfully, CakePHP comes with a built-in data validation feature that can really make our lives much easier. Time for Action: Adding Data Validation to Check for Empty Title In the Task model that we created in /CakeTooDoo/app/models, add the following code inside the Task Model class. The Task Model will look like this: <?php class Task extends AppModel { var $name = 'Task'; var $validate = array( 'title' => array( 'rule' => VALID_NOT_EMPTY, 'message' => 'Title of a task cannot be empty' ) ); } ?> Now open the Add Task form in the browser by pointing it to http://localhost/CakeTooDoo/tasks/add, and try to add a task with an empty title. It will show the following error message:
Read more
  • 0
  • 0
  • 1709

article-image-build-advanced-contact-manager-using-jboss-richfaces-33-part-2
Packt
18 Nov 2009
10 min read
Save for later

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 2

Packt
18 Nov 2009
10 min read
The contact detail For the third column, we would like to show three different statuses: The "No contact selected" message when no contact is selected (so the property is null) A view-only box when we are not in the edit mode (the property selectedContactEditing is set to false) An edit box when we are in the edit mode (the property selectedContactEditing is set to true) So, let's open the home.xhtml page and insert the third column inside the panel grid with the three statuses: <a:outputPanel id="contactDetail"> <a:outputPanel rendered="#{homeSelectedContactHelper. selectedContact==null}"> <rich:panel> <h:outputText value="#{messages['noContactSelected']}"/> </rich:panel></a:outputPanel> <a:outputPanel rendered="#{homeSelectedContactHelper. selectedContact!=null and homeSelectedContactHelper. selectedContactEditing==false}"> <ui:include src="main/contactView.xhtml"/> </a:outputPanel> <a:outputPanel rendered="#{homeSelectedContactHelper. selectedContact!=null and homeSelectedContactHelper. selectedContactEditing==true}"> <ui:include src="main/contactEdit.xhtml"/> </a:outputPanel></a:outputPanel> Here, we have put the main a:outputPanel as the main placeholder, and inside it we put three more instances of a:outputPanel (one for every state) with the rendered attribute in order to decide which one to show. The first one just shows a message when homeSelectedContactHelper.selectedContact is set to null: The second instance of a:outputPanel will include the main/contactView.xhtml file only if homeSelectedContactHelper.selectedContact is not null, and we are not in editing mode (so homeSelectedContactHelper.selectedContactEditing is set to false); the third one will be shown only if homeSelectedContactHelper.selectedContact is not null, and we are in the edit mode (that is homeSelectedContactHelper.selectedContactEditing is equal to true). Before starting to write the include sections, let's see how the main bean for the selected contact would look, and connect it with the data table for selecting the contact from it. The support bean Let's create a new class called HomeSelectedContactHelper inside the book.richfaces.advcm.modules.main package; the class might look like this: @Name("homeSelectedContactHelper")@Scope(ScopeType.CONVERSATION)public class HomeSelectedContactHelper { @In(create = true) EntityManager entityManager; @In(required = true) Contact loggedUser; @In FacesMessages facesMessages; // My code here} This is a standard JBoss Seam component and  now let's add the properties. The bean that we are going to use for view and edit features is very simple to understand—it just contains two properties (namely selectedContact and selectedContactEditing) and some action methods to manage them. Let's add the properties to our class: private Contact selectedContact;private Boolean selectedContactEditing;public Contact getSelectedContact() { return selectedContact;}public void setSelectedContact(Contact selectedContact) { this.selectedContact = selectedContact;}public Boolean getSelectedContactEditing() { return selectedContactEditing;}public void setSelectedContactEditing(Boolean selectedContactEditing) { this.selectedContactEditing = selectedContactEditing;} As you can see, we just added two properties with standard the getter and setter. Let's now see the action methods: public void createNewEmptyContactInstance() { setSelectedContact(new Contact());}public void insertNewContact() { // Attaching the owner of the contact getSelectedContact().setContact(loggedUser); entityManager.persist(getSelectedContact()); facesMessages.addFromResourceBundle(StatusMessage.Severity.INFO,  "contactAdded");}public void saveContactData() { entityManager.merge(getSelectedContact()); facesMessages.addFromResourceBundle(StatusMessage.Severity.INFO, "contactSaved");}public void deleteSelectedContact() { entityManager.remove(getSelectedContact()); // De-selecting the current contact setSelectedContact(null); setSelectedContactEditing(null); facesMessages.addFromResourceBundle(StatusMessage.Severity.INFO, "contactDeleted");}public boolean isSelectedContactManaged() { return getSelectedContact() != null && entityManager.contains (getSelectedContact());} It's not difficult to understand what they do, however, in order to be clear, we are going to describe what each method does. The method createNewEmptyContactInstance() simply sets the selectedContact property with a new instance of the Contact class—it will be called by the "add contact" button. After the user has clicked on the "add contact" button and inserted the contact data, he/she has to persist this new instance of data into the database. It is done by the insertNewContact() method, called when he/she clicks on the Insert button. If the user edits a contact and clicks on the "Save" button, the saveContactData() method will be called, in order to store the modifications into the database. As for saving, the deleteSelectedContact() method will be called by the "Delete" button, in order to remove the instance from the database. A special mention for the isSelectedContactManaged() method—it is used to determine if the selectedContact property contains a bean that exists in the database (so, I'm editing it), or a new instance not yet persisted to the database. We use it especially in rendered properties, in order to determine which component to show (you will see this in the next section). Selecting the contact from the contacts list We will use the contacts list in order to decide which contact must be shown in the detail view. The simple way is to add a new column into the dataTable, and put a command button (or link) to select the bean in order to visualize the detail view. Let's open the contactsList.xhtml file and add another column as follows: <rich:column width="10%" style="text-align: center"> <a:commandButton image="/img/view.png" reRender="contactDetail"> <f:setPropertyActionListener value="#{contact}" target="#{homeSelectedContactHelper.selectedContact}"/> <f:setPropertyActionListener value="#{false}" target="#{homeSelectedContactHelper.selectedContactEditing}"/> </a:commandButton></rich:column> Inside the column, we added the a:commandButton component (that shows an image instead of the standard text) that doesn't call any action—it uses the f:setPropertyAction method to set the homeSelectedContactHelper.selectedContact value to contact (the row value of the dataTable), and to tell to show the view box and not the edit one (setting homeSelectedContactHelper.selectedContactEditing to false). After the Ajax call, it will re-render the contactDetail box in order to reflect the change. Also, the header must be changed to reflect the column add: <rich:dataTable ... > <f:facet name="header"> <rich:columnGroup> <rich:column colspan="3"> <h:outputText value="Contacts"/> </rich:column> <rich:column breakBefore="true"> <h:outputText value="Name"/> </rich:column> <rich:column> <h:outputText value="Surname"/> </rich:column> <rich:column> <rich:spacer/> </rich:column> </rich:columnGroup> </f:facet> ... We incremented the colspan attribute value and added a new (empty) column header. The new contacts list will look like the following screenshot: Adding a new contact Another feature we would like to add to the contacts list is the "Add contact" button. In order to do that, we are going to use the empty toolbar. Let's add a new action button into the rich:toolbar component: <a:commandButton image="/img/addcontact.png" reRender="contactDetail"action="#{homeSelectedContactHelper.createNewEmptyContactInstance}"> <f:setPropertyActionListener value="#{true}"target="#{homeSelectedContactHelper.selectedContactEditing}"/></a:commandButton> This button will call the homeSelectedContactHelper.createNewEmptyContactInstance() action method in order to create and select an empty instance and will set homeSelectedContactHelper.selectedContactEditing to true in order to start the editing; after those Ajax calls, it will re-render the contactDetail box to reflect the changes. Viewing contact detail We are ready to implement the view contact detail box; just open the /view/main/contactView.xhtml file and add the following code: <h:form> <rich:panel> <f:facet name="header"> <h:outputText value="#{homeSelectedContactHelper.selectedContact.name} #{homeSelectedContactHelper.selectedContact.surname}"/> </f:facet> <h:panelGrid columns="2" rowClasses="prop" columnClasses="name,value"> <h:outputText value="#{messages['name']}:"/> <h:outputText value="#{homeSelectedContactHelper.selectedContact.name}"/> <h:outputText value="#{messages['surname']}:"/> <h:outputText value="#{homeSelectedContactHelper.selectedContact.surname}"/> <h:outputText value="#{messages['company']}:"/> <h:outputText value="#{homeSelectedContactHelper.selectedContact.company}"/> <h:outputText value="#{messages['email']}:"/> <h:outputText value="#{homeSelectedContactHelper.selectedContact.email}"/> </h:panelGrid> </rich:panel> <rich:toolBar> <rich:toolBarGroup> <a:commandLink ajaxSingle="true" reRender="contactDetail" styleClass="image-command-link"> <f:setPropertyActionListener value="#{true}" target="#{homeSelectedContactHelper.selectedContactEditing}"/> <h:graphicImage value="/img/edit.png" /> <h:outputText value="#{messages['edit']}" /> </a:commandLink> </rich:toolBarGroup> </rich:toolBar></h:form> The first part is just rich:panel containing h:panelGrid with the fields' detail. In the second part of the code, we put rich:toolBar containing a command link (with an image and a text) that activates the edit mode—it, in fact, just sets the homeSelectedContactHelper.selectedContactEditing property to true and re-renders contactDetail in order to make it appear in the edit box. We also added a new CSS class into the /view/stylesheet/theme.css file to manage the layout of command links with images: .image-command-link { text-decoration: none;}.image-command-link img { vertical-align: middle; padding-right: 3px;} The view box looks like: We are now ready to develop the edit box. Editing contact detail When in the edit mode, the content of the /view/main/contactEdit.xhtml file will be shown in the contact detail box—let's open it for editing. Let's add the code for creating the main panel: <h:form> <rich:panel> <f:facet name="header"> <h:panelGroup> <h:outputText value="#{homeSelectedContactHelper.selectedContact.name} #{homeSelectedContactHelper.selectedContact.surname}"rendered="#{homeSelectedContactHelper.selectedContactManaged}"/> <h:outputText value="#{messages['newContact']}"rendered="#{!homeSelectedContactHelper.selectedContactManaged}"/> </h:panelGroup> </f:facet> <!-- my code here --> </rich:panel><!-- my code here --></h:form> This is a standard rich:panel with a customized header—it has two h:outputText components that will be shown depending on the rendered attribute (whether it's a new contact or not). More than one component inside f:facetRemember that f:facet must have only one child, so, to put more than one component, you have to use a surrounding one like h:panelGroup or something similar. Inside the panel, we are going to put h:panelGrid containing the components for data editing: <rich:graphValidator> <h:panelGrid columns="3" rowClasses="prop" columnClasses="name,value,validatormsg"> <h:outputLabel for="scName" value="#{messages['name']}:"/> <h:inputText id="scName" value="#{homeSelectedContactHelper.selectedContact.name}"/> <rich:message for="scName" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> <h:outputLabel for="scSurname" value="#{messages['surname']}:"/> <h:inputText id="scSurname" value="#{homeSelectedContactHelper.selectedContact.surname}"/> <rich:message for="scSurname" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> <h:outputLabel for="scCompany" value="#{messages['company']}:"/> <h:inputText id="scCompany" value="#{homeSelectedContactHelper.selectedContact.company}"/> <rich:message for="scCompany" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> <h:outputLabel for="scEmail" value="#{messages['email']}:"/> <h:inputText id="scEmail" value="#{homeSelectedContactHelper.selectedContact.email}"/> <rich:message for="scEmail" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> </h:panelGrid><rich:graphValidator> Nothing complicated here, we've just used h:outputLabel, h:inputText, and rich:message for every Contact property to be edited; it appears as follows:
Read more
  • 0
  • 0
  • 817
article-image-create-quick-application-cakephp-part-1
Packt
17 Nov 2009
9 min read
Save for later

Create a Quick Application in CakePHP: Part 1

Packt
17 Nov 2009
9 min read
The ingredients are fresh, sliced up, and in place. The oven is switched on, heated, and burning red. It is time for us to put on the cooking hat, and start making some delicious cake recipes. So, are you ready, baker? In this article, we are going to develop a small application that we'll call the "CakeTooDoo". It will be a simple to-do-list application, which will keep record of the things that we need to do. A shopping list, chapters to study for an exam, list of people you hate, and list of girls you had a crush on are all examples of lists. CakeTooDoo will allow us to keep an updated list. We will be able to view all the tasks, add new tasks, and tick the tasks that are done and much more. Here's another example of a to-do list, things that we are going to cover in this article: Make sure Cake is properly installed for CakeTooDoo Understand the features of CakeTooDoo Create and configure the CakeTooDoo database Write our first Cake model Write our first Cake controller Build a list that shows all the tasks in CakeTooDoo Create a form to add new tasks to CakeTooDoo Create another form to edit tasks in the to-do list Have a data validation rule to make sure users do not enter empty task title Add functionality to delete a task from the list Make separate lists for completed and pending Tasks Make the creation and modification time of a task look nicer Create a homepage for CakeTooDoo Making Sure the Oven is Ready Before we start with CakeTooDoo, let's make sure that our oven is ready. But just to make sure that we do not run into any problem later, here is a check list of things that should already be in place: Apache is properly installed and running in the local machine. MySQL database server is installed and running in the local machine. PHP, version 4.3.2 or higher, is installed and working with Apache. The latest 1.2 version of CakePHP is being used. Apache mod_rewrite module is switched on. AllowOverride is set to all for the web root directory in the Apache configuration file httpd.conf. CakePHP is extracted and placed in the web root directory of Apache. Apache has write access for the tmp directory of CakePHP. In this case, we are going to rename the Cake directory to it CakeTooDoo. CakeTooDoo: a Simple To-do List Application As we already know, CakeTooDoo will be a simple to-do list. The list will consist of many tasks that we want to do. Each task will consist of a title and a status. The title will indicate the thing that we need to do, and the status will keep record of whether the task has been completed or not. Along with the title and the status, each task will also record the time when the task has been created and last modified. Using CakeTooDoo, we will be able to add new tasks, change the status of a task, delete a task, and view all the tasks. Specifically, CakeTooDoo will allow us to do the following things: View all tasks in the list Add a new task to the list Edit a task to change its status View all completed tasks View all pen Delete a task A homepage that will allow access to all the features. You may think that there is a huge gap between knowing what to make and actually making it. But wait! With Cake, that's not true at all! We are just 10 minutes away from the fully functional and working CakeTooDoo. Don't believe me? Just keep reading and you will find it out yourself. Configuring Cake to Work with a Database The first thing we need to do is to create the database that our application will use. Creating database for Cake applications are no different than any other database that you may have created before. But, we just need to follow a few simple naming rules or conventions while creating tables for our database. Once the database is in place, the next step is to tell Cake to use the database. Time for Action: Creating and Configuring the Database Create a database named caketoodoo in the local machine's MySQL server. In your favourite MySQL client, execute the following code: CREATE DATABASE caketoodoo; In our newly created database, create a table named tasks, by running the following code in your MySQL client: USE caketoodoo; CREATE TABLE tasks ( id int(10) unsigned NOT NULL auto_increment, title varchar(255) NOT NULL, done tinyint(1) default NULL, created datetime default NULL, modified datetime default NULL, PRIMARY KEY (id) ); Rename the main cake directory to CakeTooDoo, if you haven't done that yet. Move inside the directory CakeTooDoo/app/config. In the config directory, there is a file named database.php.default. Rename this file to database.php. Open the database.php file with your favourite editor, and move to line number 73, where we will find an array named $default. This array contains database connection options. Assign login to the database user you will be using and password to the password of that user. Assign database to caketoodoo. If we are using the database user ahsan with password sims, the configuration will look like this: var $default = array( 'driver' => 'mysql', 'persistent' => false, 'host' => 'localhost', 'port' => '', 'login' => 'ahsan', 'password' => 'sims', 'database' => 'caketoodoo', 'schema' => '', 'prefix' => '', 'encoding' => '' ); Now, let us check if Cake is being able to connect to the database. Fire up a browser, and point to http://localhost/CakeTooDoo/. We should get the default Cake page that will have the following two lines: Your database configuration file is present and Cake is able to connect to the database, as shown in the following screen shot. If you get the lines, we have successfully configured Cake to use the caketoodoo database. What Just Happened? We just created our first database, following Cake convention, and configured Cake to use that database. Our database, which we named caketoodoo, has only one table named task. It is a convention in Cake to have plural words for table names. Tasks, users, posts, and comments are all valid names for database tables in Cake. Our table tasks has a primary key named id. All tables in Cake applications' database must have id as the primary key for the table. Conventions in CakePHPDatabase tables used with CakePHP should have plural names. All database tables should have a field named id as the primary key of the table. We then configured Cake to use the caketoodoo database. This was achieved by having a file named database.php in the configuration directory of the application. In database.php, we set the default database to caketoodoo. We also set the database username and password that Cake will use to connect to the database server. Lastly, we made sure that Cake was able to connect to our database, by checking the default Cake page. Conventions in Cake are what make the magic happen. By favoring convention over configuration, Cake makes productivity increase to a scary level without any loss to flexibility. We do not need to spend hours setting configuration values to just make the application run. Setting the database name is the only configuration that we will need, everything else will be figured out "automagically" by Cake. Throughout this article, we will get to know more conventions that Cake follows.   Writing our First Model Now that Cake is configured to work with the caketoodoo database, it's time to write our first model. In Cake, each database table should have a corresponding model. The model will be responsible for accessing and modifying data in the table. As we know, our database has only one table named tasks. So, we will need to define only one model. Here is how we will be doing it: Time for Action: Creating the Task Model Move into the directory CakeTooDoo/app/models. Here, create a file named task.php. In the file task.php, write the following code: <?php class Task extends AppModel { var $name = 'Task'; } ?> Make sure there are no white spaces or tabs before the <?php tag and after the ?> tag. Then save the file. What Just Happened? We just created our first Cake model for the database table tasks. All the models in a CakePHP application are placed in the directory named models in the app directory. Conventions in CakePHP: All model files are kept in the directory named models under the app directory. Normally, each database table will have a corresponding file (model) in this directory. The file name for a model has to be singular of the corresponding database table name followed by the .php extension. The model file for the tasks database table is therefore named task.php. Conventions in CakePHP: The model filename should be singular of the corresponding database table name. Models basically contain a PHP class. The name of the class is also singular of the database table name, but this time it is CamelCased. The name of our model is therefore Task. Conventions in CakePHP: A model class name is also singular of the name of the database table that it represents. You will notice that this class inherits another class named AppModel. All models in CakePHP must inherit this class. The AppModel class inherits another class called Model. Model is a core CakePHP class that has all the basic functions to add, modify, delete, and access data from the database. By inheriting this class, all the models will also be able to call these functions, thus we do not need to define them separately each time we have a new model. All we need to do is to inherit the AppModel class for all our models. We then defined a variable named $name in the Task'model, and assigned the name of the model to it. This is not mandatory, as Cake can figure out the name of the model automatically. But, it is a good practice to name it manually.
Read more
  • 0
  • 0
  • 2647

article-image-apache-geronimo-logging
Packt
16 Nov 2009
8 min read
Save for later

Apache Geronimo Logging

Packt
16 Nov 2009
8 min read
We will start by briefly looking at each of the logging frameworks mentioned above, and will then go into how the server logs events and errors and where it logs them to. After examining them, we will look into the different ways in which we can configure application logging. Apache log4j: Log4j is an open source logging framework that is developed by the Apache Software Foundation. It provides a set of loggers, appenders, and layouts, to control which messages should be logged at runtime, where they should be logged to, and in what format they should be logged. The loggers are organized in a tree hierarchy, starting with the root logger at the top of the hierarchy. All loggers except the root logger are named entities and can be retrieved by their names. The root logger can be accessed by using the Logger.getRootLogger() API, while all other loggers can be accessed by using the Logger.getLogger() API. The names of the loggers follow the rule that the name of the parent logger followed by a '.' is a prefix to the child logger's name. For example, if com.logger.test is the name of a logger, then its direct ancestor is com.logger, and the prior ancestor is com. Each of the loggers may be assigned levels. The set of possible levels in an ascending order are—TRACE, DEBUG, INFO, WARN, ERROR, and FATAL. If a logger is not assigned a level, then it inherits its level from its closest ancestor. A log statement makes a logging request to the log4j subsystem. This request is enabled only if its logging level is higher than or equal to its logger's level. If it is lower than the log, then the message is not output through the configured appenders. Log4j allows logs to be output to multiple destinations. This is done via different appenders. Currently there are appenders for the console, files, GUI components, JMS destinations, NT, and Unix system event loggers and remote sockets. Log4j is one of the most widely-used logging frameworks for Java applications, especially ones running on application servers. It also provides more features than the other logging framework that we are about to see, that is, the Java Logging API. Java Logging API: The Java Logging API, also called JUL, from the java.util.logging package name of the framework, is another logging framework that is distributed with J2SE from version 1.4 onwards. It also provides a hierarchy of loggers such as log4j, and the inheritance of properties by child loggers from parents just like log4j. It provides handlers for handling output, and formatters for configuring the way that the output is displayed. It provides a subset of the functionality that log4j provides, but the advantage is that it is bundled with the JRE, and so does not require the application to include third-party JARS as log4j does. SLF4J: The Simple Logging Facade for Java or SLF4J is an abstraction or facade over various logging systems. It allows a developer to plug in the desired logging framework at deployment time. It also supports the bridging of legacy API calls through the slf4j API, and to the underlying logging implementation. Versions of Apache Geronimo prior to 2.0 used Apache Commons logging as the facade or wrapper. However, commons logging uses runtime binding and a dynamic discovery mechanism, which came to be the source of quite a few bugs. Hence, Apache Geronimo migrated to slf4j, which allows the developer to plug in the logging framework during deployment, thereby eliminating the need for runtime binding. Configuring Apache Geronimo logging Apache Geronimo uses slf4j and log4j for logging. The log4j configuration files can be found in the <GERONIMO_HOME>/var/log directory. There are three configuration files that you will find in this directory, namely: client-log4j.properties deployer-log4j.properties server-log4j.properties Just as they are named, these files configure log4j logging for the client container (Java EE application client), deployer system, and the server. You will also find the corresponding log files—client.log, deployer.log, and server.log. The properties files, listed above, contain the configuration of the various appenders, loggers, and layouts for the server, deployer, and client. As mentioned above, log4j provides a hierarchy of loggers with a granularity ranging from the entire server to each class on the server. Let us examine one of the configuration files: the server-log4j.properties file: This file starts with the line log4j.rootLogger=INFO, CONSOLE, FILE. This means that the log4j root logger has a level of INFO and writes log statements to two appenders, namely, the CONSOLE appender and the FILE appender. These are the appenders that write to the console and to files respectively. The console appender and file appenders are configured to write to System.out and to <GERONIMO_HOME>/var/log/geronimo.log. Below this section, there is a finer-grained configuration of loggers at class or package levels. For example, log4j.logger.openjpa.Enhance=TRACE. It configures the logger for the class log4j.logger.openjpa.Enhance to the TRACE level. Note that all of the classes that do not have a log level defined will take on the log level of their parents. This applies recursively until we reach the root logger and inherit its log level (INFO in this case). Configuring application logging We will be illustrating how applications can log messages in Geronimo by using two logging frameworks, namely, log4j and JUL. We will also illustrate how you can use the slf4j wrapper to log messages with the above two underlying implementations. We will be using a sample application, namely, the HelloWorld web application to illustrate this. Using log4j We can use log4j for logging the application log to either a separate logfile or to the geronimo.log file. We will also illustrate how the logs can be written to a separate file in the <GERONIMO_HOME>/var/log directory, by using a GBean. Logging to the geronimo.log file and the command console Logging to the geronimo.log file and the command console is the simplest way to do application logging in Geronimo. For enabling this in your application, you only need to add logging statements to your application code. The HelloWorld sample application has a servlet called HelloWorldServlet, which has the following statements for enabling logging. The servlet is shown below. package com.packtpub.hello;import java.io.*;import javax.servlet.ServletException;import javax.servlet.http.*;import org.apache.log4j.Logger;public class HelloWorldServlet extends HttpServlet{ Logger logger = Logger.getLogger(HelloWorldServlet.class.getName()); protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); out.print("<html>"); logger.info("Printing out <html>"); out.print("<head><title>Hello World Application</title></head>"); logger.info("Printing out <head><title>Hello World Application</title></head>"); out.print("<body>"); logger.info("Printing out <body>"); out.print("<b>Hello World</b><br>"); logger.info("Printing out <b>Hello World</b><br>"); out.print("</body>"); logger.info("Printing out </body>"); out.print("</html>"); logger.info("Printing out </html>"); logger.warn("Sample Warning message"); logger.error("Sample error message"); }} Deploy the sample HelloWorld-1.0.war file, and then access http://localhost:8080/HelloWorld/. This servlet will log the following messages in the command console, as shown in the image below: The geronimo.log file will have the following entries: 2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out <html>2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out <head><title>Hello World Application</title></head>2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out <body>2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out <b>Hello World</b><br>2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out </body>2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out </html>2009-02-02 20:01:38,906 WARN [HelloWorldServlet] Sample Warning message2009-02-02 20:01:38,906 ERROR [HelloWorldServlet] Sample error message Notice that only the messages with a logging level of greater than or equal to WARN are being logged to the command console, while all the INFO, ERROR, and WARN messages are logged to the geronimo.log file. This is because in server-log4j.properties the CONSOLE appender's threshold is set to the value of the system property, org.apache.geronimo.log.ConsoleLogLevel, as shown below: log4j.appender.CONSOLE.Threshold=${org.apache.geronimo.log.ConsoleLogLevel} The value of this property is, by default, WARN. All of the INFO messages are logged to the logfile because the FILE appender has a lower threshold, of TRACE, as shown below: log4j.appender.FILE.Threshold=TRACE Using this method, you can log messages of different severity to the console and logfile to which the server messages are logged. This is done for operator convenience, that is, only high severity log messages, such as warnings and errors, are logged to the console, and they need the operator's attention. The other messages are logged only to a file.
Read more
  • 0
  • 0
  • 2230

article-image-geronimo-architecture-part-1
Packt
13 Nov 2009
8 min read
Save for later

Geronimo Architecture: Part 1

Packt
13 Nov 2009
8 min read
Inversion of Control and dependency injection Inversion of Control (IoC) is a design pattern used in software engineering that facilitates the creation of loosely-coupled systems. In an IoC system, the flow of control is inverted, that is, the program is called by the framework—unlike in normal linear systems where the program calls the libraries. This allows us to circumvent the tight coupling that arises from the control being with the calling program. Dependency injection is a specific case of IoC where the framework provides an assembler or a configurator that provides the user program with the objects that it needs through injection. The user program declares dependencies on other services (provided by the framework or other user programs), and the assembler injects the dependencies into the user program wherever they are needed. It is important that you clearly understand the concept of dependency injection before we proceed further into the Geronimo architecture, as that is the core concept behind the functioning of the Geronimo kernel and how services are loosely coupled in it. To help you understand the concept more clearly, we will provide a simple example. Consider the following two classes: package packtsamples;public class RentCalculator{ private float rentRate; private TaxCalculator tCalc; public RentCalculator(float rate, float taxRate){ rentRate = rate; tCalc = new ServiceTaxCalculator(taxRate); } public void calculateRent(int noOfDays){ float totalRent = noOfDays * rentRate; float tax = tCalc.calculateTax(totalRent); totalRent = totalRent + tax; System.out.println("Rent is:"+totalRent); }}package packtsamples;public class ServiceTaxCalculator implements TaxCalculator{ private float taxRate; public ServiceTaxCalculator(float rate){ taxRate = rate; } public float calculateTax(float amount){ return (amount * taxRate/100); }}package packtsamples;public interface TaxCalculator{ public float calculateTax(float amount);}package packtsamples;public class Main { /** * @param args. args[0] = taxRate, args[1] = rentRate, args[2] =noOfDays */ public static void main(String[] args) { RentCalculator rc = new RentCalculator(Float.parseFloat(args[1]),Float.parseFloat(args[0])); rc.calculateRent(Integer.parseInt(args[2])); }} The RentCalculator class calculates the room rent including tax, given the rent rate, and the number of days. The TaxCalculator class calculates the tax on a particular amount, given the tax rate. As you can see from the code snippet given, the RentCalculator class is dependent on the TaxCalculator interface for calculating the tax. In the given sample, the ServiceTaxCalculator class is instantiated inside the RentCalculator class. This makes the two classes tightly coupled, so that we cannot use the RentCalculator with another TaxCalculator implementation. This problem can be solved through dependency injection. If we apply this concept to the previous classes, then the architecture will be slightly different. This is shown in the following code block:> package packtsamples.di;public class RentCalculator{ private float rentRate; private TaxCalculator tCalc; public RentCalculator(float rate, TaxCalculator tCalc){ rentRate = rate; this.tCalc = tCalc; } public void calculateRent(int noOfDays){ float totalRent = noOfDays * rentRate; float tax = tCalc.calculateTax(totalRent); totalRent = totalRent + tax; System.out.println("Rent is:" +totalRent); }}package packtsamples.di;public class ServiceTaxCalculator implements TaxCalculator{ private float taxRate; public ServiceTaxCalculator(float rate){ taxRate = rate; } public float calculateTax(float amount){ return (amount * taxRate/100); }}package packtsamples.di;public interface TaxCalculator{ public float calculateTax(float amount);} Notice the difference here from the previous implementation. The RentCalculator class has a TaxCalculator argument in its constructor. The RentCalculator then uses this TaxCalculator instance to calculate tax by calling the calculateTax method. You can pass in any implementation, and its calculateTax method will be called. In the following section, we will see how to write the class that will assemble this sample into a working program. package packtsamples.di;import java.lang.reflect.InvocationTargetException;public class Assembler { private TaxCalculator createTaxCalculator(String className, float taxRate){ TaxCalculator tc = null; try { Class cls = Class.forName(className); tc = (TaxCalculator)cls.getConstructors()[0] .newInstance(taxRate); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return tc; } private RentCalculator createRentCalculator(float rate, TaxCalculator tCalc){ return new RentCalculator(rate,tCalc); } private void assembleAndExecute(String className, float taxRate, float rentRate, int noOfDays){ TaxCalculator tc = createTaxCalculator(className, taxRate); createRentCalculator(rentRate, tc).calculateRent(noOfDays);} /** * * @param args args[0] = className, args[1] = taxRate args[2] = rentRate args[3] = noOfDays */ public static void main(String[] args){ new Assembler().assembleAndExecute(args[0], Float.parseFloat(args[1]), Float.parseFloat(args[2]), Integer.parseInt(args[3])); }} In the given sample code, you can see that there is a new class called the Assembler. The Assembler, in its main method, invokes the implementation class of TaxCalculator that we want RentCalculator to use. The Assembler then instantiates an instance of RentCalculator, injects the TaxCalculator instance of the type we specify into it, and calls the calculateRent method. Thus the two classes are not tightly coupled and the program control lies with the assembler, unlike in the previous case. Thus there is Inversion of Control happening here, as the framework (Assembler in this case) is controlling the execution of the program. This is a very trivial sample. We can write an assembler class that is more generic and is not even coupled to the interface as in the previous case. This is an example of dependency injection. An injection of this type is called constructor injection, where the assembler injects values through the constructor. You can also have other types of dependency injection, namely setter injection and field injection. In the former, the values are injected into the object by invoking the setter methods that are provided by the class, and in the latter, the values are injected into fields through reflection or some other method. The Apache Geronimo kernel uses both setter injection and constructor injection for resolving dependencies between the different modules or configurations that are deployed in it. The code for these examples is provided under di-sample in the samples. To build the sample, use the following command: mvn clean install To run the sample without dependency injection, use the following command: java –cp di-sample-1.0.jar packtsamples.Main <taxRate> <rentRate><noOfDays> To run the sample with dependency injection, use the following command: java –cp di-sample-1.0.jar packtsamples.Assembler packtsamples.di.ServiceTaxCalculator <taxRate> <rentRate> <noOfDays> GBeans A GBean is the basic unit in Apache Geronimo. It is a wrapper that is used to wrap or implement different services that are deployed in the kernel. GBeans are similar to MBeans from JMX. A GBean has attributes that store its state and references to other GBeans, and can also register dependencies on other GBeans. GBeans also have lifecycle callback methods and metadata. The Geronimo architects decided to invent the concept of GBeans instead of using MBeans in order to keep the Geronimo architecture independent from JMX. This ensured that they did not need to push in all of the functionality required for the IoC container (that forms Geronimo kernel) into the JMX implementation. Even though GBeans are built on top of MBeans, they can be moved to some other framework as well. A user who is writing a GBean has to follow certain conventions. A sample GBean is shown below: import org.apache.geronimo.gbean.GBeanInfo;import org.apache.geronimo.gbean.GBeanInfoBuilder;import org.apache.geronimo.gbean.GBeanLifecycle;public class TestGBean implements GBeanLifecycle{ private String name; public TestGBean(String name){ this.name = name; } public void doFail() { System.out.println("Failed............."); } public void doStart() throws Exception { System.out.println("Started............"+name); } public void doStop() throws Exception { System.out.println("Stopped............"+name); } public static final GBeanInfo GBEAN_INFO; static { GBeanInfoBuilder infoBuilder = GBeanInfoBuilder .createStatic(TestGBean .class, "TestGBean"); infoBuilder.setPriority(2); infoBuilder.addAttribute("name", String.class, true); infoBuilder.setConstructor(new String[]{"name"}); GBEAN_INFO = infoBuilder.getGBeanInfo(); } public static GBeanInfo getGBeanInfo() { return GBEAN_INFO; }} You will notice certain characteristics that this GBean has from the previous section. We will list these characteristics as follows: All GBeans should have a static getGBeanInfo method, which returns aGBeanInfo object that describes the attributes and references of GBean as well as the interfaces it can implement. All GBeans will have a static block where a GBeanInfoBuilder object is created and linked to that GBean. All of the metadata that is associated with this GBean is then added to the GBeanInfoBuilder object. The metadata includes descriptions of the attributes, references, interfaces, and constructors of GBean. We can add GBeans to configurations either programmatically, using methods exposed through the configuration manager and kernel, or by making an entry in the plan for the GBean, as follows: <gbean name="TestGBean" class="TestGBean"> <attribute name="name">Nitya</attribute></gbean> We need to specify the attribute values in the plan, and the kernel will inject those values into the GBean at runtime. There are three attributes for which we need not specify values. These are called the magic attributes, and the kernel will automatically inject these values when the GBeans are being started. These attributes are abstractName, kernel, and classLoader. As there is no way to specify the values of these attributes in the deployment plan (an XML file in which we provide Geronimo specific information while deploying a configuration), we need not specify them there. However, we should declare these attributes in the GBeanInfo and in the constructor. If the abstractName attribute is declared, then the Geronimo kernel will inject the abstractName of the GBean into it. If it is the kernel attribute, then a reference to the kernel that loaded this GBean is injected. If we declare classLoader, then the class loader for that configuration is injected.
Read more
  • 0
  • 0
  • 969
article-image-geronimo-architecture-part-2
Packt
13 Nov 2009
10 min read
Save for later

Geronimo Architecture: Part 2

Packt
13 Nov 2009
10 min read
Class loader architecture This section covers the class loader architecture for Apache Geronimo. The following image shows the class loader hierarchy for an application that is deployed in Apache Geronimo: The BootStrap class loader of the JVM is followed by the Extensions class loader and then the System class loader. The j2ee-system class loader is the primary class loader of Apache Geronimo. After the j2ee-system class loader, there are multiple other layers of class loaders before reaching the application class loaders. Applications have an application class loader, which loads any required application-level libraries and EJB modules. However, the web application packaged in the EAR will have its own class loader. The Administration Console has a ClassLoader Viewer portlet that can be used to view the class loader hierarchy as well as the classes loaded by each class loader. Modifying default class loading behavior In certain situations, we will need to follow a class loading strategy that is different from the default one that is provided by Apache Geronimo. A common situation where we need this functionality is when a parent configuration uses a library that is also used by the child and the library used by the parent is a different version, which is incompatible with the child's version of the library. In this case, if we follow the default class loading behavior, then we will always get the classes loaded by the parent configuration and will never be able to reference the classes in the library present in the child configuration. Apache Geronimo provides you with the ability to modify the default class loading behavior at the configuration level to handle such scenarios. This is done by providing certain elements in the deployment plan which, if present, will change the class loading behavior. These elements and the changes in class loading behavior that they represent, are explained as follows: hidden-classes: This tag is used to hide classes that are loaded in parent class loaders, so that the child class loader loads its own copy. Similarly, we can use this tag to specify the resources that should be loaded from the configuration class loader. For example, consider the case where you have a module that needs to load its copy of log4j. The server also has its own copy used for logging that is loaded in the parent class loader. We can add the hidden-classes element in the deployment plan for that module so that it loads its own copy of log4j, and the server loaded version of log4j is hidden from it. non-overridable-classes: This element specifies the list of classes that can be loaded only from the parent configurations of this configuration. In other words, the classes specified in this element cannot be loaded by the current configuration's class loader. The non-overridable-classes element is for preventing applications from loading their own copies of classes that should always be loaded from the parent class loaders, such as the Java EE API classes. private-classes: The classes that are defined by this tag will not be visible to class loaders that are the children of the current class loader. These classes will be loaded either from the current class loader or from its parents. The same class loading behavior can be achieved by using the hidden-classes tag in all of the child class loaders. inverse-classloading: If this element is specified, then the standard class loading strategy will be reversed for this module. This in effect means that a class is first looked up from the current class loader and then from its parent. Thus, the class loader hierarchy is inverted. suppress-default-environment: This will suppress the environment that is created by the builder for this module or configuration. This is a rarely-used element and can have nasty side effects if it is used carelessly. Important modules In this section, we will list the important configurations in Apache Geronimo. We will group them according to the Apache or other open source projects that they wrap. Configurations that do not wrap any other open source project will be listed under the Geronimo section. Apache ActiveMQ   org.apache.geronimo.configs/activemqbroker/2.1.4/car Apache Axis org.apache.geronimo.configs/axis/2.1.4/car org.apache.geronimo.configs/axis-deployer/2.1.4/car Apache Axis2 org.apache.geronimo.configs/axis2-deployer/2.1.4/car org.apache.geronimo.configs/axis2-ejb/2.1.4/car org.apache.geronimo.configs/axis2-ejb-deployer/2.1.4/car Apache CXF org.apache.geronimo.configs/cxf/2.1.4/car org.apache.geronimo.configs/cxf-deployer/2.1.4/car org.apache.geronimo.configs/cxf-ejb/2.1.4/car org.apache.geronimo.configs/cxf-ejb-deployer/2.1.4/car Apache Derby org.apache.geronimo.configs/derby/2.1.4/car Apache Geronimo org.apache.geronimo.configs/client/2.1.4/car org.apache.geronimo.configs/client-deployer/2.1.4/car org.apache.geronimo.configs/client-security/2.1.4/car org.apache.geronimo.configs/client-transaction/2.1.4/car org.apache.geronimo.configs/clustering/2.1.4/car org.apache.geronimo.configs/connector-deployer/2.1.4/car org.apache.geronimo.configs/farming/2.1.4/car org.apache.geronimo.configs/hot-deployer/2.1.4/car org.apache.geronimo.configs/j2ee-deployer/2.1.4/car org.apache.geronimo.configs/j2ee-server/2.1.4/car org.apache.geronimo.configs/javamail/2.1.4/car org.apache.geronimo.configs/persistence-jpa10-deployer/2.1.4/car org.apache.geronimo.configs/sharedlib/2.1.4/car org.apache.geronimo.configs/transaction/2.1.4/car org.apache.geronimo.configs/webservices-common/2.1.4/car org.apache.geronimo.framework/client-system/2.1.4/car org.apache.geronimo.framework/geronimo-gbeandeployer/2.1.4/car org.apache.geronimo.framework/j2ee-security/2.1.4/car org.apache.geronimo.framework/j2ee-system/2.1.4/car org.apache.geronimo.framework/jee-specs/2.1.4/car org.apache.geronimo.framework/jmx-security/2.1.4/car org.apache.geronimo.framework/jsr88-cli/2.1.4/car org.apache.geronimo.framework/jsr88-deploymentfactory/2.1.4/car org.apache.geronimo.framework/offline-deployer/2.1.4/car org.apache.geronimo.framework/online-deployer/2.1.4/car org.apache.geronimo.framework/plugin/2.1.4/car org.apache.geronimo.framework/rmi-naming/2.1.4/car org.apache.geronimo.framework/server-securityconfig/2.1.4/car org.apache.geronimo.framework/shutdown/2.1.4/car org.apache.geronimo.framework/transformeragent/2.1.4/car org.apache.geronimo.framework/upgrade-cli/2.1.4/car Apache Yoko org.apache.geronimo.configs/j2ee-corba-yoko/2.1.4/car org.apache.geronimo.configs/client-corba-yoko/2.1.4/car Apache Jasper org.apache.geronimo.configs/jasper/2.1.4/car org.apache.geronimo.configs/jasper-deployer/2.1.4/car JaxWS org.apache.geronimo.configs/jaxws-deployer/2.1.4/car org.apache.geronimo.configs/jaxws-ejb-deployer/2.1.4/car JSR 88 org.apache.geronimo.configs/jsr88-earconfigurer/2.1.4/car org.apache.geronimo.configs/jsr88-jarconfigurer/2.1.4/car org.apache.geronimo.configs/jsr88-rarconfigurer/2.1.4/car org.apache.geronimo.configs/jsr88-warconfigurer/2.1.4/car Apache MyFaces org.apache.geronimo.configs/myfaces/2.1.4/car org.apache.geronimo.configs/myfaces-deployer/2.1.4/car Apache OpenEJB org.apache.geronimo.configs/openejb/2.1.4/car org.apache.geronimo.configs/openejb-corbadeployer/2.1.4/car org.apache.geronimo.configs/openejb-deployer/2.1.4/car Apache OpenJPA org.apache.geronimo.configs/openjpa/2.1.4/car Spring org.apache.geronimo.configs/spring/2.1.4/car Apache Tomcat6 org.apache.geronimo.configs/tomcat6/2.1.4/car org.apache.geronimo.configs/tomcat6-clusteringbuilder-wadi/2.1.4/car org.apache.geronimo.configs/tomcat6-clusteringwadi/2.1.4/car org.apache.geronimo.configs/tomcat6-deployer/2.1.4/car org.apache.geronimo.configs/tomcat6-no-ha/2.1.4/car Apache WADI org.apache.geronimo.configs/wadi-clustering/2.1.4/car GShell org.apache.geronimo.framework/gshell-framework/2.1.4/car org.apache.geronimo.framework/gshell-geronimo/2.1.4/car Apache XmlBeans org.apache.geronimo.framework/xmlbeans/2.1.4/car Apache Pluto org.apache.geronimo.plugins/pluto-support/2.1.4/car     If you check the configurations, then you will see that most of the components that make up Geronimo have a deployer configuration and a main configuration. The deployer configuration contains the GBeans that will deploy modules onto that component. For example, the openejb-deployer contains GBeans that implement the functionality to deploy an EJB module onto Apache Geronimo. For accomplishing this, the EJB JAR file and its corresponding deployment plan are parsed by the deployer and then converted into a format that can be understood by the OpenEJB subsystem. This is then deployed on the OpenEJB container. The main configuration will usually contain the GBeans that configure the container and also manage its lifecycle. Server directory structure It is important for a user or an administrator to understand the directory structure of a Geronimo server installation. The directory structure of a v2.1.4 server is shown in the following screenshot: Please note that the directory that we will be referring to as <GERONIMO_HOME> is the geronimo-tomcat6-javaee5-2.1.4 directory shown in the screenshot. The following are some important directories that you should be familiar with: The bin directory contains the command scripts and the JAR files required to start the server, stop the server, invoke the deployer, and start the GShell. The etc directory contains the configuration files for GShell. The schema directory contains Geronimo schemas. The var/config directory contains Geronimo configurations files. A Geronimo administrator or user can find most of the configuration information about the server here. The var/derby directory contains the database files for the embedded Derby database server. The var/log directory contains logging configuration and logfiles. The var/security directory contains user credential and grouping files. The var/security/keystores directory contains the cryptographic keystore files used for server SSL configuration. The following are some important configuration files under the Geronimo directory structure: config.xml: This file is located under the &ltGERONIMO_HOME>/var/config directory. This file preserves the information regarding GBean attributes and references that were overridden from the default values used at deployment time. config-substitutions.properties: This file is located under the &ltGERONIMO_HOME>/var/config directory. The property values specified in this file are used in expressions in config.xml. The property values in this file can be overridden by using a system property or environment variable with a property name that is prefixed with org.apache.geronimo.config.substitution. artifact_aliases.properties: This file is located under the &ltGERONIMO_HOME>/var/config directory. This file is used to substitute one module or configuration ID for another module or configuration ID. The entries in this file are of the form oldArtifactId=newArtifactId, for example default/mylib//jar=default/mylib/2.0/jar. Note that the version number in the old artifact ID may be omitted, but the version number in the new artifact ID must be specified. client_artifact_aliases.properties: This file is located under the &ltGERONIMO_HOME>/var/config directory. This file is used for artifact aliasing with application clients. server-log4j.properties: This file is located under the &ltGERONIMO_HOME>/var/log directory. This file contains the logging configuration for the server. deployer-log4j.properties: This file is located under the &ltGERONIMO_HOME>/var/log directory. This file contains the logging configuration for the deployer. client-log4j.properties: This file is located under the &ltGERONIMO_HOME>/var/log directory. This file contains the logging configuration for application clients. users.properties: This file is located under the &ltGERONIMO_HOME>/var/security directory. This file contains the authentication credentials for the server. groups.properties: This file is located under the &ltGERONIMO_HOME>/var/security directory. This file contains the grouping information for the users defined in users.properties Among the directories that contain sensitive information, such as user passwords, are var/security, var/derby, and var/config. These directories should be protected using operating system provided directory and file security.
Read more
  • 0
  • 0
  • 1236

article-image-geronimo-plugins
Packt
12 Nov 2009
11 min read
Save for later

Geronimo Plugins

Packt
12 Nov 2009
11 min read
Developing a plugin In this section, we will develop our very own plugin, the World Clock plugin. This is a very simple plugin that provides the time in different locales. We will go through all of the steps required to develop it from scratch. These steps are as follows: Creating the plugin project Generating the plugin project, using maven2 Writing the plugin interface and implementation Creating a deployment plan Installing the plugin Creating a plugin project There are many ways in which you can develop plugins. You can manually create all of the plugin artifacts and package them. We will use the easiest method, that is, by using Maven's geronimo-plugin-archetype. This will generate the plugin project with all of the artifacts with the default values filled in. To generate the plugin project, run the following command: mvn archetype:create -DarchetypeGroupId=org.apache.geronimo.buildsupport -DarchetypeArtifactId=geronimo-plugin-archetype -DarchetypeVersion=2.1.4 -DgroupId=com.packt.plugins -DartifactId=WorldClock This will create a plugin project called WorldClock. A directory called WorldClock will be created, with the following artifacts in it: pom.xml pom.sample.xml src/main/plan/plan.xml src/main/resources In the same directory in which the WorldClock directory is created, you will need to create a java project that will contain the source code of the plugin. We can create this by using the following command: mvn archetype:create -DgroupId=com.packt.plugins -DartifactId=WorldClockModule This will create a java project with the same groupId and artifactId in a directory called WorldClockModule. This directory will contain the following artifacts: pom.xml src/main/java/com/packt/plugins/App.java src/test/java/com/packt/plugins/AppTest.java You can safely remove the second and third artifacts, as they are just sample stubs generated by the archetype. In this project, we will need to modify the pom.xml to have a dependency on the Geronimo kernel, so that we can compile the GBean that we are going to create and include in this module. The modified pom.xml is shown below: <project xsi_schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.packt.plugins</groupId> <artifactId>WorldClockModule</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>WorldClockModule</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.geronimo.framework</groupId> <artifactId>geronimo-kernel</artifactId> <version>2.1.4</version> </dependency> </dependencies></project> For simplicity, we have only one GBean in our sample. In a real world scenario, there may be many GBeans that you will need to create. Now we need to create the GBean that forms the core functionality of our plugin. Therefore, we will create two classes, namely, Clock and ClockGBean. These classes are shown below: package com.packt.plugins;import java.util.Date;import java.util.Locale;public interface Clock { public void setTimeZone(String timeZone); public String getTime();} and package com.packt.plugins;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.util.GregorianCalendar;import java.util.Locale;import java.util.TimeZone;import org.apache.geronimo.gbean.GBeanInfo;import org.apache.geronimo.gbean.GBeanInfoBuilder;import org.apache.geronimo.gbean.GBeanLifecycle;import sun.util.calendar.CalendarDate;public class ClockGBean implements GBeanLifecycle, Clock{ public static final GBeanInfo GBEAN_INFO; private String name; private String timeZone; public String getTime() { GregorianCalendar cal = new GregorianCalendar(TimeZone. getTimeZone(timeZone)); int hour12 = cal.get(Calendar.HOUR); // 0..11 int minutes = cal.get(Calendar.MINUTE); // 0..59 int seconds = cal.get(Calendar.SECOND); // 0..59 boolean am = cal.get(Calendar.AM_PM) == Calendar.AM; return (timeZone +":"+hour12+":"+minutes+":"+seconds+":"+((am)? "AM":"PM")); } public void setTimeZone(String timeZone) { this.timeZone = timeZone; } public ClockGBean(String name){ this.name = name; timeZone = TimeZone.getDefault().getID(); } public void doFail() { System.out.println("Failed............."); } public void doStart() throws Exception { System.out.println("Started............"+name+" "+getTime()); } public void doStop() throws Exception { System.out.println("Stopped............"+name); } static { GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic ("ClockGBean",ClockGBean.class); infoFactory.addAttribute("name", String.class, true); infoFactory.addInterface(Clock.class); infoFactory.setConstructor(new String[] {"name"}); GBEAN_INFO = infoFactory.getBeanInfo(); } public static GBeanInfo getGBeanInfo() { return GBEAN_INFO; }} As you can see, Clock is an interface and ClockGBean  is a GBean that implements this interface. The Clock interface exposes the functionality that is provided by the ClockGBean. The doStart(),   doStop(), and doFail()  methods are provided by the GBeanLifeCycle interface, and provide lifecycle callback functionality. The next step is to run Maven to build this module. Go to the command prompt, and change the directory to the WorldClockModule directory. To build the module, run the following command: mvn clean install Once the build completes, you will find a WorldClockModule-1.0-SNAPSHOT.jar in the WorldClockModule/target directory. Now change the directory to WorldClock, and open the generated pom.xml file. You will need to uncomment the deploymentConfigs for the gbeanDeployer, and add the following module that you want to include in the plugin: <module> <groupId>com.packt.plugins</groupId> <artifactId>WorldClockModule</artifactId> <version>1.0</version> <type>jar</type></module> You will notice that we are using the car-maven-plugin in the pom.xml file. The car-maven-plugin is used to build Apache Geronimo configuration archives without starting the server. The final step is to create the deployment plan in order to deploy the module that we just created into the Apache Geronimo server. This deployment plan will be used by the car-maven-plugin to actually create the artifacts that will be created during deployment to Apache Geronimo. The deployment plan is shown below: <module > <environment> <moduleId> <groupId>com.packt.plugins</groupId> <artifactId>WorldClock</artifactId> <version>1.0</version> <type>car</type> </moduleId> <dependencies/> <hidden-classes/> <non-overridable-classes/> <private-classes/> </environment> <gbean name="ClockGBean" class="com.packt.clock.ClockGBean"> <attribute name="name">ClockGBean</attribute> </gbean></module> Once the plan is ready, go to the command prompt and change the directory to the WorldClock directory. Run the following command to build the plugin: mvn clean install You will notice that the car-maven-plugin is invoked and a WorldClock-1.0-SNAPSHOT.car file is created in the WorldClock/target directory. We have now completed the steps required to create an Apache Geronimo plugin. In the next section, we will see how we can install the plugin in Apache Geronimo. Installing a plugin We can install a plugin in three different ways. One way is to   use the deploy.bat or deploy.sh script, another way is to use the install-plugin command in GShell, and the third way is to use the Administration Console to  install a plugin from a plugin repository. We will discuss each of these methods: Using deploy.bat or deploy.sh file: The deploy.bat or deploy.sh script is found in the <GERONIMO_HOME>/bin directory. It has an option install-plugin, which can be used to install plugins onto the server. The command syntax is shown below: deploy install-plugin <path to the plugin car file> Running this command, and passing the path to the plugin .car archive on the disk, will result in the plugin being installed onto the Geronimo server. Once the installation has finished, an Installation Complete message will be displayed, and the command will exit. Using GShell: Invoke  the gsh command from the command prompt, after changing the current directory to <GERONIMO_HOME>/bin. This will bring up the GShell prompt. In the GShell prompt, type the following command to install the plugin: deploy/install-plugin <path to the plugin car file> Please note that, you should escape special characters in the path by using a leading "" (back slash) before the character. Another way to install plugins that are available in remote plugin repository is by using the list-plugins command. The syntax of this command is as given below: deploy/list-plugins <URI of the remote repository> If a remote repository is not specified, then the one configured in Geronimo will be used instead. Once this command has been invoked, the list of available plugins in the remote repository is shown, along with their serial numbers, and you will be prompted to enter a comma separated list of the serial numbers of the plugins that you want to install. Using the Administration Console: The Administration Console has a Plugins portlet that can be used to list the plugins available in a repository specified by the user. You can use the Administration Console to select and install the plugins that you want from this list. This portlet also has the capability to export applications or services in your server instance as Geronimo plugins, so that they can be installed on other server instances. See the Plugin portlet section for details of the usage of this portlet. Available plugins The  web  site http://geronimoplugins.com/ hosts Apache Geronimo plugins. It has many plugins listed for Apache Geronimo. There are plugins for Quartz, Apache Directory Server, and many other popular software packages. However, they are not always available for the latest versions of Apache Geronimo. A couple of fairly up-to-date plugins that are available for Apache Geronimo are the Windows Service Wrapper plugin and the Apache Tuscany plugin for Apache Geronimo. The Windows Service Wrapper provides the ability for Apache Geronimo to be registered as a windows service. The Tuscany plugin is an implementation of the SCA Java EE Integration specification by integrating Apache Tuscany as an Apache Geronimo plugin. Both of these plugins are available from the Apache Geronimo web site. Pluggable Administration Console Older versions of Apache Geronimo came with a monolithic Administration Console. However, the server was extendable through plugins. This introduced a problem: How to administer the new plugins that were added to the server? To resolve this problem, the Apache Geronimo developers rewrote the Administration Console to be extensible through console plugins called Administration Console Extensions. In this section, we will look into how to create an Administration Console portlet for the World Clock plugin that we developed in the previous section. Architecture The pluggable Administration Console functionality is based on the support provided by the Apache Pluto portlet container for dynamically adding and removing portlets and pages without requiring a restart. Apache Geronimo exposes this functionality through two GBeans, namely, the Administration Console Extension (ACE) GBean  (org.apache.geronimo.pluto.AdminConsoleExtensionGBean) and the Portal Container Services GBean (org.apache.geronimo.pluto. PortalContainerServicesGBean). The PortalContainerServicesGBean exposes the features of the Pluto container in order to add and remove portlets and pages at runtime. The ACE GBean invokes these APIs to add and remove the portlets or pages. The  ACE GBean should be specified in the Geronimo-specific deployment plan of your web application or plugin, that is, geronimo-web.xml. The architecture is shown in the following figure: Developing an Administration Console extension We will now go through the steps to develop an Administration Console Extension for the World Clock plugin that we created in the previous section. We will use Maven WAR archetype to create a web application project. To create the project, run the following command from the command-line console: mvn archetype:create -DgroupId=com.packt.plugins -DartifactId=ClockWebApp -DarchetypeArtifactId=maven-archetype-webapp This will result in the Maven web project being created, named ClockWebApp. A default pom.xml will be created. This will need to be edited to add dependencies to the two modules, as shown in the following code snippet: <dependency> <groupId>org.apache.geronimo.framework</groupId> <artifactId>geronimo-kernel</artifactId> <version>2.1.4</version></dependency><dependency> <groupId>com.packt.plugins</groupId> <artifactId>WorldClockModule</artifactId> <version>1.0</version></dependency> We add these dependencies because the portlet that we are going to write will use the classes mentioned in the above two modules.
Read more
  • 0
  • 0
  • 1795