Miles to go ...

Arun Gupta is a Technology Evangelist for Web Services and Web 2.0 Apps at Sun. He was the spec lead for APIs in the Java platform, committer in multiple Open Source projects, participated in standard bodies and contributed to Java EE and SE releases.
Main | Next page »

http://blogs.sun.com/arungupta/date/20080827 Wednesday August 27, 2008

TOTD #43: GlassFish v3 Build Flavors

Here are different flavors of GlassFish v3 builds:

You can subscribe to dev@glassfish for all the fun! Otherwise check out plan and schedule for GlassFish v3 Prelude.

Technorati: totd glassfish v3 builds prelude

del.icio.us | furl | simpy | slashdot | technorati | digg

http://blogs.sun.com/arungupta/date/20080820 Wednesday August 20, 2008

TOTD #42: Hello JavaServer Faces World with NetBeans and GlassFish


This TOTD (Tip Of The Day) shows how to create a simple Java Server Faces application using NetBeans IDE 6.1. This is my first ever Java Server Faces application :) Much more comprehensive applications are already available in NetBeans and GlassFish tutorials.

The application is really simple - it allows you to create a database of cities/country that you like. You enter the city & country name on a page and click on Submit. This stores the data entered in the backend database and displays all the stored values in a new page. This application demonstrates simple JSF concepts:

  • How to create a JSF application using NetBeans IDE ?
  • How to populate a JSF widget with a Managed Bean ?
  • How to use a Persistence Unit with JSF widgets ?
  • How to setup navigation rules between multiple pages ?
  • How to print simple error validation messages ?
  • How to inject a bean into another class ?
This particular TOTD is using JSF 1.2 that is already bundled with GlassFish v2. Let's get started.
  1. In NetBeans IDE, create a new project
    1. Create a new NetBeans Web project and enter the values ("Cities") as shown:



      and click on "Next".
    2. Choose GlassFish v2 as the deployment server and click on "Next".
    3. Select "JavaServer Faces" framework as shown below:



      take defaults and click on "Finish".
  2. Create a Persistence Unit as explained in TOTD #38. The values required for this TOTD are slightly different and given below.
    1. Use the following table definition:

      create table cities(id integer AUTO_INCREMENT,
                          city_name varchar(20),
                          country_name varchar(20),
                          PRIMARY KEY(id));
    2. There is no need to populate the table.
    3. Use "jndi/cities" as Data Source name.
    4. There is no need to create a Servlet.
    5. Add the following NamedQuery:

      @NamedQuery(name = "Cities.findAll", query = "SELECT c FROM Cities c"), 

      right after the highlighted parentheses shown below:


  3. Create a new bean which will perform all the database operations
    1. Right-click on "Source Packages", select "New", "Java Class..." and specify the values as shown below:



      and click on "Finish".
    2. Create a new class instance variable for "Cities" entity class by adding a new variable and accessor methods as shown below:

          private Cities cities;
          
          public void setCities(Cities cities) {
              this.cities = cities;
          }

      and then injecting in "faces-config.xml" as shown by the fragment below:

          <managed-bean>
              <managed-bean-name>cities</managed-bean-name>
              <managed-bean-class>server.Cities</managed-bean-class>
              <managed-bean-scope>request</managed-bean-scope>
          </managed-bean>
          <managed-bean>
              <managed-bean-name>dbUtil</managed-bean-name>
              <managed-bean-class>server.DatabaseUtil</managed-bean-class>
              <managed-bean-scope>request</managed-bean-scope>
              <managed-property>
                  <property-name>cities</property-name>
                  <value>#{cities}</value>
              </managed-property>
          </managed-bean>
    3. Inject EntityManager and UserTransaction as shown:

          @PersistenceContext(unitName="CitiesPU")
          private EntityManager entityManager;
          
          @Resource
          UserTransaction utx;
    4. Add a method that returns a Collection of all entries in the database table as shown below:

          public Collection<Cities> getAllCities() {
              Collection<Cities> allCities = new ArrayList<Cities>();

              List list = entityManager.createNamedQuery("Cities.findAll").getResultList();
              for (int i = 0; i < list.size(); i++) {
                  allCities.add((Cities)list.get(i));
              }
              return allCities;
          }
    5. Add a method that will save a new entry in the database by using values from the injected "Cities" entity class as shown below:

      public String saveCity() throws NotSupportedException, SystemException, RollbackException, HeuristicMixedException, HeuristicRollbackException {
              utx.begin();
              entityManager.persist(cities);
              utx.commit();
              
              return "submit";
          }
    6. Finally, right-click in the editor pane and select "Fix Imports":



      and click on "OK". Make sure to pick the right package name for "NotSupportedException" and "RollbackException".
  4. Add Java Server Faces widgets in the main entry page
    1. In "welcomeJSF.jsp", drag/drop "JSF Form" widget on line 22 as shown below:


    2. Select "Form Generated from Entity Class" and specify "server.Cities" entity class in the text box as shown:


    3. The generated code fragment looks like:

      <h2>Detail</h2>
       <h:form>
        <h:panelGrid columns="2">
          <h:outputText value="Id:"/>
          <h:outputText value="#{anInstanceOfserver.Cities.id}" title="Id" />
          <h:outputText value="CityName:"/>
          <h:outputText value="#{anInstanceOfserver.Cities.cityName}" title="CityName" />
          <h:outputText value="CountryName:"/>
          <h:outputText value="#{anInstanceOfserver.Cities.countryName}" title="CountryName" />
        </h:panelGrid>
       </h:form>

      It generates a 2-column table based upon fields from the entity class. We will use this form for accepting inputs by making the following changes:

      1. Remove first two "h:outputText" entries because "id" is auto generated.
      2. Change "h:outputText" that uses value expression to "h:inputText" to accept the input.
      3. Use "cities" managed bean instead of the default generated expression.
      4. Add required="true" to inputText fields. This will ensure that the form can not be submitted if text fields are empty.
      5. Add "id" attributes to inputText fields. This will be used to display the error message if fields are empty.

      The updated code fragment (with changes highlighted in bold) looks like:

      <h2>Detail</h2>
       <h:form>
        <h:panelGrid columns="2">
          <h:outputText value="CityName:"/>
          <h:inputText value="#{cities.cityName}" title="CityName" id="cityName" required="true"/>
          <h:outputText value="CountryName:"/>
          <h:inputText value="#{cities.countryName}" title="CountryName" id="countryName" required="true"/>
        </h:panelGrid>
       </h:form>

      Issue# 144217 will ensure to pick a pre-declared managed-bean or declare a new one if it does not exist already. After issue# 144499 is fixed then "id" attributes will be generated by default.
    4. Add a button to submit the results:

      <h:commandButton action="#{dbUtil.saveCity}" value="submit"/>

      This must be added between </h:panelGrid> and </h:form> tags.
    5. Add a placeholder for displaying error messages:

      <br><br>
      <h:message for="cityName" showSummary="true" showDetail="false" style="color: red"/><br>
      <h:message for="countryName" showSummary="true" showDetail="false" style="color: red"/>

      right after <h:commandButton> tag. The official docs specify the default value of "false" for both "showSummary" and "showDetail" attribute. But TLD says "false" for "showSummary" and "true" for "showDetail". Issue# 773 will fix that.
  5. Add a new page that displays result of all the entries added so far
    1. Right-click on the main project, select "New", "JSP..." and specify the name as "result".
    2. Add the following namespace declarations at top of the page:

      <%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
      <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

    3. Issue #144218 will ensure these namespaces are declared by the IDE.
    4. Drag/Drop a "JSF Data Table" widget in the main HTML body and enter the values as shown:



      The generated code fragment looks like:

      <f:view>
      <h:form>
       <h1><h:outputText value="List"/></h1>
       <h:dataTable value="#{arrayOrCollectionOfserver.Cities}" var="item">
      <h:column>
       <f:facet name="header">
       <h:outputText value="Id"/>
       </f:facet>
       <h:outputText value=" #{item.id}"/>
      </h:column>
      <h:column>
       <f:facet name="header">
       <h:outputText value="CityName"/>
       </f:facet>
       <h:outputText value=" #{item.cityName}"/>
      </h:column>
      <h:column>
       <f:facet name="header">
       <h:outputText value="CountryName"/>
       </f:facet>
       <h:outputText value=" #{item.countryName}"/>
      </h:column>
      </h:dataTable>
       </h:form>
      </f:view>

      Change the <h:dataTable> tag as shown below (changes highlighted in bold):

       <h:dataTable value="#{cities.allCities}" var="item">
    5. This page will be used to show the results after an entry is added to the database. Add a new button to go back to the entry page by adding the following fragment:

      <h:form>
           <h:commandButton action="back" value="back"/>
      </h:form>

      between </h:form> and </f:view> tags.
  6. Add the navigation rules to "faces-config.xml" as shown below:



    The corresponding XML fragment is:

        <navigation-rule>
            <from-view-id>/welcomeJSF.jsp</from-view-id>
            <navigation-case>
                <from-outcome>submit</from-outcome>
                <to-view-id>/result.jsp</to-view-id>
            </navigation-case>
        </navigation-rule>
        <navigation-rule>
            <from-view-id>/result.jsp</from-view-id>
            <navigation-case>
                <from-outcome>back</from-outcome>
                <to-view-id>/welcomeJSF.jsp</to-view-id>
            </navigation-case>
        </navigation-rule>

Let's run the application by right-clicking on the project and selecting "Deploy and Undeploy". The welcome page shows up and looks like as shown below:



Clicking on "Submit" without entering any values shows the default error messages as shown below:



Enter your favorite city/country and click on "Submit" to see the result page as:



Click on "Back" and enter few more cities. The updated result page looks like:



Here are some useful pointers for you:
Subsequent entries on this trail will show how Java Server Faces Technology Extensions, Facelets, Mojarra make the application richer.

Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive of all tips is available here.

Technorati: totd mysql javaserverfaces netbeans glassfish

del.icio.us | furl | simpy | slashdot | technorati | digg

http://blogs.sun.com/arungupta/date/20080818 Monday August 18, 2008

TOTD# 41: How I created transparent logo of GlassFish using Gimp ?

I followed the original instructions with Gimp 2.4.5.

  1. Open up the original image in Gimp. The original image has an embedded color profile and needs to be converted to RGB. Opening the original image shows the following message:



    Click on "Convert".
  2. Select "Tools", "Selection Tools", "Fuzzy Select" as shown:



    and click anywhere on the white background. There are numerous types of selection tools available but mostly the background needs to be made transparent.
  3. Select "Layer" menu item, "Transparency", "Add Alpha Channel" as shown:


  4. If "Add Alpha Channel" menu item is disabled then proceed to the next step.
  5. Select "Edit" menu item, "Clear" to make the selection transparent.
  6. Finally save the image with default settings. Make sure to give the extension as ".png", just specifying the file type as "PNG" does not automatically provide the right extension. And the transparent GlassFish image is available here.
A complete set of GlassFish buttons (including these images) are available here - feel free to use them!

How do you intend to use them ? :)

Technorati: totd gimp glassfish image

del.icio.us | furl | simpy | slashdot | technorati | digg

http://blogs.sun.com/arungupta/date/20080806 Wednesday August 06, 2008

TOTD #40: jQuery Autcomplete widget with MySQL, GlassFish, NetBeans

TOTD #39 explained how to create an Autocomplete widget (server-powered autocompleting of text fields, similar to Google Suggest) using Prototype/Script.aculo.us libraries with NetBeans, GlassFish and MySQL. This Tip Of The Day (TOTD) builds upon that project and shows how same functionality can be achieved using jQuery Library.

  1. Use the NetBeans project created in TOTD #39. Right-clicking on the project, select "New", "JSP...", enter the name as "index2" and click on "Finish".
  2. Download jquery JavaScript library from here (1.2.6 (minified) as of this writing) and copy into the "javascripts" folder of your NetBeans project.
  3. Copy contents from "index.jsp" into "index2.jsp".
  4. Borrowing the code from AjaxCompleter Tutorial, replace <script> tags in "index2.jsp" with the following code fragment:

            <script src="javascripts/jquery-1.2.6.min.js" type="text/javascript"></script>
            <script type="text/javascript">
                function autocomplete(autocomplete) {
                    if (autocomplete.length == 0) {
                        $('#autocomplete_choices').hide();
                    } else {
                        $.post("/Autocomplete/StatesServlet", { autocomplete_parameter: "" + autocomplete + ""},
                            function(data) {
                                if (data.length > 0) {
                                    $('#autocomplete_choices').show();
                                    $('#autocomplete_choices').html(data);
                                }
                            });
                    }
                }
            </script>

And here are couple of output screenshots:





Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive of all tips is available here.

Technorati: totd mysql jpa persistenceunit netbeans glassfish jquery autocomplete

del.icio.us | furl | simpy | slashdot | technorati | digg

http://blogs.sun.com/arungupta/date/20080729 Tuesday July 29, 2008

TOTD #39: Prototype/Script.aculo.us Autcomplete widget with MySQL, GlassFish, NetBeans

There are several JavaScript libraries that can be embedded in your webapplication to create a visually appealing interface. Script.aculo.us is one of the popular ones and is built on the Prototype JavaScript Framework. The library provides an easy-to-use, cross-browser user interface JavaScripts that allows you to create fancy effects commonly visible on web pages these days.

This blog entry gets you started by using Ajax.Autocompleter that allows for server-powered autocompleting of text fields. Basically, you type a character in a text field and suggestions for possible correct values starting with that character are shown . This is achieved by by sending an Ajax request to the data source on server, passing the typed character in the request and processing the response to display on the web page. This effect was first popularized by Google Suggest.

In this TOTD (Tip Of The Day) we will create a simple web application with a text field in a JSP page that will use Servlet as the data source. The Servlet retrieves the parameter from the RequestContext, uses Java Persistence API to query the database and return response in the expected format. We will use:

Let's get started!
  1. TOTD #38 explains how to create a MySQL Persistence Unit. Please follow the steps there to create a new Web application and Persistence Unit. Follow the steps listed below after the PU is created.
    1. In Project Explorer, expand "Source Packages", "server" and open "States" class. Add the following NamedQuery:

      @NamedQuery(name = "States.findLikeName", query = "SELECT s FROM States s WHERE LOWER(s.name) LIKE :searchString"),

      at the position shown below:

    2. In "StatesServlet" class, replace the commented code in "processRequest" with the following fragment:

                  String searchString = request.getParameter("autocomplete_parameter");

                  List<States> list = em.createNamedQuery("States.findLikeName").
                          setParameter("searchString", searchString.toLowerCase() + "%").
                          getResultList();

                  out.println("<ul>");

                  for (int i = 0; i < list.size(); i++) {
                      States s = list.get(i);
                      out.println("<li>" + s.getName() + "</li>");
                  }
                  out.println("</ul>");

      and fix the imports by right-clicking in editor pane and selecting "Fix Imports".
  2. Download & Use Script.aculo.us libraries
    1. Download latest Script.aculo.us libraries from here (version 1.8.1 as of this writing) and unzip them.
    2. In NetBeans, right-click on "Web Pages", select "New", "Folder" and specify the folder name as "javascripts".
    3. From the unzipped Script.aculo.us bundle, copy all files from "src" and "lib" directory to the newly created "javascripts" folder.
    4. Expand "Web Pages" and open "index.jsp". Add the following fragment in HTML <head>:

              <script src="javascripts/prototype.js" type="text/javascript"></script>
              <script src="javascripts/scriptaculous.js?load=effects,controls" type="text/javascript"></script>
              <script type="text/javascript">
                  window.onload = function() {
                      new Ajax.Autocompleter("autocomplete", "autocomplete_choices", "/Autocomplete/StatesServlet", {});
                  }
              </script>

      and the following in HTML <body>:

              <input type="text" id="autocomplete" name="autocomplete_parameter"/>
              <div id="autocomplete_choices" class="autocomplete"></div>

      These fragments are part of the original tutorial.
    5. Optionally, specify a stylesheet to render the result nicely
      1. Create a "stylesheets" folder in "Web pages".
      2. Right -click on the newly created folder, select "New", "Other...", "Other" category and "Cascading Style Sheet" file type. Give the name "autocompleter" and click on "Finish".
      3. Replace the generated template with the following contents:

        .autocomplete {
            position:absolute;
            width:250px;
            background-color:white;
            margin:0px;
            padding:0px;
            overflow:hidden;
        }
        .autocomplete ul {
            list-style-type:none;
            margin:0px;
            padding:0px;
            overflow:auto;
        }
        .autocomplete ul li.selected { background-color: #ffb;}
        .autocomplete ul li {
            list-style-type:none;
            display:block;
            margin:0;
            padding:2px;
            height:32px;
            cursor:pointer;
        }
      4. Add the following fragment in "index.jsp" in <head>:

        <LINK href="stylesheets/autocompleter.css" rel="stylesheet" type="text/css">
Now the show time ... right-click the project and select "Run". This deploys the project on GlassFish v2 and brings up "http://localhost:8080/Autocomplete/index.jsp" in the default browser window. The default page looks like:



As you start typing characters in the text box, Ajax.Autocompleter sends a request to the Servlet (specified using the "/Autocomplete/StatesServlet") by passing the typed characters as query parameters. The servlet returns an unordered HTML list. Typing "A" in the text box shows the following output:



and Firebug output looks like:



Typing "C" in the text box shows the following output:



Typing "Mi" in the text box shows the following output:



A request to the Servlet is made everytime a letter is typed. The minimum number of characters that must be entered in the field before a Servlet request is made can be altered by passing the arguments to Ajax.Autocompleter function as shown below (changes highligted in bold):
            window.onload = function() {
                new Ajax.Autocompleter("autocomplete", "autocomplete_choices", "/Autocomplete/StatesServlet", { minChars: 2 });
            }

Some potential fun ideas to make this entry more meaningful:
  • Servlet can access data from a RESTful endpoint and transform the data to an unordered list
  • Autocompleter data source return data in JSON format
  • Autocompleter used in a HTML <form> and "afterUpdateElement" is used to process the selected entry, may be filter the data shown
Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive of all tips is available here.

Technorati: totd web2.0 autocompleter scriptaculous prototype javascript glassfish mysql netbeans

del.icio.us | furl | simpy | slashdot | technorati | digg

http://blogs.sun.com/arungupta/date/20080725 Friday July 25, 2008

TOTD #38: Creating a MySQL Persistence Unit using NetBeans IDE


This TOTD (Tip Of The Day) shows how to create a Persistence Unit (PU) for a MySQL database using NetBeans IDE. This PU can then be used in any of Java EE artifacts (JSP, Servlet, EJB, ...) for database interaction.

  1. In NetBeans IDE, create a new project
    1. Create a new NetBeans Web project and enter the values ("Autocomplete") as shown:



      and click on "Next".
    2. Choose GlassFish v2 as the deployment server and then click on "Finish".
  2. Set up the database
    1. Start the database as:

      ~ >sudo mysqld_safe --user root
      Password:<YOUR PASSWORD>
      Starting mysqld daemon with databases from /usr/local/mysql/data

    2. Create a user, create the database and grant the privileges to newly created user as:

      mysql> CREATE USER duke IDENTIFIED by 'duke';
      Query OK, 0 rows affected (0.00 sec)

      mysql> create database states;
      Query OK, 1 row affected (0.00 sec)

      mysql> GRANT ALL on states.* TO duke;
      Query OK, 0 rows affected (0.00 sec)
    3. In NetBeans IDE, Services panel, right-click on Databases and click on "New Connection..." and enter the values as shown:



      and click on "OK" and again on "OK".
    4. Right-click on the newly created database and select "Execute Command ..." as shown:


    5. Create the database table as:

      CREATE TABLE STATES (
            id INT,
            abbrev VARCHAR(2),
            name VARCHAR(50),
            PRIMARY KEY (id)
      );

      and click on the green button to run the query as shown here:


    6. Following the same instructions, populate the table using the following SQL:

      INSERT INTO STATES VALUES (1, "AL", "Alabama");
      INSERT INTO STATES VALUES (2, "AK", "Alaska");
      INSERT INTO STATES VALUES (3, "AZ", "Arizona");
      INSERT INTO STATES VALUES (4, "AR", "Arkansas");
      INSERT INTO STATES VALUES (5, "CA", "California");
      INSERT INTO STATES VALUES (6, "CO", "Colorado");
      INSERT INTO STATES VALUES (7, "CT", "Connecticut");
      INSERT INTO STATES VALUES (8, "DE", "Delaware");
      INSERT INTO STATES VALUES (9, "GL", "Florida");
      INSERT INTO STATES VALUES (10, "GA", "Georgia");
      INSERT INTO STATES VALUES (11, "HI", "Hawaii");
      INSERT INTO STATES VALUES (12, "ID", "Idaho");
      INSERT INTO STATES VALUES (13, "IL", "Illinois");
      INSERT INTO STATES VALUES (14, "IN", "Indiana");
      INSERT INTO STATES VALUES (15, "IA", "Iowa");
      INSERT INTO STATES VALUES (16, "KS", "Kansas");
      INSERT INTO STATES VALUES (17, "KY", "Kentucky");
      INSERT INTO STATES VALUES (18, "LA", "Louisiana");
      INSERT INTO STATES VALUES (19, "ME", "Maine");
      INSERT INTO STATES VALUES (20, "MD", "Maryland");
      INSERT INTO STATES VALUES (21, "MA", "Massachussetts");
      INSERT INTO STATES VALUES (22, "MI", "Michigan");
      INSERT INTO STATES VALUES (23, "MN", "Minnesota");
      INSERT INTO STATES VALUES (24, "MS", "Mississippi");
      INSERT INTO STATES VALUES (25, "MO", "Missouri");
      INSERT INTO STATES VALUES (26, "MT", "Montana");
      INSERT INTO STATES VALUES (27, "NE", "Nebraska");
      INSERT INTO STATES VALUES (28, "NV", "Nevada");
      INSERT INTO STATES VALUES (29, "NH", "New Hampshire");
      INSERT INTO STATES VALUES (30, "NJ", "New Jersey");
      INSERT INTO STATES VALUES (31, "NM", "New Mexico");
      INSERT INTO STATES VALUES (32, "NY", "New York");
      INSERT INTO STATES VALUES (33, "NC", "North Carolina");
      INSERT INTO STATES VALUES (34, "ND", "North Dakota");
      INSERT INTO STATES VALUES (35, "OH", "Ohio");
      INSERT INTO STATES VALUES (36, "OK", "Oklahoma");
      INSERT INTO STATES VALUES (37, "OR", "Orgeon");
      INSERT INTO STATES VALUES (38, "PA", "Pennsylvania");
      INSERT INTO STATES VALUES (39, "RI", "Rhode Island");
      INSERT INTO STATES VALUES (40, "SC", "South Carolina");
      INSERT INTO STATES VALUES (41, "SD", "South Dakota");
      INSERT INTO STATES VALUES (42, "TN", "Tennessee");
      INSERT INTO STATES VALUES (43, "TX", "Texas");
      INSERT INTO STATES VALUES (44, "UT", "Utah");
      INSERT INTO STATES VALUES (45, "VT", "Vermont");
      INSERT INTO STATES VALUES (46, "VA", "Virginia");
      INSERT INTO STATES VALUES (47, "WA", "Washington");
      INSERT INTO STATES VALUES (48, "WV", "West Virignia");
      INSERT INTO STATES VALUES (49, "WI", "Wisconsin");
      INSERT INTO STATES VALUES (50, "WY", "Wyoming");
  3. Create and configure the persistence unit
    1. Right-click on the newly created project and select "New", "Entity Classes from Database ..." as shown:


    2. In DataSource, select "New Data Source..." and enter the JNDI name "jndi/states" as shown:


    3. Select "STATES" table in "Available Tables:" and click on "Add >" and then "Next >".
    4. Click on "Create Persistence Unit ...", take all the defaults and click on "Create".
    5. Enter the package name as "server" and click on "Finish".
    6. Expand "Configuration File", open "persistence.xml". Unselect "Include All Entity Classes" check box, click on "Add Class...", select "server.States" and click on OK. The updated view looks like:

    7. Select the XML view and replace <properties/> with

          <properties>
              <property name="toplink.jdbc.user" value="duke"/>
              <property name="toplink.jdbc.password" value="duke"/>
          </properties>

      The username and password values must match the ones specified during database creation. The updated "persistence.xml" looks like:

      <?xml version="1.0" encoding="UTF-8"?>
      <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
        <persistence-unit name="AutocompletePU" transaction-type="JTA">
          <jta-data-source>jndi/states</jta-data-source>
          <class>server.States</class>
          <exclude-unlisted-classes>true</exclude-unlisted-classes>
          <properties>
            <property name="toplink.jdbc.user" value="duke"/>
            <property name="toplink.jdbc.password" value="duke"/>
          </properties>
        </persistence-unit>
      </persistence>
  4. Create a Servlet to perform the database operations
    1. Right-click on the project, select "New", "Servlet".
    2. Enter the class name as "StatesServlet" and package as "server" and click on "Finish".
    3. Add the following fragment in the beginning of the class:

          EntityManager em;

          @Override
          public void init() throws ServletException {
              EntityManagerFactory emf = Persistence.createEntityManagerFactory("AutocompletePU");
              em = emf.createEntityManager();
          }

      Alternatively, you can use resource injection to populate the EntityManager. Use the following fragment, instead of the above, to achieve that:

          @PersistenceContext(unitName="AutocompletePU")
          EntityManager em;
    4. Replace the commented code in "processRequest" with the following fragment:

                  String abbrev = request.getParameter("abbrev");

                  List<States> list = em.createNamedQuery("States.findByAbbrev").
                          setParameter("abbrev", abbrev).
                          getResultList();

                  if (list.size() > 0) {
                      States s = list.get(0);
                      out.println("Found " + s.getName() + " with abbrev \"" + abbrev + "\"");
                  } else {
                      out.println("No matching state found with \"" + abbrev + "\"");
                  }

      and fix the imports by right-clicking in editor pane and selecting "Fix Imports".
    5. Right-click on the project and select "Undeploy and Deploy".
Now let's try it!

Invoking "curl http://localhost:8080/Autocomplete/StatesServlet?abbrev=CA" shows the following output on command prompt:

Found California with abbrev "CA"

Alternatively, you can enter this URL in browser as well to see the output as:



Invoking "http://localhost:8080/Autocomplete/StatesServlet?abbrev=CB" shows the output:



Even though MySQL is used as the database in this case, any other database can be easily used for creating this portable PU.

Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive of all tips is available here.

Technorati: totd mysql jpa persistenceunit netbeans glassfish
Technorati: totd mysql jpa persistenceunit netbeans glassfish jquery autocomplete

del.icio.us | furl | simpy | slashdot | technorati | digg

http://blogs.sun.com/arungupta/date/20080702 Wednesday July 02, 2008

TOTD #37: SQLite3 with Ruby-on-Rails on GlassFish Gem


The default database for Rails 2.0.x application is SQLite3. This database is bundled with Mac OSX Leopard and so makes it really easy to get started with Ruby-on-Rails. But it requires couple of additional steps if you are using JRuby.


TOTD #28 explains how to create a simple CRUD application using Rails 2.0.x. It uses MySQL database which is strongly recommended for deployment. This TOTD (Tip Of The Day) provides complete steps to run a Ruby-on-Rails application using JRuby and GlassFish Gem with the default database, i.e. SQLite3.
  1. Create a Rails application as:

    ~/samples/jruby >~/testbed/jruby-1.1.2/bin/jruby -S rails runner
          create 
          create  app/controllers
          create  app/helpers
          create  app/models
          create  app/views/layouts
    . . .
          create  log/server.log
          create  log/production.log
          create  log/development.log
          create  log/test.log

    The generated "database.yml" looks like:

    # SQLite version 3.x
    #   gem install sqlite3-ruby (not necessary on OS X Leopard)
    development:
      adapter: sqlite3
      database: db/development.sqlite3
      timeout: 5000

    # Warning: The database defined as "test" will be erased and
    # re-generated from your development database when you run "rake".
    # Do not set this db to the same as development or production.
    test:
      adapter: sqlite3
      database: db/test.sqlite3
      timeout: 5000

    production:
      adapter: sqlite3
      database: db/production.sqlite3
      timeout: 5000
  2. SQLite3 adapter is installed for the native Ruby bundled with Leopard. But in order to use SQLite3 with JRuby, you need to install SQLite3 JDBC adapter as shown below:

    ~/samples/jruby/runner >~/testbed/jruby-1.1.2/bin/jruby -S gem install activerecord-jdbcsqlite3-adapter
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Successfully installed activerecord-jdbc-adapter-0.8.2
    Successfully installed jdbc-sqlite3-3.5.8
    Successfully installed activerecord-jdbcsqlite3-adapter-0.8.2
    3 gems installed
    Installing ri documentation for activerecord-jdbc-adapter-0.8.2...
    Installing ri documentation for jdbc-sqlite3-3.5.8...
    Installing ri documentation for activerecord-jdbcsqlite3-adapter-0.8.2...
    Installing RDoc documentation for activerecord-jdbc-adapter-0.8.2...
    Installing RDoc documentation for jdbc-sqlite3-3.5.8...
    Installing RDoc documentation for activerecord-jdbcsqlite3-adapter-0.8.2...
  3. Create a new file as "db/development.sqlite3". It can be easily created using the "touch" command. See the beauty of SQLite that "db:create" is not required :)
  4. Update the development section of "database.yml" such that it looks like:

    development:
      adapter: jdbcsqlite3
      database: db/development.sqlite3
      timeout: 5000
  5. Create a simple scaffold as shown below:

    ~/samples/jruby/runner >~/testbed/jruby-1.1.2/bin/jruby script/generate scaffold run distance:float minutes:integer
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
          exists  app/models/
          exists  app/controllers/
          exists  app/helpers/
          create  app/views/runs
          exists  app/views/layouts/
          exists  test/functional/
          exists  test/unit/
          exists  public/stylesheets/
          create  app/views/runs/index.html.erb
          create  app/views/runs/show.html.erb
          create  app/views/runs/new.html.erb
          create  app/views/runs/edit.html.erb
          create  app/views/layouts/runs.html.erb
          create  public/stylesheets/scaffold.css
          create  app/controllers/runs_controller.rb
          create  test/functional/runs_controller_test.rb
          create  app/helpers/runs_helper.rb
           route  map.resources :runs
      dependency  model
          exists    app/models/
          exists    test/unit/
          exists    test/fixtures/
          create    app/models/run.rb
          create    test/unit/run_test.rb
          create    test/fixtures/runs.yml
          create    db/migrate
          create    db/migrate/20080630211244_create_runs.rb

    and run the migration as

    ~/samples/jruby/runner >~/testbed/jruby-1.1.2/bin/jruby -S rake db:migrate
    (in /Users/arungupta/samples/jruby/runner)
    == 20080630205502 CreateRuns: migrating =======================================
    -- create_table(:runs)
       -> 0.0410s
       -> 0 rows
    == 20080630205502 CreateRuns: migrated (0.0420s) ==============================
  6. A Rails application is deployed on GlassFish from it's parent directory. Therefore the application needs to be updated so taht exact location of database is specified. Basically you need to edit "database.yml" and the updated "development" fragment looks like:

    development:
      adapter: jdbcsqlite3
      database: runner/db/development.sqlite3
      timeout: 5000
  7. Run the application on GlassFish v3 gem as:

    ~/samples/jruby >~/testbed/jruby-1.1.2/bin/jruby -S glassfish_rails runner
    Jun 30, 2008 1:52:08 PM com.sun.enterprise.glassfish.bootstrap.ASMain main
    INFO: Launching GlassFish on HK2 platform
    Jun 30, 2008 1:52:08 PM com.sun.enterprise.glassfish.bootstrap.ASMainHK2 findDerbyClient
    INFO: Cannot find javadb client jar file, jdbc driver not available
    Jun 30, 2008 1:52:09 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
    INFO: Listening on port 3000
    Jun 30, 2008 1:52:09 PM com.sun.enterprise.v3.services.impl.GrizzlyEmbeddedHttpConfigurator configureSSL
    WARNING: pewebcontainer.all_ssl_protocols_disabled
    Jun 30, 2008 1:52:09 PM com.sun.enterprise.v3.services.impl.GrizzlyEmbeddedHttpConfigurator configureSSL
    WARNING: pewebcontainer.all_ssl_ciphers_disabled
    Jun 30, 2008 1:52:09 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
    INFO: Listening on port 3131
    Jun 30, 2008 1:52:09 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
    INFO: Listening on port 3838
    Jun 30, 2008 1:52:09 PM com.sun.enterprise.v3.admin.adapter.AdminConsoleAdapter setContextRoot
    INFO: Admin Console Adapter: context root: /admin
    Jun 30, 2008 1:52:09 PM com.sun.grizzly.jruby.RailsAdapter startRubyRuntimePool
    INFO: Starting Rails instances
    Jun 30, 2008 1:52:16 PM  
    SEVERE: JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Jun 30, 2008 1:52:17 PM com.sun.grizzly.jruby.RubyObjectPool$1 run
    INFO: JRuby and Rails instance instantiation took : 7998ms
    Jun 30, 2008 1:52:17 PM org.glassfish.scripting.rails.RailsDeployer load
    INFO: Loading application runner at /
    Jun 30, 2008 1:52:17 PM com.sun.enterprise.v3.server.AppServerStartup run
    INFO: Glassfish v3 started in 9430 ms

After adding couple of entries, "http://localhost:3000/runs" looks like:



So now you can use SQLite3 as your development database for Rails applications running on GlassFish v3 Gem.

Here are some useful pointers:

Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive is available here.


Technorati: totd rubyonrails jruby ruby sqlite sqlite3 glassfish v3 gem

del.icio.us | furl | simpy | slashdot | technorati | digg

http://blogs.sun.com/arungupta/date/20080701 Tuesday July 01, 2008

TOTD# 36: Writing First Test for a Rails Application

I've created a Rails "Hello World" app numerous times. But I decided to write a simple using the testing framework provided by Rails. This blog explains my experience of writing such a test.

  1. Create a "Hello World" app as:

    ~/samples/jruby/test >~/testbed/jruby-1.1.2/bin/jruby -S rails helloworld        
          create 
          create  app/controllers
          create  app/helpers
          create  app/models
          create  app/views/layouts
          create  config/environments
          create  config/initializers

    . . .

          create  log/production.log
          create  log/development.log
          create  log/test.log

    There is no "-d mysql" in the command because I don't expect this application to do any database access. The database access is disabled by following TOTD #26.
  2. I tried generating a new controller using the command:

    ~/samples/jruby/test/helloworld >~/testbed/jruby-1.1.2/bin/jruby script/generate controller home index

    and got the error:

    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:278:in `load_missing_constant': uninitialized constant ActiveRecord (NameError)
            from /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:467:in `const_missing'
            from /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:479:in `const_missing'
            from /Users/arungupta/samples/jruby/test/helloworld/config/initializers/new_rails_defaults.rb:5:in `/Users/arungupta/samples/jruby/test/helloworld/config/initializers/new_rails_defaults.rb'
            from /Users/arungupta/samples/jruby/test/helloworld/config/initializers/new_rails_defaults.rb:502:in `load'
            from /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:502:in `load'
            from /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:354:in `new_constants_in'
            from /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:502:in `load'
            from /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:475:in `load_application_initializers'
             ... 8 levels...
            from /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/commands/generate.rb:27:in `require'
            from /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
            from script/generate:3

    So even though database access has been explicitly disabled, there are still references to ActiveRecord. So I had to explicitly disable them by changing the code in "config/initializers/new_rails_defaults.rb" as:

    if defined?(ActiveRecord)
    # Include Active Record class name as root for JSON serialized output.
    ActiveRecord::Base.include_root_in_json = true

    # Store the full class name (including module namespace) in STI type column.
    ActiveRecord::Base.store_full_sti_class = true
    end

    and then the controller is easily generated as:

    ~/samples/jruby/test/helloworld >~/testbed/jruby-1.1.2/bin/jruby script/generate controller home index
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
          exists  app/controllers/
          exists  app/helpers/
          create  app/views/home
          exists  test/functional/
          create  app/controllers/home_controller.rb
          create  test/functional/home_controller_test.rb
          create  app/helpers/home_helper.rb
          create  app/views/home/index.html.erb
  3. Run your application using GlassFish v3 gem as:

    ~/workspaces/glassfish-scripting/rails/v3/src/test/rails >~/testbed/jruby-1.1.2/bin/jruby -S glassfish_rails helloworld
    Jun 27, 2008 2:46:18 PM com.sun.enterprise.glassfish.bootstrap.ASMain main
    INFO: Launching GlassFish on HK2 platform
    Jun 27, 2008 2:46:18 PM com.sun.enterprise.glassfish.bootstrap.ASMainHK2 findDerbyClient
    INFO: Cannot find javadb client jar file, jdbc driver not available
    Jun 27, 2008 2:46:18 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
    INFO: Listening on port 3000
    Jun 27, 2008 2:46:18 PM com.sun.enterprise.v3.services.impl.GrizzlyEmbeddedHttpConfigurator configureSSL
    WARNING: pewebcontainer.all_ssl_protocols_disabled
    Jun 27, 2008 2:46:18 PM com.sun.enterprise.v3.services.impl.GrizzlyEmbeddedHttpConfigurator configureSSL
    WARNING: pewebcontainer.all_ssl_ciphers_disabled
    Jun 27, 2008 2:46:19 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
    INFO: Listening on port 3131
    Jun 27, 2008 2:46:19 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
    INFO: Listening on port 3838
    Jun 27, 2008 2:46:19 PM com.sun.enterprise.v3.admin.adapter.AdminConsoleAdapter setContextRoot
    INFO: Admin Console Adapter: context root: /admin
    Jun 27, 2008 2:46:19 PM com.sun.grizzly.jruby.RailsAdapter startRubyRuntimePool
    INFO: Starting Rails instances
    Jun 27, 2008 2:46:24 PM  
    SEVERE: JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Jun 27, 2008 2:46:24 PM com.sun.grizzly.jruby.RubyObjectPool$1 run
    INFO: JRuby and Rails instance instantiation took : 5169ms
    Jun 27, 2008 2:46:24 PM org.glassfish.scripting.rails.RailsDeployer load
    INFO: Loading application helloworld at /
    Jun 27, 2008 2:46:24 PM com.sun.enterprise.v3.server.AppServerStartup run
    INFO: Glassfish v3 started in 6419 ms
    Jun 27, 2008 2:46:28 PM com.sun.grizzly.jruby.RailsAdapter$Logger log
    INFO: 
  4. Chapter 9 in Rails Manual explains how to test controllers. Modify "test/functional/home_controller_test.rb" as:

    require 'home_controller'

    class HomeControllerTest < ActionController::TestCase
      def test_index
        get :index
        assert_response :success
      end

    end
  5. Run the test as:

    ~/workspaces/glassfish-scripting/rails/v3/src/test/rails/helloworld >~/testbed/jruby-1.1.2/bin/jruby -S rake test
    (in /Users/arungupta/workspaces/glassfish-scripting/rails/v3/src/test/rails/helloworld)
    /Users/arungupta/testbed/jruby-1.1.2/bin/jruby -Ilib:test "/Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb"  
    /Users/arungupta/testbed/jruby-1.1.2/bin/jruby -Ilib:test "/Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb" "test/functional/home_controller_test.rb"
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Loaded suite /Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader
    Started
    .
    Finished in 0.308 seconds.

    1 tests, 1 assertions, 0 failures, 0 errors
    /Users/arungupta/testbed/jruby-1.1.2/bin/jruby -Ilib:test "/Users/arungupta/testbed/jruby-1.1.2/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb"

If you indeed are using database (which is the most common case anyway) then you can load data using Fixtures and then Test your Models.

Keep adding controller and models and testing them!

Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive is available here.

Technorati: rubyonrails jruby ruby glassfish totd

del.icio.us | furl | simpy | slashdot | technorati | digg

http://blogs.sun.com/arungupta/date/20080623 Monday June 23, 2008

TOTD #35: Rails Database Connection on Solaris

Are you deploying your JRuby-on-Rails applications on Solaris (or any variety of Unix) and not able to connect to the database ?

I experienced it last week so thought of sharing the tip here. Luckily it's really simple.

Here is the default generated "config/database.yml"

development:
  adapter: mysql
  encoding: utf8
  database: runner_development
  username: root
  password:
  socket: /tmp/mysql.sock

The only required change is to add "host: 127.0.01" for the required database configuration. The updated fragment is shown below (with change highlighted):

development:
  adapter: mysql
  encoding: utf8
  database: runner_development
  username: root
  password:
  socket: /tmp/mysql.sock
  host: 127.0.01

Even though "host" is required for TCP connections but the database connection does not seem to work without this entry. The exact same application works without "host" entry on Windows and Mac OS.

Alternatively, you can always install the JDBC adapter as explained here.

Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive is available here.

Technorati: totd rubyonrails jruby ruby opensolaris mysql

del.icio.us | furl | simpy | slashdot | technorati | digg