Miles to go ...

Arun Gupta is a GlassFish Evangelist focusing on Web Tier 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/20090618 Thursday June 18, 2009

TOTD #85: Getting Started with Django Applications on GlassFish v3

GlassFish v3 is an extensible App server. Basically the core App server functionality can be easily extended using add-ons such as an OSGi module. This allows to keep the core light-weight and install the required features on demand. The add-ons can be easily installed using the Update Center. The what/why/how about extensibility is described in the GlassFish v3 Extensibility One-pager.

GlassFish v3 provides support for Dynamic Languages and Web Frameworks such as Ruby-on-Rails, Groovy/Grails, and Python/Django using this extensibility. This blog has published multiple tips on using Ruby-on-Rails at rubyonrails+totd and a few tips on Groovy/Grails at grails+totd. This blog will explain how to get started with deploying Python/Django applications on GlassFish v3 Preview. The blog will use Jython interpreter which is the Java implemention of Python.

Vivek already blogged about the detailed instructions and this blog shows how to run the pre-bundled samples.

  1. Download GlassFish v3 Preview.
  2. Install Jython 2.5
    1. Download Jython 2.5 from here
    2. Install as:

      java -jar ~/Downloads/jython_installer-2.5.0.jar

      Choose the default options (pick your directory) as shown below:



      and click on "Next" to start the installation process.
    3. As mentioned in Django on Jython wiki, create the following aliases:

      alias jython25=~/tools/jython2.5.0/bin/jython
      alias django-admin-jy="jython25 ~/tools/jython2.5.0/bin/django-admin.py"

    4. Invoking the command "jython25" from the installation directory shows the Jython interpreter as:

      ~/tools/jython/jython2.5rc4 >jython25
      Jython 2.5rc4 (Release_2_5rc4:6470, Jun 8 2009, 13:23:16)
      [Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_13
      Type "help", "copyright", "credits" or "license" for more information.
      >>>

  3. Install Django
    1. Download Django 1.0.2 from here.
    2. Install Django 1.0.2 as:

      ~/tools >tar xzvf ~/Downloads/Django-1.0.2-final.tar.gz
      Django-1.0.2-final/
      Django-1.0.2-final/AUTHORS
      Django-1.0.2-final/django/
      . . .
      Django-1.0.2-final/scripts/rpm-install.sh
      Django-1.0.2-final/setup.cfg
      Django-1.0.2-final/setup.py
      ~/tools/Django-1.0.2-final >jython25 setup.py install
      running install
      running build
      running build_py
      . . .
      running install_egg_info
      Writing /Users/arungupta/tools/jython/jython2.5.0/Lib/site-packages/Django-1.0.2_final-py2.5.egg-info

  4. Install Jython container for GlassFish
    1. Start GlassFish v3 Preview Update Center using the following command:

      ~/tools/glassfish/v3/preview/glassfishv3/bin >./updatetool 

      to see the screen as:


    2. Select "GlassFish v3 Jython Container" and click on "Install", "Accept" the license and complete the installation. Close the Update Center window. This installs Jython Container OSGi module and Grizzly Adapter JARs in the "glassfish/modules" directory.
  5. Start and configure GlassFish
    1. Start GlassFish as:

      ~/tools/glassfish/v3/preview/glassfishv3/glassfish >./bin/asadmin start-domain

    2. Configure Jython in GlassFish as:

      ~/tools/glassfish/v3/preview/glassfishv3/glassfish >./bin/asadmin create-jvm-options -Djython.home=/Users/arungupta/tools/jython2.5.0
      created 1 option(s)

      Command create-jvm-options executed successfully.

      Make sure to specify the directory where Jython is installed.
  6. Deploy the samples bundled with the Django installation as:

    ~/tools/Django-1.0.2-final/examples >~/tools/glassfish/v3/preview/glassfishv3/glassfish/bin/asadmin deploy .

    Command deploy executed successfully.

    and now they are accessible at "http://localhost:8080/examples/" and shown as:



    Make sure to specify the end "/" otherwise the context root is not resolved correctly and none of the links will work.

    Click on "Hello World (HTML)" to see the output as:



    And click on "Displaying request metadata" to see output as:



    The same sample can, of course, run using the built-in development server as:

    ~/tools/Django-1.0.2-final/examples >jython25 manage.py runserver
    Validating models...
    0 errors found

    Django version 1.0.2 final, using settings 'examples.settings'
    Development server is running at http://127.0.0.1:8000/
    Quit the server with CONTROL-C.

    and then accessible at "http://localhost:8000" as:

More details are available in Django Tutorial. The subsequent blogs will provide more detailed samples.

If you are using GlassFish v2 then Django applications can be deployed as a WAR file as explained here.

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

Technorati: totd glassfish v3 django python

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

http://blogs.sun.com/arungupta/date/20090616 Tuesday June 16, 2009

TOTD #84: Using Apache + mod_proxy_balancer to load balance Ruby-on-Rails running on GlassFish


TOTD #81 explained how to install/configure nginx for load-balancing/front-ending a cluster of Rails application running on GlassFish Gem. Another popular approach in the Rails community is to use Apache HTTPDmod_proxy_balancer. A user asked the exact details of this setup on the GlassFish Gem Forum. This Tip Of The Day (TOTD) will clearly explain the steps.

  1. Create a simple Rails scaffold and run this application using GlassFish Gem on 3 separate ports as explained in TOTD #81.
  2. Setup and configure HTTPD and mod_proxy_balancer
    1. Setup and install Apache HTTPD as explained here. I believe mod_proxy_balancer and other related modules comes pre-bundled with HTTPD, at least that's what I observed with Mac OS X 10.5.7. Make sure that the "mod_proxy_balancer" module is enabled by verifying the following line is uncommented in "/etc/apache2/httpd.conf":

      LoadModule proxy_balancer_module libexec/apache2/mod_proxy_balancer.so

      Please note another similar file exists in "/etc/httpd/httpd.conf" but ignore that one.
    2. Setup a mod_proxy_balancer cluster by adding the following fragment in "httpd.conf" as:

      <Proxy balancer://glassfishgem>
      BalancerMember http://localhost:3000
      BalancerMember http://localhost:3001
      BalancerMember http://localhost:3002
      </Proxy>

      The port numbers must exactly match with those used in the first step.
    3. Specify the ProxyPass directives to map the cluster to a local path as:

      ProxyPass / balancer://glassfishgem/
      CustomLog /var/log/glassfishgem.log/apache_access_log combined

      The "/" at the end of "balancer://glassfishgem" is very important to ensure that all the files are resolved correctly.
    4. Optionally, the following directive can be added to view the access log:

      CustomLog /var/log/glassfishgem.log/apache_access_log combined

      Make sure to create the directory specified in "CustomLog" directive.
  3. Now the application is accessible at "http://localhost/runlogs". If a new GlassFish instance is started then update the <Proxy> directive and restart your HTTPD as "sudo httpd -k restart". Dynamic update of BalancerMembers can be configured as explained here.
TOTD #81 started the Rails application in root context. You can alternatively start the application in a non-root context as:

~/tools/jruby/rails/runner >../../bin/jruby -S glassfish -e production -c myapp
Starting GlassFish server at: 10.0.177.178:3000 in production environment...
Writing log messages to: /Users/arungupta/tools/jruby-1.3.0/rails/runner/log/production.log.
Press Ctrl+C to stop.
. . .
~/tools/jruby/rails/runner >../../bin/jruby -S glassfish -e production -c myapp -p 3001
Starting GlassFish server at: 10.0.177.178:3001 in production environment...
Writing log messages to: /Users/arungupta/tools/jruby-1.3.0/rails/runner/log/production.log.
Press Ctrl+C to stop.
. . .
~/tools/jruby/rails/runner >../../bin/jruby -S glassfish -e production -c myapp -p 3002
Starting GlassFish server at: 10.0.177.178:3002 in production environment...
Writing log messages to: /Users/arungupta/tools/jruby-1.3.0/rails/runner/log/production.log.
Press Ctrl+C to stop.

and then the ProxyPass directive will change to:

ProxyPass /myapp/ balancer://glassfishgem/myapp/

The changes are highlighted in bold. And the application is now accessible at "http://localhost/myapp/runlogs".

After discussing on Apache HTTP Server forum, the BalancerMember host/port can be printd in the log file using a custom log format. So add the following log format to "/etc/apache2/httpd.conf":

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{BALANCER_WORKER_NAME}e\"" custom

And change the format from the default "combined" to the newly defined "custom" format as:

CustomLog /var/log/glassfishgem.com/apache_access_log custom

Three subsequent invocations of "http://localhost/runlogs" then prints the following log entries:

::1 - - [17/Jun/2009:10:53:53 -0700] "GET /runlogs HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.11) Gecko/2009060214 Firefox/3.0.11" "http://localhost:3002"
::1 - - [17/Jun/2009:10:54:04 -0700] "GET /runlogs HTTP/1.1" 200 621 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.11) Gecko/2009060214 Firefox/3.0.11" "http://localhost:3000"
::1 - - [17/Jun/2009:10:54:05 -0700] "GET /runlogs HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.11) Gecko/2009060214 Firefox/3.0.11" "http://localhost:3001"

As evident from the last fragment of each log line, the load is distributed amongst three GlassFish Gem instances. More details on load balancer algorithm are available here.

Feel free to drop a comment on this blog if you are using GlassFish in production for your Rails applications. Several stories are already available at rubyonrails+glassfish+stories.

Technorati: glassfish rubyonrails apache httpd mod_proxy_balancer loadbalancing clustering

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

http://blogs.sun.com/arungupta/date/20090521 Thursday May 21, 2009

TOTD #83: Eclipse Tools Bundle for GlassFish 1.0 - Now Available!


The GlassFish Tools Bundle for Eclipse 1.0 is now available.



An earlier blog entry explains how to get started using this bundle.

If you used an earlier version (0.99.x) of this bundle, then an upgrade is not supported. However backwards compatibility will be maintained going forward!

Here are some pointers to get you started:

Enjoy and send us feedback at users@glassfishplugins.dev.java.net.

Technorati: glassfish eclipse

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

http://blogs.sun.com/arungupta/date/20090519 Tuesday May 19, 2009

TOTD #82: Getting Started with Servlet 3.0 and EJB 3.1 in Java EE 6 using NetBeans 6.7


EJB 3.1 (JSR 318) and Servlet 3.0 (JSR 315) are the two new JSRs in Java EE 6 (JSR 316).

The EJB 3.1 specification provides multiple new features such as WAR packaging, Optional Local Business Interfaces, EJB.lite, Portable Global JNDI Names, Singleton Session Beans (Container-managed and Bean-managed concurrency), Application Initialization and Shutdown events, Timer Service enhancements, Simple/Light-weight Asynchrony, and many other features defined in the specification.

The Servlet 3.0 specification is an update to Servlet 2.5 and focuses on ease-of-use. It also adds several new features such as "web.xml" free deployment (mostly), Dynamic Registration of servlets/filters, Pluggability of frameworks using "web-fragment.xml", Asynchronous API, Security enhancements (Constraints via annotations, programmatic container authentication and logout), and several other miscellaneous additions like default error page, file upload, etc.

GlassFish v3 provides the most complete implementation of EJB 3.1 and Servlet 3.0 along with other Java EE 6 specifications. This Tip Of The Day (TOTD) will show how to create a simple EJB and invoke it from a Servlet, all in a deployment-descriptor free way.

  1. Enable support for v3 Preview in NetBeans
    1. Using NetBeans 6.7 latest nightly, enable support for recent GlassFish v3 builds either using the command-line switch or the marker module.
    2. Download and unzip GlassFish v3 Preview 47b. The latest promoted builds are always available here.
    3. In the "Services" tab, right-click on "Servers" and click on "Add Server". Select "GlassFish v3" as shown below:



      and click on "Next".
    4. Specify location of the previously unzipped bundle, click on "Next >", and press "Finish".
  2. Create a new Web project by right-click in the "Projects" pane, select "New Project", choose "Java Web" and "Web  Application" as categories and projects.
  3. Click on "Next >", choose "Java EE 5" as the Java EE version and click on "Finish". A future version of NetBeans will will provide direct support for Java EE 6.
  4. Add a POJO-based EJB
    1. Right-click on "Source Packages" and select "New", "Java Class..." as shown below:



      Give the class name as "HelloEJB" and package as "server" as shown below:



      and click on "Finish".
    2. Add "@Stateless" class-level annotation and press Shift+Command+I (default shortcut) to fix the imports. This annotation comes from the "javax.ejb" package.
    3. Add the following method:

          public String sayHello(String name) {
              return "Hello " + name;
          }

      to the class. And can you believe it, that's your complete EJB ready to be deployed and that too in a WAR file - the beauty of Java EE 6. The complete class looks like:


      package server;

      import javax.ejb.Stateless;

      /**
       * @author arungupta
       */
      @Stateless
      public class HelloEJB {
          public String sayHello(String name) {
              return "Hello " + name;
          }
      }
  5. Add a Servlet to invoke this EJB
    1. Add a new class "HelloServlet" in the "server" package as explained above.
    2. Add "@WebServlet" class-level annotation and Shift+Command+I to fix the imports. This annotation comes from the "javax.servlet.annotation" package. And specify a URL pattern as:

      @WebServlet(urlPatterns="/hello")
    3. According to the Servlet3 specification, the contract is inherited from the "javax.servlet.http.HttpServlet" interface. So add:

      extends HttpServlet

      to the class.
    4. Inject a local EJB reference using the code:

      @EJB HelloEJB ejbClient;
    5. Override the GET method as:

          @Override
          public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
              res.setContentType("text/html");
              res.getOutputStream().print("<h1>Hosted at: " + req.getContextPath() + "</h1>");
              res.getOutputStream().print("<h2>" + ejbClient.sayHello("Duke") + "</h2>");
          }

      and again Shift+Command+I to fix the imports. The complete class looks like:

      package server;

      import java.io.IOException;
      import javax.ejb.EJB;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;

      /**
       * @author arungupta
       */
      @WebServlet(urlPatterns="/hello")
      public class HelloServlet extends HttpServlet {
          @EJB HelloEJB ejbClient;

          @Override
          public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
              res.setContentType("text/html");
              res.getOutputStream().print("<h1>Hosted at: " + req.getContextPath() + "</h1>");
              res.getOutputStream().print("<h2>" + ejbClient.sayHello("Duke") + "</h2>");
          }
      }
That completes the project creation. Now lets make our application deployment descriptor free by expanding "WEB-INF" directory and deleting "sun-web.xml" and "web.xml". Java EE 6 makes the deployment descriptors optional by introducing equivalent annotations.

Lets run the project by right-click on the project and select "Run". The web application is deployed to GlassFish v3 Preview 47b and "http://localhost:8080/WebApplication1" shows the default "index.jsp" created by the IDE.

Our servlet is accessible at "http://localhost:8080/WebApplication1/hello" and shows the output as:



The directory of the generated WAR file looks like:



As evident "WEB-INF/classes" has only two POJO classes and yet this is a Java EE 6 application.

So we created a trivial Java EE 6 application using Servlet 3 and EJB 3.1 APIs and deployed successfully on GlassFish v3 Preview 47b using NetBeans 6.7.

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

Technorati: totd glassfish v3 javaee6 servlet3 ejb3.1 netbeans

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

http://blogs.sun.com/arungupta/date/20090430 Thursday April 30, 2009

TOTD #81: How to use nginx to load balance a cluster of GlassFish Gem ?

nginx (pronounced as "engine-ex") is an open-source and high-performance HTTP server. It provides the common features such as reverse proxying with caching, load balancing, modular architecture using filters (gzipping, chunked responses, etc), virtual servers, flexible configuration and much more.

nginx is known for it's high performance and low resource consumption. It's a fairly popular front-end HTTP server in the Rails community along with Apache, Lighttpd, and others. This TOTD (Tip Of The Day) will show how to install/configure nginx for load-balancing/front-ending a cluster of Rails application running on GlassFish Gem.
  1. Download, build, and install nginx using the simple script (borrowed from dzone):

    ~/tools > curl -L -O http://sysoev.ru/nginx/nginx-0.6.36.tar.gz
    ~/tools > tar -xzf nginx-0.6.36.tar.gz
    ~/tools > curl -L -O http://downloads.sourceforge.net/pcre/pcre-7.7.tar.gz
    ~/tools > tar -xzf pcre-7.7.tar.gz
    ~/tools/nginx-0.6.36 > ./configure --prefix=/usr/local/nginx --sbin-path=/usr/sbin --with-debug --with-http_ssl_module --with-pcre=../pcre-7.7
    ~/tools/nginx-0.6.36 > make
    ~/tools/nginx-0.6.36 > sudo make install
    ~/tools/nginx-0.6.36 > which nginx
    /usr/sbin/nginx

    OK, nginx is now roaring and can be verified by visiting "http://localhost" as shown below:


  2. Create a simple Rails scaffold as:

    ~/samples/jruby >~/tools/jruby/bin/jruby -S rails runner
    ~/samples/jruby/runner >~/tools/jruby/bin/jruby script/generate scaffold runlog miles:float minutes:integer
    ~/samples/jruby/runner >sed s/'adapter: sqlite3'/'adapter: jdbcsqlite3'/ <config/database.yml >config/database.yml.new
    ~/samples/jruby/runner >mv config/database.yml.new config/database.yml
    ~/samples/jruby/runner >~/tools/jruby/bin/jruby -S rake db:migrate
  3. Run this application using GlassFish Gem on 3 separate ports as:

    ~/samples/jruby/runner >~/tools/jruby/bin/jruby -S glassfish
    Starting GlassFish server at: 192.168.1.145:3000 in development environment...
    Writing log messages to: /Users/arungupta/samples/jruby/runner/log/development.log.
    Press Ctrl+C to stop.

    The default port is 3000. Start the seond one by explicitly specifying the port using "-p" option ..

    ~/samples/jruby/runner >~/tools/jruby/bin/jruby -S glassfish -p 3001
    Starting GlassFish server at: 192.168.1.145:3001 in development environment...
    Writing log messages to: /Users/arungupta/samples/jruby/runner/log/development.log.
    Press Ctrl+C to stop.

    and the last one on 3002 port ...

    ~/samples/jruby/runner >~/tools/jruby/bin/jruby -S glassfish -p 3002
    Starting GlassFish server at: 192.168.1.145:3002 in development environment...
    Writing log messages to: /Users/arungupta/samples/jruby/runner/log/development.log.
    Press Ctrl+C to stop.

    On Solaris and Linux, you can run GlassFish as a daemon as well.
  4. Nginx currently uses a simple round-robin algorithm. Other load balancers such as nginx-upstream-fair (fair proxy) and nginx-ey-balancer (maximum connections) are also available. The built-in algorithm will be used for this blog. Edit "/usr/local/nginx/conf/nginx.conf" to specify an upstream module which provides load balancing:
    1. Create a cluster definition by adding an upstream module (configuration details) right before the "server" module:

      upstream glassfish {
              server 127.0.0.1:3000;
              server 127.0.0.1:3001;
              server 127.0.0.1:3002;
          }

      The cluster specifies a bunch of GlassFish Gem instances running at the backend. Each server can be weighted differently as explained here. The port numbers must exactly match as those specified at the start up. The modified "nginx.conf" looks like:



      The changes are highlighted on lines #35 through #39.
    2. Configure load balancing by specifying this cluster using "proxy_pass" directive as shown below:

      proxy_pass http://glassfish;

      in the "location" module. The updated "nginx.conf" looks like:



      The change is highlighted on line #52.
  5. Restart nginx by using the following commands:

    sudo kill -15 `cat /usr/local/nginx/logs/nginx.pid`
    sudo nginx
Now "http://localhost" shows the default Rails page as shown below:



"http://localhost/runlogs" now serves the page from the deployed Rails application.

Now lets configure logging so that the upstream server IP address and port are printed in the log files. In "nginx.conf", uncomment "log_format" directive and add "$upstream_addr" variable as shown:

    log_format  main  '$remote_addr - [$upstream_addr] $remote_user [$time_local] $request '
                      '"$status" $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;

Also change the log format to "main" by uncommenting "access_log logs/access.log main;" line as shown above (default format is "combined"). Accessing "http://localhost/runlogs" shows the following lines in "logs/access.log":

127.0.0.1 - [127.0.0.1:3000] - [29/Apr/2009:15:27:57 -0700] GET /runlogs/ HTTP/1.1 "200" 3689 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1" "-"
127.0.0.1 - [127.0.0.1:3001] - [29/Apr/2009:15:27:57 -0700] GET /favicon.ico HTTP/1.1 "200" 0 "http://localhost/runlogs/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1" "-"
127.0.0.1 - [127.0.0.1:3002] - [29/Apr/2009:15:27:57 -0700] GET /stylesheets/scaffold.css?1240977992 HTTP/1.1 "200" 889 "http://localhost/runlogs/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1" "-"

The browser makes multiple requests (3 in this case) to load resources on a page and they are nicely load-balanced on the cluster. If an instance running on port 3002 is killed, then the access log show the entries like:

127.0.0.1 - [127.0.0.1:3000] - [29/Apr/2009:15:28:53 -0700] GET /runlogs/ HTTP/1.1 "200" 3689 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1" "-"
127.0.0.1 - [127.0.0.1:3002, 127.0.0.1:3000] - [29/Apr/2009:15:28:53 -0700] GET /favicon.ico HTTP/1.1 "200" 0 "http://localhost/runlogs/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1" "-"
127.0.0.1 - [127.0.0.1:3001] - [29/Apr/2009:15:28:53 -0700] GET /stylesheets/scaffold.css?1240977992 HTTP/1.1 "200" 889 "http://localhost/runlogs/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1" "-"

The second log line shows that server running on port 3002 did not respond and so it automatically fall back to 3000, this is nice!

But this is inefficient because a back-end trip is made even for serving a static file ("/favicon.ico" and "/stylesheets/scaffold.css?1240977992"). This can be easily solved by enabling Rails page caching as described here and here.

More options about logging are described in NginxHttpLogModule and upstream module variables are defined in NginxHttpUpstreamModule.

Here are some nginx resources:
Are you using nginx to front-end your GlassFish cluster ?

Apache + JRuby + Rails + GlassFish = Easy Deployment! shows similar steps if you want to front-end your Rails application running using JRuby/GlassFish with Apache.

Hear all about it in Develop with Pleasure, Deploy with Fun: GlassFish and NetBeans for a Better Rails Experience session at Rails Conf next week.

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: rubyonrails glassfish v3 gem jruby nginx loadbalancing clustering

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

http://blogs.sun.com/arungupta/date/20090429 Wednesday April 29, 2009

TOTD #80: Sinatra CRUD application using Haml templates with JRuby and GlassFish Gem


TOTD #79 showed how to run a trivial Sinatra application using GlassFish Gem. Sinatra provides support for Haml, Erb, Builder, Sass, and Inline templates as described here. This TOTD will show how to get started with creating a Sinatra CRUD application using Haml templates.

Haml is based on one primary principle - Markup should be beautiful because beauty makes you faster.

Get started by installing the Haml gem as:

/tools/jruby-1.2.0 >./bin/jruby -S gem install haml --no-ri --no-rdoc
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Successfully installed haml-2.0.9
1 gem installed

And follow the tutorial, documentation, and reference page for more details.

Sinatra is ORM-agnostic and so any Ruby ORM framework such as ActiveRecord, DataMapper, Sequel, and others. DataMapper with JRuby requires work so this TOTD will show how to use ActiveRecord instead. There is sinatras-hat which allows to create RESTy CRUD apps with Sinatra. There probably are mutiple other ways to create this application but I prefer to understanding the wiring so this blog will use a bare minimal structure.

Anyway, lets get started!
  1. Create the database as:

    ~/tools/jruby/samples/sinatra-sample >mysql --user root
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 664
    Server version: 5.1.30 MySQL Community Server (GPL)

    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

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

    mysql> use hello_development;
    Database changed
    mysql> CREATE TABLE `runners` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `distance` float, `minutes` int(11), `created_at` datetime, `updated_at` datetime);             
    Query OK, 0 rows affected (0.06 sec)

  2. Update "hello.rb" from TOTD #79 such that it looks like:

    require 'rubygems'
    require 'sinatra'
    require 'activerecord'

    ## Setup

    ActiveRecord::Base.establish_connection(
      :adapter  => "jdbcmysql",
      :host     => "localhost",
      :username => "root",
      :password => "",
      :database => "hello_development"
    )

    ## Models

    class Runner < ActiveRecord::Base
    end

    ## Controller Actions

    get '/hi' do
      "Hello World!"
    end

    get '/' do
      @runner = Runner.find(:all)
      haml :index
    end

    get '/new' do
      haml :new
    end

    get '/:id' do
      @runner = Runner.find(params[:id])
      if (@runner)
        haml :show
      else
        redirect '/'
      end
    end

    post '/' do
      @runner = Runner.new(:distance => params[:distance], :minutes => params[:minutes])
      if @runner.save
        redirect "/#{@runner.id}"
      else
        redirect '/'
      end
    end

    Firstly, it pulls in the ActiveRecord dependency. Then "ActiveRecord::Base.establish_connection" is used to establish a connection with the previously created database. "Runner" is tagged as a model class by inheriting from "ActiveRecord::Base" and uses the default table name ("runners" in this case). Add four new methods:
    1. Three GET methods to show all the runners, a form to enter new data, and show a particular log entry. Each method requires a HAML template (will be created in next step) to render the information.
    2. One POST method to save the newly created log entry in the database.
  3. Create a new directory "views" and create the following files in that directory. Each file serves as a view and rendered from an action in "hello.rb".
    1. "index.haml": Show all the runners

      %h1 Listing all runners ...
      %table
        %tr
          %th Distance
          %th Minutes
        - @runner.each do |r|
          %tr
            %td= r.distance
            %td= r.minutes
      %br
      %a{:href=>"/new"}
        New Runner

    2. "new.haml": Enter a new entry

      %h1 Adding a new runner log ...
      %form{:method=>"post", :action=>"/"}
        Distance:
        %input{:type=>"text", :name=>"distance"}
        %br
        Minutes:
        %input{:type=>"text", :name=>"minutes"}
        %br
        %input{:type=>"submit", :value=>"Submit"}
        %br

    3. "show.haml": Show a particular log entry

      %h1 Showing a runner log ...
      Distance:
      = @runner.distance
      %br
      Minutes:
      = @runner.minutes
      %br
      %br
      %a{:href=>"/"}= "Show All!"

      The complete directory structure looks like:

      .
      ./hello.rb
      ./views
      ./views/index.haml
      ./views/new.haml
      ./views/show.haml
That's it, now run the application as:

~/tools/jruby/samples/sinatra-sample >../../bin/jruby -S glassfish
Starting GlassFish server at: 192.168.1.145:3000 in development environment...
Writing log messages to: /Users/arungupta/tools/jruby-1.2.0/samples/sinatra-sample/log/development.log.
Press Ctrl+C to stop.

The main page is available at "http://localhost:3000/" and looks like:



Clicking on "New Runner" gives ...



Enter the data, and click on "Submit" to show ...



Click on "Show All!" to see all the entries added so far ...



And after adding few entries the main page looks like ...



This application shows Create and Read from the CRUD, it's fairly easy to add Update and Delete functionality as well but that's an excercise left for the readers :-)

You'll hear all about it at Develop with Pleasure, Deploy with Fun: GlassFish and NetBeans for a Better Rails Experience at Rails Conf next week.

Technorati: totd glassfish jruby sinatra crud

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

http://blogs.sun.com/arungupta/date/20090428 Tuesday April 28, 2009

TOTD #79: Getting Started with Sinatra applications on JRuby and GlassFish Gem


Sinatra is a DSL for quickly creating web-applications in Ruby with minimal effort. Like Rails and Merb, Sinatra is not an MVC framework and basically follows a flat-file structure instead. The framework define conventions such as location of static files and views, bootstrap, dev/production/test environment variables, filters, helpers, TDD, and much more.  Read Getting Started for complete details. Even though Sinatra is not a MVC framework but sinatra-gen may be used to generate new Sinatra projects.

GlassFish Gem can easily run Rails, Merb, Sinatra, and any other Ruby framework applications based upon Rack. TOTD #70 shows how to run Rails applications and TOTD #53 shows to run Merb applications. This TOTD will explain how to run a trivial Sinatra application. A later blog will describe how to plug a generic Rack-based framework.

Lets see how to get started with Sinatra using JRuby and GlassFish gem.
  1. Install Sinatra gem as:

    ~/tools/jruby >./bin/jruby -S gem install sinatra
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Successfully installed sinatra-0.9.1.1
    1 gem installed
    Installing ri documentation for sinatra-0.9.1.1...
    Installing RDoc documentation for sinatra-0.9.1.1...

  2. Create a directory "sinatra-sample", create a file "hello.rb" in that directory with the contents shown below:

    require 'rubygems'
    require 'sinatra'
    get '/hi' do
      "Hello World!"
    end

  3. Run your sample using GlassFish gem as:

    ~/tools/jruby/samples/sinatra-sample >../../bin/jruby -S glassfish
    Log file /Users/arungupta/tools/jruby-1.2.0/samples/sinatra-sample/log/development.log does not exist. Creating a new one...
    Starting GlassFish server at: 192.168.1.145:3000 in development environment...
    Writing log messages to: /Users/arungupta/tools/jruby-1.2.0/samples/sinatra-sample/log/development.log.
    Press Ctrl+C to stop.

    And then the output is available at "http://localhost:3000/hi" and looks like:


Neat and simple!

You'll hear all about it at Develop with Pleasure, Deploy with Fun: GlassFish and NetBeans for a Better Rails Experience at Rails Conf next week.

Here is the order in which I'll seek any help:
The next blog will show how to create a Sinatra CRUD application and run it using GlassFish.

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

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

http://blogs.sun.com/arungupta/date/20090408 Wednesday April 08, 2009

TOTD #78: GlassFish, EclipseLink, and MySQL efficient pagination using LIMIT

EclipseLink JPA replaces TopLink Essentials as the JPA implementation in GlassFish v3. One of the benefits of using EclipseLink is that it provides efficient pagination support for the MySQL database by generating native SQL statements such as "SELECT ... FROM <table> LIMIT <offset>, <rowcount>".

The MySQL LIMIT clause definition says:

The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement. LIMIT takes one or two numeric arguments, which must both be non-negative integer constants (except when using prepared statements).

With two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. The offset of the initial row is 0 (not 1):

SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

So instead of fetching all rows from the database and then filtering from row 6-15, only rows 6 through 15 are fetched.

This TOTD (Tip Of The Day) explains how to create a JPA Persistence Unit for sakila (MySQL sample database) using NetBeans, use EclipseLink as the Persistence Provider, and then write a JPA query to leverage the pagination support - all on GlassFish v3.

  1. Create a Persistence Unit for "sakila" as explained in this blog using bullets #1 - 3. The differences are explained below:
    1. In 2.1, choose "GlassFish v3 Prelude" as the server. Even though "GlassFish v3 Prelude" is chosen as the server but it will be replaced with a recent promoted build because pagination feature is not implemented in the Prelude. Alternatively you can use NetBeans 6.7 M3 and GlassFish v3 as explained here.
    2. In 3.3, EclipseLink is shown as the default Persistence Provider as shown below:

    3. In 3.5, there is no need to specify the properties for "user" and "password as the JDBC resource is stored in the server configuration. Instead specify the following property:

      <properties>
          <property name="eclipselink.logging.level" value="FINE"/>
      </properties>

      This will log any SQL statement sent by JPA to the underlying persistence provider (EclipseLink in this case).
  2. If GlassFish v3 was configured using NetBeans 6.7 M3, then the JDBC Connection Pool and JDBC resource were created in the server directly. If not, then download and unzip the latest GlassFish v3 latest promoted build (b43 as of this writing). Create the JDBC Connection Pool as:

    ./asadmin create-jdbc-connection-pool --datasourceclassname com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource --property user=duke:password=glassfish:ServerName=localhost:portNumber=3306:databaseName=sakila jdbc-mysql-pool

    and the JDBC resource:

    ./asadmin create-jdbc-resource --connectionpoolid jdbc-mysql-pool jndi/sakila

    GlassFish v3 b43 bundles "Eclipse Persistence Services - 2.0.0.r3652-M1". A later blog will explain how to replace the bundled EclipseLink version with a newer/different EclipseLink version.
  3. Create a new Servlet "QueryServlet". Inject the javax.persistence.EntityManagerFactory resource:

        @PersistenceUnit
        EntityManagerFactory emf;

    and change the "processRequest" operation to:

            EntityManager em = emf.createEntityManager();

            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
            try {
                int startRow = Integer.valueOf(request.getParameter("start_row"));
                int howMany = Integer.valueOf(request.getParameter("how_many"));
                Query q = em.createNamedQuery("Film.findAll");

                q.setFirstResult(startRow);
                q.setMaxResults(startRow + howMany);
                for (Object film : q.getResultList()) {
                    out.print(((Film)film).toString() + "<br/>");
                }
            } finally {
                out.close();
            }

    This Servlet reads two parameters from the request and sets parameters on the JPA Query to enable pagination.
  4. Deploy the application on GlassFish v3.
    1. Using NetBeans 6.7 M3, select "Deploy" from the context-sensitive menu.
    2. Using NetBeans 6.5.1, select "Clean and Build" and then manually deploy the WAR file using "asadmin deploy dist/Pagination.war".
If the project name was "Pagination", then the Servlet is accessible at "http://localhost:8080/Pagination/QueryServlet?start_row=1&how_many=10" and shows ten rows starting at index "1". The output looks like:



The log file in "domains/domain1/logs/server.log" show the following SQL query generated by EclipseLink:

[#|2009-04-07T14:01:12.815-0700|FINE|glassfish|org.eclipse.persistence.session.file: /Users/arungupta/tools/glassfish/v3/b43/glassfishv3/glassfish/domains/domain1/applications/Pagination/WEB-INF/classes/-PaginationPU.sql| _ThreadID=15;_ThreadName=Thread-1;ClassName=null;MethodName=null;|SELECT film_id AS film_id1, special_features AS special_features2, last_update AS last_update3, rental_duration AS rental_duration4, release_year AS release_year5, title AS title6, description AS description7, replacement_cost AS replacement_cost8, length AS length9, rating AS rating10, rental_rate AS rental_rate11, language_id AS language_id12, original_language_id AS original_language_id13 FROM film LIMIT ?, ?
        bind => [1, 11]|#]

As you can see, the query uses the LIMIT clause which optimizes the data returned from the table.

If a different database, for example Derby, is used then the generated SQL query looks like as:

[#|2009-04-07T17:00:34.210-0700|FINE|glassfish|org.eclipse.persistence.session.file: /Users/arungupta/tools/glassfish/v3/b43/glassfishv3/glassfish/domains/domain1/applications/Pagination/WEB-INF/classes/-PaginationPU.sql| _ThreadID=15;_ThreadName=Thread-1;ClassName=null;MethodName=null;|SELECT film_id, special_features, last_update, rental_duration, release_year, title, description, replacement_cost, length, rating, rental_rate, language_id, original_language_id FROM film|#]

In this case, the entire table is fetched and the rows are filtered based upon the critieria specified on the client side.

If the number of rows is huge (a typical case for enterprise) then MySQL provides efficient fetching of records. And GlassFish v3, with EclipseLink JPA integrated, makes it much seamless for you.

Thanks to Mr GlassFish Persistence (aka Mitesh :) for helping me understand the inner workings.

Discuss this more at Creating Quick and Powerful Web Applications with MySQL, GlassFish, and NetBeans technical session in the upcoming MySQL Users Conference!

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

Technorati: totd glassfish v3 eclipselink jpa mysql

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

http://blogs.sun.com/arungupta/date/20090403 Friday April 03, 2009

TOTD # 77: Running Seam examples with GlassFish

Seam is a full-stack solution to assemble complex web applications using simple annotated classes, a rich set of UI components, and very little XML. It integrates Ajax and Business Process Modeling with several Java EE technologies such as Java Server Faces (JSF), Java Persistence API (JPA), and Enterprise Java Beans (EJB 3.0).

GlassFish is a Java EE compliant application server so it's natural to pick GlassFish as your deployment platform for Seam applications :)

This blog is going to show how Seam samples can be easily run on GlassFish.
  1. Download Seam 2.1.1 GA from here and unzip.
  2. Build "examples/jpa" sample as:

    ~/tools/jboss-seam-2.1.1.GA/examples/jpa >ant glassfish
    Buildfile: build.xml

    glassfish:

    initcopy:

    initpoms:
         [echo] Setting up dependencies
        [mkdir] Created dir: /Users/arungupta/tools/jboss-seam-2.1.1.GA/classes/poms
         [copy] Copying 1 file to /Users/arungupta/tools/jboss-seam-2.1.1.GA/classes/poms
    [artifact:install] [INFO] Installing /Users/arungupta/tools/jboss-seam-2.1.1.GA/classes/poms/root.pom to . . .

    . . .

    init.war:

    war:
         [copy] Copying 27 files to /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jpa/exploded-archives-glassfish/jboss-seam-jpa.war
         [copy] Copying 7 files to /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jpa/exploded-archives-glassfish/jboss-seam-jpa.war/WEB-INF/lib

    noejb.war:
         [copy] Copying 18 files to /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jpa/exploded-archives-glassfish/jboss-seam-jpa.war/WEB-INF/lib
         [copy] Copying 2 files to /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jpa/exploded-archives-glassfish/jboss-seam-jpa.war
         [copy] Copying 4 files to /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jpa/exploded-archives-glassfish/jboss-seam-jpa.war

    distributable.war:

    noejb.archive:
          [jar] Building jar: /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jpa/dist-glassfish/jboss-seam-jpa.war

    BUILD SUCCESSFUL
    Total time: 5 seconds
  3. Deploy the sample as:

    ~/tools/jboss-seam-2.1.1.GA/examples/jpa >~/tools/glassfish/v2.1/glassfish/bin/asadmin deploy dist-glassfish/jboss-seam-jpa.war
    Command deploy executed successfully.

    The app is now accessible at "http://localhost:8080/jboss-seam-jpa" and here are some of the captured screenshots:







    Simple and easy!
  4. Build "examples/hibernate" as:

    ~/tools/jboss-seam-2.1.1.GA/examples/hibernate >ant glassfish
    Buildfile: build.xml

    glassfish:

    initcopy:

    initpoms:
         [echo] Setting up dependencies
         [copy] Copying 1 file to /Users/arungupta/tools/jboss-seam-2.1.1.GA/classes/poms
    [artifact:install] [INFO] Installing /Users/arungupta/tools/jboss-seam-2.1.1.GA/classes/poms/root.pom to /Users/arungupta/.m2/repository/org/jboss/seam/root/2.1.1.GA/root-2.1.1.GA.pom

     . . .

    distributable.war:

    noejb.archive:
          [jar] Building jar: /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/hibernate/dist-glassfish/jboss-seam-hibernate.war

    BUILD SUCCESSFUL
    Total time: 6 seconds

  5. Deploy the sample as:

    ~/tools/jboss-seam-2.1.1.GA/examples/hibernate >~/tools/glassfish/v2.1/glassfish/bin/asadmin deploy dist-glassfish/jboss-seam-hibernate.war
    Command deploy executed successfully.

    The app is now accessible at "http://localhost:8080/jboss-seam-hibernate" and has exactly similar snapshots as shown in "jboss-seam-jpa" sample. Simple and easy, yet again!
  6. Build "examples/jee5/booking" and deploy as:

    ~/tools/jboss-seam-2.1.1.GA/examples/jee5/booking >ant
    Buildfile: build.xml

    initcopy:

    initpoms:
         [echo] Setting up dependencies
         [copy] Copying 1 file to /Users/arungupta/tools/jboss-seam-2.1.1.GA/classes/poms
    [artifact:install] [INFO] Installing /Users/arungupta/tools/jboss-seam-2.1.1.GA/classes/poms/root.pom to /Users/arungupta/.m2/repository/org/jboss/seam/root/2.1.1.GA/root-2.1.1.GA.pom
         [copy] Copying 1 file to /Users/arungupta/tools/jboss-seam-2.1.1.GA/classes/poms

    . . .

    archive:
          [jar] Building jar: /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jee5/booking/dist/jboss-seam-jee5-booking.jar
          [jar] Building jar: /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jee5/booking/dist/jboss-seam-jee5-booking.war
          [jar] Building jar: /Users/arungupta/tools/jboss-seam-2.1.1.GA/examples/jee5/booking/dist/jboss-seam-jee5-booking.ear

    BUILD SUCCESSFUL
    Total time: 5 seconds
    ~/tools/jboss-seam-2.1.1.GA/examples/jee5/booking >~/tools/glassfish/v2.1/glassfish/bin/asadmin deploy dist/jboss-seam-jee5-booking.ear
    Command deploy executed successfully.

    The application is now accessible at "http://localhost:8080/seam-jee5-booking". Wow, that's simple and easy as well!
So we have deployed multiple Seam samples on GlassFish v2.1 - simple and easy!

Here are some more useful pointers realted to Seam and GlassFish:
  • Chapter 39 of the Seam Community Documentation even describes how to deploy an application created using seam-gen on GlassFish.
  • Dan Allen, the author of Manning's Seam in Action, presented a webinar at TheAquarium Online.
  • Several other Seam entries @ TA.
  • Deploying a seam-gen project to GlassFish (blog entry) - Here is a quote from the blog:

    GlassFish has a very sexy administrative console, but it also has a very sexy commandline tool known as asadmin. The asadmin tool gives you virtually unbounded control over the application server, including core tasks such as starting and stopping the application server, deploying and undeploying applications, and setting up database connection pools, amidst a plethora of other controls. You'll see that my modified seam-gen tool takes advantage of a handful of these commands.

    And another one ...

    GlassFish gives you efficiency through automation, which is undoubtedly the most effective way to become efficient. ... GlassFish volunteers itself to participate in a script and is the reason why I choose it as my preferred application server.
  • GlassFish support added to seam-gen: It is certainly exciting to know that there are targets like "gf-deploy-datasource", "gf-deploy-hibernate", and "gf-prepare" available to Seam developers out-of-the-box.
  • Sample Application using JSF, Seam, and Java Persistence APIs on GlassFish - detailed step-by-step blog explaining how to run Seam applications on GlassFish
The other samples in the bundle (that I tried) rely upon non-Java EE jars in the App Server's classpath. A slight build file tweaking can bundle those jars in the application itself and will allow to run them as well.

Are you deploying your Seam applications on GlassFish ?

Happy Seaming on GlassFish!

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

Technorati: totd seam glassfish javaee javaserverfaces ejb jpa

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

http://blogs.sun.com/arungupta/date/20090320 Friday March 20, 2009

TOTD # 76: JRuby 1.2, Rails 2.3, GlassFish Gem 0.9.3, ActiveRecord JDBC Adapter 0.9.1 - can they work together ?


Oh, what a week for the JRuby, Rails, and GlassFish enthusiasts!

JRuby 1.2, Rails 2.3GlassFish Gem 0.9.3, and ActiveRecord JDBC Adapater 0.9.1 - all released earlier this week. This is an opportune moment to run the integration tests to ensure the latest JRuby and GlassFish versions work nicely with each other.

First, lets see whats there to get exicted in each release.

JRuby 1.2 introduces a new versioning scheme by jumping from 1.1.6 -> 1.2. JRUBY-3649 is an important fix for the Windows users. Improved Ruby 1.9 support, 3-6x faster parsing, and preliminary android support are some other highlights. 1052 revisions and 256 bugfixes since 1.1.6 (89 days ago) means close to 12 revisions / day and 3 bugfixes/day!

Rails 2.3 has a bunch of highlights ranging from Rack integration, nested forms, attributes, and transactions, reconnecting lost MySQL connections, Application controller renamed (make sure to "rake rails:update:action_controller" to update from an older version), faster boot time in dev mode using lazy loading, and many others. The Release Notes provide all the detailed information.

The GlassFish Gem with features like running as daemon,  rake-style configuration of JVM options, ability to "sudo install" gem and run as normal user and multi-level logging are all gearing towards adding more production-quality features. My favorite here is running as daemon since that brings the Gem one step closer to the Rails community.

Lets get back to running our tests #1, #2, #3, #4, and #5 for these released versions.

First, lets unzip JRuby 1.2 and install Rails 2.3, GlassFish Gem 0.9.3, and other gems as:

~/tools/jruby-1.2.0 >./bin/jruby -S gem install rails glassfish activerecord-jdbcmysql-adapter
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Successfully installed activesupport-2.3.2
Successfully installed activerecord-2.3.2
Successfully installed actionpack-2.3.2
Successfully installed actionmailer-2.3.2
Successfully installed activeresource-2.3.2
Successfully installed rails-2.3.2
Successfully installed rack-0.9.1
Successfully installed glassfish-0.9.3-universal-java
Successfully installed activerecord-jdbc-adapter-0.9.1
Successfully installed jdbc-mysql-5.0.4
Successfully installed activerecord-jdbcmysql-adapter-0.9.1
11 gems installed
Installing ri documentation for activesupport-2.3.2...
Installing ri documentation for activerecord-2.3.2...
Installing ri documentation for actionpack-2.3.2...
Installing ri documentation for actionmailer-2.3.2...
Installing ri documentation for activeresource-2.3.2...
Installing ri documentation for rack-0.9.1...
Installing ri documentation for glassfish-0.9.3-universal-java...
Installing ri documentation for activerecord-jdbc-adapter-0.9.1...
Installing ri documentation for jdbc-mysql-5.0.4...
Installing ri documentation for activerecord-jdbcmysql-adapter-0.9.1...
Installing RDoc documentation for activesupport-2.3.2...
Installing RDoc documentation for activerecord-2.3.2...
Installing RDoc documentation for actionpack-2.3.2...
Installing RDoc documentation for actionmailer-2.3.2...
Installing RDoc documentation for activeresource-2.3.2...
Installing RDoc documentation for rack-0.9.1...
Installing RDoc documentation for glassfish-0.9.3-universal-java...
Installing RDoc documentation for activerecord-jdbc-adapter-0.9.1...
Installing RDoc documentation for jdbc-mysql-5.0.4...
Installing RDoc documentation for activerecord-jdbcmysql-adapter-0.9.1...

If you have a previous version of GlassFish gem installed, then update it as:

~/tools/jruby-1.1.6 >./bin/jruby -S gem update glassfish
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Updating installed gems
Updating glassfish
Successfully installed glassfish-0.9.3-universal-java
Gems updated: glassfish

Similarly ActiveRecord gem can be updated as:

~/tools/jruby-1.1.6 >./bin/jruby -S gem update activerecord
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Updating installed gems
Updating activerecord-jdbc-adapter
Successfully installed activerecord-jdbc-adapter-0.9.1
Updating activerecord-jdbcmysql-adapter
Successfully installed activerecord-jdbcmysql-adapter-0.9.1
Updating activerecord-jdbcsqlite3-adapter
Successfully installed jdbc-sqlite3-3.6.3.054
Successfully installed activerecord-jdbcsqlite3-adapter-0.9.1
Updating merb_activerecord
Successfully installed merb_activerecord-1.0.0.1
Gems updated: activerecord-jdbc-adapter, activerecord-jdbcmysql-adapter, jdbc-sqlite3, activerecord-jdbcsqlite3-adapter, merb_activerecord

Running test #1 encounters JRUBY-3502, basically "db:create" is not working with JRuby 1.2.0, Rails 2.3.2 and MySQL ActiveRecord JDBC Adapter. However "db:create" works if JRuby 1.2.0 and Rails 2.2.2 are used. Alternatively SQLite3 ActiveRecord JDBC Adapter may be used. So first lets install SQLite3 JDBC adapter as:

~/tools/jruby-1.2.0 >./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 jdbc-sqlite3-3.6.3.054
Successfully installed activerecord-jdbcsqlite3-adapter-0.9.1
2 gems installed
Installing ri documentation for jdbc-sqlite3-3.6.3.054...
Installing ri documentation for activerecord-jdbcsqlite3-adapter-0.9.1...
Installing RDoc documentation for jdbc-sqlite3-3.6.3.054...
Installing RDoc documentation for activerecord-jdbcsqlite3-adapter-0.9.1...

Now lets recreate our application without specifying "-d mysql" switch as:

~/tools/jruby-1.2.0/samples/rails >../../bin/jruby -S rails runner
      create 
      create  app/controllers
      create  app/helpers
. . .
      create  log/production.log
      create  log/development.log
      create  log/test.log

In the generated "config/database.yml", change the database adapter from:

development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

to

development:
  adapter: jdbcsqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

The changes are highlighted in bold. Run the remainder of test #1.

The supported Rails version on GlassFish v3 Prelude is Rails 2.1 so we'll stick with running a Rails 2.1 (instead of Rails 2.3.2) simple scaffold application but will use the latest JRuby 1.2.0. Running a Rails 2.3.2 on GlassFish v3 Prelude will encounter issue #7384. Please add your comments to the bug report if you are running GlassFish v3 Prelude in production and would like this bug to be fixed!

Rails 2.3.2 require workaround for a WAR-based deployment of a Rails application as expained here. This workaround is required only if you are using JRuby-Rack 0.9.1 or lower. A newer version of JRuby-Rack may solve these problems making these steps optional. The steps are anyway outlined below for convenience:
  1. Uncomment the following line from "config/initializers/session_initializers.rb":

    ActionController::Base.session_store = :active_record_store
  2. Do "jruby -S warble config" to generate the template "config/warble.rb", edit it and add the following line:

    config.webxml.jruby.session_store = 'db'
  3. In "config/environment.rb", add the following code:

     if defined?(JRUBY_VERSION)
     # hack to fix jruby-rack's incompatibility with rails edge
     module ActionController
       module Session
         class JavaServletStore
           def initialize(app, options={}); end
           def call(env); end
         end
       end
     end
    end 

    just above the line "Rails::Initializer.run do |config|".
Always refer to JRuby/Rails 2.3.2 wiki for the latest information on these steps.

The deployment goes fine after making the changes but bringing up the scaffold page in the browser shows the following error message:


So commented the "jndi" and "driver" entry from "config/database.yml" such that the bundled MySQL JDBC Adapter is used instead. And then the test passes.

Here is a status report after running all the tests:

Test # Description Status
#1 Simple Scaffold using GlassFish Gem PASS (with workaround in JRUBY-3502)
#2 Simple Scaffold using GlassFish v3 Prelude PASS
#3 Simple Scaffold using GlassFish v3 FAIL (used workaround mentioned in JRUBY-3502,  issues #7266, #7270, #7271 still need to be fixed). PASS if the Application and Controller name are different.
#4 Simple Scaffold as WAR-based application on GlassFish v2.1 FAIL (issue #7385), PASS (with workaround in issue JRUBY-3515)
#5 Redmine using GlassFish Gem PASS

It's certainly exciting to know that @grantmichaels is already using the latest version of GlassFish Gem and Rails in production :)

JRuby/GlassFish Wiki provide a list of other known JRuby/Rails/GlassFish deployments in production. Leave a comment on this blog if you are using it as well and we'll be happy to add your name!

The complete set of tests are available using the tags rubyonrails+glassfish+integrationtest. So to answer the title of this blog - YES, JRuby 1.2.0, Rails 2.3.2, GlassFish Gem 0.9.3, ActiveRecord JDBC Adapater 0.9.1 all work together with the restrictions stated above. GlassFish v3 is a moving target and the bugs will be fixed soon. JRUBY-3515 is what delayed this entry otherwise would've posted it much earlier ;-)

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 rubyonrails glassfish v3 gem jruby sampleapp activerrecord redmine integrationtest

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

http://blogs.sun.com/arungupta/date/20090318 Wednesday March 18, 2009

TOTD #75: Getting Started with Grails using GlassFish v3 Embedded


For a change, this blog entry is talking about something that exists for a while now :)

Basically, I wanted to setup a demo environment for Grails and GlassFish v3 Prelude on my machine and so decided to dcument the steps along the process. More detailed steps with explanation are available on GlassFish/Grails Getting Started Wiki.

  1. Download and unzip GlassFish v3 Prelude.
  2. Run GlassFish Update Center to install the Grails module as shown:

    ~/demos/glassfishv3-prelude >./bin/updatetool

    The software needed for this command (updatetool) is not installed.

    If you choose to install Update Tool, your system will be automatically
    configured to periodically check for software updates. If you would like
    to configure the tool to not check for updates, you can override the
    default behavior via the tool's Preferences facility.

    When this tool interacts with package repositories, some system information
    such as your system's IP address and operating system type and version
    is sent to the repository server. For more information please see:

    http://wiki.updatecenter.java.net/Wiki.jsp?page=UsageMetricsUC2

    Once installation is complete you may re-run this command.

    Would you like to install Update Tool now (y/n): y

    Install image: /Users/arungupta/demos/glassfishv3-prelude/bin/..
    Installing pkg packages.
    Installing: [pkg:/pkg@1.0.7,0-15.1269:20081008T212532Z, pkg:/python2.4-minimal@2.4.5.0,0-15.1269:20081008T212544Z]
    Installing updatetool packages.
    Installing: [pkg:/updatetool@2.0.0,0-15.1269:20081008T212613Z, pkg:/wxpython2.8-minimal@2.8.8,0-15.1269:20081008T212630Z]
    Registering notifier: Already registered.
    Initialization complete.

    Software successfully installed. You may now re-run this command (updatetool).
  3. Now run the Update Center again to see a screen as shown below:


  4. Select "GlassFish support for Grails Framework" and click on "Install" to install the module locally. This creates a new directory "grails" in your GlassFish v3 Prelude directory and install Grails 1.0.4 there.
  5. Set environment variables as:

    ~/demos/glassfishv3-prelude/glassfish/grails >export GRAILS_HOME=~/demos/glassfishv3-prelude/glassfish/grails
    ~/demos/glassfishv3-prelude/glassfish/grails >export PATH=$GRAILS_HOME/bin:$PATH

  6. Create a template application as:

    ~/demos/glassfishv3-prelude/glassfish/grails/samples >grails create-app bookstore

    Welcome to Grails 1.0.4 - http://grails.org/
    Licensed under Apache Standard License 2.0
    Grails home is set to: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails

    Base Directory: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples
    Note: No plugin scripts found
    Running script /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/scripts/CreateApp.groovy
    Environment set to development
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/src
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/src/java
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/src/groovy
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/controllers
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/services
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/domain
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/taglib
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/utils
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/views
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/views/layouts
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/i18n
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/conf
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/test
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/test/unit
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/test/integration
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/scripts
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app/js
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app/css
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app/images
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app/META-INF
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/lib
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/conf/spring
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/conf/hibernate
    [propertyfile] Creating new property file: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/application.properties
         [copy] Copying 2 files to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
         [copy] Copied 1 empty directory to 1 empty directory under /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
         [copy] Copying 2 files to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app/WEB-INF
         [copy] Copying 5 files to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app/WEB-INF/tld
         [copy] Copying 28 files to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app
         [copy] Copying 18 files to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app
         [copy] Copying 1 file to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
         [copy] Copying 1 file to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
         [copy] Copying 1 file to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
         [copy] Copying 1 file to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
    [propertyfile] Updating property file: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/application.properties
    Created Grails Application at /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore

  7. Create a domain specific class as:

    ~/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore >grails create-domain-class book

    Welcome to Grails 1.0.4 - http://grails.org/
    Licensed under Apache Standard License 2.0
    Grails home is set to: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails

    Base Directory: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
    Note: No plugin scripts found
    Running script /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/scripts/CreateDomainClass.groovy
    Environment set to development
         [copy] Copying 1 file to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/domain
    Created Domain Class for Book
         [copy] Copying 1 file to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/test/integration
    Created Tests for Book

  8. Add attributes to the domain class by editing "grails-app/domain/Book.groovy" such that it looks like:

    class Book {
      String title
      String author
    }

  9. Create a new controller as:

    ~/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore >grails create-controller Book

    Welcome to Grails 1.0.4 - http://grails.org/
    Licensed under Apache Standard License 2.0
    Grails home is set to: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails

    Base Directory: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
    Note: No plugin scripts found
    Running script /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/scripts/CreateController.groovy
    Environment set to development
         [copy] Copying 1 file to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/controllers
    Created Controller for Book
        [mkdir] Created dir: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/views/book
         [copy] Copying 1 file to /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/test/integration
    Created ControllerTests for Book
  10. Edit the generated controller in "grails-app/controller/BookController.groovy" to specify scaffold for the domain class. It looks like:

    class BookController {
        def scaffold = Book
    }
  11. Run the app as shown below:

    ~/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore >grails run-app

    Welcome to Grails 1.0.4 - http://grails.org/
    Licensed under Apache Standard License 2.0
    Grails home is set to: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails

    Base Directory: /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore
    Note: No plugin scripts found
    Running script /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/scripts/RunApp.groovy
    Environment set to development
    Starting GlassFish embedded server...    [mkdir] Created dir: /Users/arungupta/.grails/1.0.4/projects/bookstore/classes
      [groovyc] Compiling 8 source files to /Users/arungupta/.grails/1.0.4/projects/bookstore/classes
        [mkdir] Created dir: /Users/arungupta/.grails/1.0.4/projects/bookstore/resources/grails-app/i18n
    [native2ascii] Converting 11 files from /Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/grails-app/i18n to /Users/arungupta/.grails/1.0.4/projects/bookstore/resources/grails-app/i18n
         [copy] Copying 1 file to /Users/arungupta/.grails/1.0.4/projects/bookstore/classes
         [copy] Copying 1 file to /Users/arungupta/.grails/1.0.4/projects/bookstore/resources
         [copy] Copying 1 file to /Users/arungupta/.grails/1.0.4/projects/bookstore
    Running Grails application..
    Application name : bookstore
    Web App Root :/Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app
    web.xml:/Users/arungupta/.grails/1.0.4/projects/bookstore/resources/web.xml
    Mar 18, 2009 10:19:09 PM CommonClassLoaderManager Skipping creation of CommonClassLoader as there are no libraries available
    INFO: urls = []
    no resource bundle found for version, using default GlassFish version
    Mar 18, 2009 10:19:09 PM AppServerStartup run
    INFO: [Thread[GlassFish Kernel Main Thread,5,main]] started
    Mar 18, 2009 10:19:09 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
    INFO: Listening on port 8080
    Mar 18, 2009 10:19:10 PM org.glassfish.admin.mbeanserver.ConnectorStartupService$ConnectorsStarterThread startConnector
    INFO: Started JMXConnector, JMXService URL = service:jmx:rmi:///jndi/rmi://192.168.1.145:8686/jmxrmi
    Mar 18, 2009 10:19:10 PM com.sun.enterprise.v3.admin.adapter.AdminEndpointDecider setGuiContextRoot
    INFO: Admin Console Adapter: context root: /admin
    Mar 18, 2009 10:19:10 PM com.sun.enterprise.v3.server.AppServerStartup run
    INFO: GlassFish v3 Prelude startup time : Embedded(418ms) startup services(887ms) total(1305ms)
    Mar 18, 2009 10:19:10 PM com.sun.enterprise.web.WebContainer createHttpListener
    INFO: Created HTTP listener http-listener-1 on port 8080
    Mar 18, 2009 10:19:10 PM com.sun.enterprise.web.WebContainer createHosts
    INFO: Created virtual server server
    Mar 18, 2009 10:19:11 PM org.apache.catalina.loader.WebappLoader setClassPath
    INFO: Unknown loader org.glassfish.grails.MaskingClassLoader@3b948e75 class org.glassfish.grails.MaskingClassLoader
    Mar 18, 2009 10:19:12 PM org.apache.catalina.loader.WebappLoader setClassPath
    INFO: Unknown loader org.glassfish.internal.api.DelegatingClassLoader@191fa2af class org.glassfish.internal.api.DelegatingClassLoader
    Mar 18, 2009 10:19:12 PM org.apache.catalina.core.ApplicationContext log
    INFO: PWC1412: WebModule[/bookstore] ServletContext.log():Set web app root system property: 'bookstore-development-0.1' = [/Users/arungupta/demos/glassfishv3-prelude/glassfish/grails/samples/bookstore/web-app/]
    Mar 18, 2009 10:19:12 PM org.apache.catalina.core.ApplicationContext log
    INFO: PWC1412: WebModule[/bookstore] ServletContext.log():Initializing log4j from [file:/Users/arungupta/.grails/1.0.4/projects/bookstore/resources/log4j.properties]
    Mar 18, 2009 10:19:12 PM org.apache.catalina.core.ApplicationContext log
    INFO: PWC1412: WebModule[/bookstore] ServletContext.log():Initializing Spring root WebApplicationContext
    [0] spring.GrailsWebApplicationContext Refreshing org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext@430b4506: display name [org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext@430b4506]; startup date [Wed Mar 18 22:19:14 PDT 2009]; parent: org.springframework.web.context.support.XmlWebApplicationContext@6ceb51a8
    [0] spring.GrailsWebApplicationContext Bean factory for application context [org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext@430b4506]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1f43243e
    Mar 18, 2009 10:19:17 PM org.apache.catalina.core.ApplicationContext log
    INFO: PWC1412: WebModule[/bookstore] ServletContext.log():Initializing Spring FrameworkServlet 'grails'
    Mar 18, 2009 10:19:17 PM com.sun.enterprise.web.WebApplication start
    INFO: Loading application bookstore at /bookstore
    Server running. Browse to http://localhost:8080/bookstore

    Notice, here GlassFish v3 Embedded Server is used for running the application. It is now accessible at "http://localhost:8080/bookstore" and looks like:



  12. Clicking on the "BookController" shows:


  13. Click on "New Book" to add a new book as:

  14. Each entry can be updated/deleted after clicking on "Create" ...



    or "Book List" as shown below:



In a matter of few minutes, we created a simple Grails scaffold that runs using GlassFish v3 Embedded Server.

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 glassfish v3 grails embedded prelude

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

http://blogs.sun.com/arungupta/date/20090316 Monday March 16, 2009

TOTD # 74: JRuby and GlassFish Integration Test #5: JRuby 1.2.0 RC2 + Rails 2.x.x + GlassFish + Redmine


TOTD #70, #71, #72, #73 shows four integration tests that can ensure that the latest JRuby and GlassFish versions work nicely with each other.

#70 showed how to create a trivial Rails application and run it using GlassFish Gem#71 showed how the same application can be deployed on GlassFish v3 Prelude#72 showed how to deploy the same application on GlassFish v3. #73 showed how to deploy a Rails application as WAR file and use the JDBC connection pooling framework available in GlassFish.

The next set of tests ensure that some commonly used open source Rails applications can be easily run using this setup. The first one is Redmine - 0.8 is the stable release now. Redmine was first tried on GlassFish a few months ago. The steps have simplified since then :)

Lets begin integration test #5.

  1. Download Redmine 0.8 ...

    /samples/jruby/redmine >svn co http://redmine.rubyforge.org/svn/branches/0.8-stable redmine-0.8
    A    redmine-0.8/test
    A    redmine-0.8/test/unit
    A    redmine-0.8/test/unit/document_test.rb
    A    redmine-0.8/test/unit/token_test.rb
    . . .
    A    redmine-0.8/public/stylesheets/scm.css
    A    redmine-0.8/public/stylesheets/application.css
    A    redmine-0.8/public/favicon.ico
     U   redmine-0.8
    Checked out revision 2580.
  2. Copy "config/database.yml.example" to "config/database.yml" and then generate/migrate the database:

    ~/samples/jruby/redmine/redmine-0.8 >../jruby-1.2.0RC2/bin/jruby -S rake db:create
    (in /Users/arungupta/samples/jruby/redmine/redmine-0.8)
    ~/samples/jruby/redmine/redmine-0.8 >../jruby-1.2.0RC2/bin/jruby -S rake db:migrate
    (in /Users/arungupta/samples/jruby/redmine/redmine-0.8)
    == 1 Setup: migrating =========================================================
    -- create_table("attachments", {:force=>true})
       -> 0.0880s
    -- create_table("auth_sources", {:force=>true})
       -> 0.1430s
    . . .
    == 100 AddChangesetsUserId: migrating =========================================
    -- add_column(:changesets, :user_id, :integer, {:default=>nil})
       -> 0.0980s
    == 100 AddChangesetsUserId: migrated (0.0990s) ================================

    == 101 PopulateChangesetsUserId: migrating ====================================
    == 101 PopulateChangesetsUserId: migrated (0.0030s) ===========================

  3. Redmine is a Rails 2.1.x application so install Rails 2.1.x using JRuby 1.2 and run the application as:

    ~/samples/jruby/redmine/redmine-0.8 >../jruby-1.2.0RC2/bin/jruby -S glassfish
    Mar 13, 2009 11:14:59 AM com.sun.enterprise.glassfish.bootstrap.ASMainStatic findDerbyClient
    INFO: Cannot find javadb client jar file, jdbc driver not available
    Mar 13, 2009 11:14:59 AM APIClassLoaderService createAPIClassLoader
    INFO: APIClassLoader = java.net.URLClassLoader@59fb8de1
    . . .
    Mar 13, 2009 11:15:10 AM com.sun.grizzly.pool.DynamicPool$1 run
    INFO: New instance created in 10,175 milliseconds
    Mar 13, 2009 11:15:10 AM com.sun.enterprise.v3.server.AppServerStartup run
    INFO: GlassFish v3  startup time : Static(356ms) startup services(11456ms) total(11812ms)

    Very simple and seamless!
The application is now accessible at "http://locahost:3000". The following screen dumps are captured by traversing through different parts of the application:















The next blog will show the last test in this series. The current set of tests are available using the tags rubyonrails+glassfish+integrationtest.

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 rubyonrails glassfish v3 gem jruby sampleapp redmine integrationtest

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

http://blogs.sun.com/arungupta/date/20090311 Wednesday March 11, 2009

TOTD # 73: JRuby and GlassFish Integration Test #4: JRuby 1.2.0 RC2 + Rails 2.2.x + GlassFish v2 + Warbler


TOTD #70, #71, #72 shows the first three integration tests that I typically run to ensure that the latest JRuby and GlassFish versions work nicely with each other.  #70 showed how to create a trivial Rails application and run it using GlassFish Gem#71 showed how the same application can be deployed on GlassFish v3 Prelude#72 showed how to deploy the same application on GlassFish v3.

The next test in the series is to ensure WAR-based deployment of a Rails application continue to work on GlassFish v2. It also shows that JNDI database connection pooling also work as expected. The latest publicly available build is GlassFish v2.1.

Lets begin integration test #4.

  1. Install Warbler gem ...

    ~/tools/jruby-1.2.0RC2/samples/rails/runner >../../../bin/jruby -S gem install warbler
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Successfully installed warbler-0.9.12
    1 gem installed
    Installing ri documentation for warbler-0.9.12...
    Installing RDoc documentation for warbler-0.9.12...
  2. Edit "config/database.yml" and change the production database adapater from:

    production:
      adapter: mysql
      encoding: utf8
      database: runner_production
      pool: 5
      username: root
      password:
      socket: /tmp/mysql.sock

    to

    production:
      adapter: jdbcmysql
      encoding: utf8
      database: runner_production
      pool: 5
      username: duke
      password: glassfish
      socket: /tmp/mysql.sock
      jndi: jdbc/runner_production
      driver: com.mysql.jdbc.Driver

    The changes are highlighted in bold.

    Notice "jndi" key/value pair is specified along with "username" and "password". The JNDI reference is created for the GlassFish domain later. The reference is not resolved when this adapter is used with the JRuby CLI and so it falls back to username/password. However this JNDI reference is correctly resolved during runtime when the application is deployed as a WAR file in GlassFish.
  3. Create and migrate the production database as:

    ~/tools/jruby-1.2.0RC1/samples/rails/runner >../../../bin/jruby -S rake db:create RAILS_ENV=production
    (in /Users/arungupta/tools/jruby-1.2.0RC1/samples/rails/runner)
    ~/tools/jruby-1.2.0RC1/samples/rails/runner >../../../bin/jruby -S rake db:migrate RAILS_ENV=production
    (in /Users/arungupta/tools/jruby-1.2.0RC1/samples/rails/runner)
    ==  CreateRunners: migrating ==================================================
    -- create_table(:runners)
       -> 0.1150s
       -> 0 rows
    ==  CreateRunners: migrated (0.1170s) =========================================

    Note, how "RAILS_ENV=production" is specified at the command-line to ensure the production environment.
  4. Copy MySQL Connector/J jar in GLASSFISH_HOME/lib as:

    ~/tools/glassfish/v2.1/glassfish/ >cp ~/tools/mysql-connector-java-5.1.6/mysql-connector-java-5.1.6-bin.jar ./lib

    This is required for connection to the MySQL database.
  5. Fire up GlassFish v2.1 as:

    ~/tools/glassfish/v2.1/glassfish/bin >./asadmin start-domain
    Starting Domain domain1, please wait.
    Default Log location is /Users/arungupta/tools/glassfish/v2.1/glassfish/domains/domain1/logs/server.log.
    Redirecting output to /Users/arungupta/tools/glassfish/v2.1/glassfish/domains/domain1/logs/server.log
    Domain domain1 started.
    Domain [domain1] is running [Sun GlassFish Enterprise Server v2.1 (9.1.1) (build b60e-fcs)] with its configuration and logs at: [/Users/arungupta/tools/glassfish/v2.1/glassfish/domains].
    Admin Console is available at [http://localhost:4848].
    Use the same port [4848] for "asadmin" commands.
    User web applications are available at these URLs:
    [http://localhost:8080 https://localhost:8181 ].
    Following web-contexts are available:
    [/web1  /__wstx-services runner ].
    Standard JMX Clients (like JConsole) can connect to JMXServiceURL:
    [service:jmx:rmi:///jndi/rmi://Macintosh-187.local:8686/jmxrmi] for domain management purposes.
    Domain listens on at least following ports for connections:
    [8080 8181 4848 3700 3820 3920 8686 ].
    Domain supports application server clusters and other standalone instances.

    The logs are created in "domains/domain1/logs/server.log". Optionally, you can specify "--verbose" on the command-line to dump the log on the console itself.
  6. Create JDBC connection pool as:

    ~/tools/glassfish/v2.1/glassfish/bin >./asadmin create-jdbc-connection-pool --datasourceclassname com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource --restype javax.sql.DataSource --property "User=duke:Password=glassfish:URL=jdbc\:mysql\://localhost/runner_production" jdbc/runner_pool
    Command create-jdbc-connection-pool executed successfully.

  7. Create JDBC resource as:

    ~/tools/glassfish/v2.1/glassfish/bin >./asadmin create-jdbc-resource --connectionpoolid jdbc/runner_pool jdbc/runner_production
    Command create-jdbc-resource executed successfully.
  8. Create Warbler config file as:

    ~/tools/jruby-1.2.0RC2/samples/rails/runner >../../../bin/jruby -S warble config
    cp /Users/arungupta/tools/jruby-1.2.0RC2/lib/ruby/gems/1.8/gems/warbler-0.9.12/generators/warble/templates/warble.rb config/warble.rb
  9. Edit "config/warble.rb" to bundle the required gems by adding the following fragment:

     # Include all gems which are used by the web application
      require "#{RAILS_ROOT}/config/environment"
      BUILD_GEMS = %w(warbler rake rcov)
      for gem in Gem.loaded_specs.values
        next if BUILD_GEMS.include?(gem.name)
        config.gems[gem.name] = gem.version.version
      end

    as specified here. And then explicitly specify the runtime gem dependency by adding the following line:

    config.gems += ["activerecord-jdbc-adapter"]

    right after the previous code fragment. The "activerecord-jdbc-adapter" dependency needs to be explicitly included because this is required only at the runtime and so not resolved correctly by the previous code fragment.
  10. And create the WAR file as:

    ~/tools/jruby-1.2.0RC2/samples/rails/runner >../../../bin/jruby -S warble
    mkdir -p tmp/war/WEB-INF/gems/specifications
    cp /Users/arungupta/tools/jruby-1.2.0RC2/lib/ruby/gems/1.8/specifications/rails-2.2.2.gemspec tmp/war/WEB-INF/gems/specifications/rails-2.2.2.gemspec
    mkdir -p tmp/war/WEB-INF/gems/gems
    . . .
    cp public/javascripts/prototype.js tmp/war/javascripts/prototype.js
    cp public/stylesheets/scaffold.css tmp/war/stylesheets/scaffold.css
    mkdir -p tmp/war/WEB-INF
  11. Deploy the WAR file ...

    ~/tools/jruby-1.2.0RC2/samples/rails/runner >~/tools/glassfish/v2.1/glassfish/bin/asadmin deploy runner.war
    Command deploy executed successfully.

    After adding few entries the page at "http://localhost:8080/runner/runners" looks like:


So we are able to deploy a trivial Rails application as WAR file on GlassFish v2.1 and also leverage the JDBC connection pooling, that passes Test# 4.

Later blogs will show the remainder of tests. The current set of tests are available using the tags rubyonrails+glassfish+integrationtest.

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 rubyonrails glassfish v2 jruby warbler connectionpooling jdbc jndi integrationtest

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

http://blogs.sun.com/arungupta/date/20090309 Monday March 09, 2009

TOTD # 72: JRuby and GlassFish Integration Test #3: JRuby 1.2.0 RC2 + Rails 2.2.x + GlassFish v3


TOTD #70 and #71 shows the first two integration tests that I typically run to ensure that the latest JRuby and GlassFish versions work nicely with each other.  #70 showed how to create a trivial Rails application and run it using GlassFish Gem. #71 showed how the same application can be deployed on GlassFish v3 Prelude.

The third test (explained in this blog) ensures that the same application can be easily deployed using GlassFish v3. GlassFish v3 will be available later this year with full support for Java EE 6.

JRuby 1.2.0 RC2 is now released. Test #1 passed, Test #2 gives the following error:

Caused by: java.lang.NumberFormatException: For input string: "0RC2"
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
        at java.lang.Integer.parseInt(Integer.java:456)
        at java.lang.Integer.parseInt(Integer.java:497)
        at com.sun.grizzly.jruby.RailsAdapter$JRubyVersion.<init>(RailsAdapter.java:137)
        at com.sun.grizzly.jruby.RailsAdapter$JRubyVersion.<init>(RailsAdapter.java:131)
        at com.sun.grizzly.jruby.RailsAdapter.<init>(RailsAdapter.java:110)
        at com.sun.grizzly.jruby.RubyRuntime.<init>(RubyRuntime.java:48)
        ... 22 more

However running the same application using JRuby trunk (rev 9372) shows the following output:



So test #2 passes with trunk but fails with RC2 bits. The final release of 1.2 will not have any characters and so this test will pass with the final JRuby 1.2 bits.

Now, lets begin the integration test #3.
  1. Download and unzip the latest GlassFish v3, b39 is the latest at time of this writing. Fire up GlassFish v3 as:

    ~/tools/glassfish/v3/b39/glassfishv3/glassfish >./bin/asadmin start-domain
    Name of the domain started: [domain1] and
    its location: [/Users/arungupta/tools/glassfish/v3/b39/glassfishv3/glassfish/domains/domain1].
    Admin port for the domain: [4848].
  2. Add JRUBY_HOME as "jvm-option" using the following command:

    ~/tools/glassfish/v3/b39/glassfishv3/glassfish >./bin/asadmin create-jvm-options -DJRUBY_HOME="/Users/arungupta/tools/jruby-1.2.0RC2"
    created 1 option(s)

    Command create-jvm-options executed successfully.

    This tells the GlassFish runtime to pick JRuby and related libraries from the directory specified in JRUBY_HOME.
  3. Deploy the application as:

    ~/tools/jruby-1.2.0RC1/samples/rails >~/tools/glassfish/v3/b39/glassfishv3/bin/asadmin deploy runner

    Command deploy executed successfully.
  4. Accessing "http://localhost:8080/runner/runners" gives the error:

    ActionController::RoutingError (No route matches "s" with {:method=>:get}):
        /Users/arungupta/tools/jruby-1.2.0RC1/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/routing/recognition_optimisation.rb:66:in `recognize_path'
        /Users/arungupta/tools/jruby-1.2.0RC1/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/routing/route_set.rb:386:in `recognize'
        /Users/arungupta/tools/jruby-1.2.0RC1/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/dispatcher.rb:182:in `handle_request'
        /Users/arungupta/tools/jruby-1.2.0RC1/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/dispatcher.rb:110:in `dispatch_unlocked'
        /Users/arungupta/tools/jruby-1.2.0RC1/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/dispatcher.rb:123:in `dispatch'
        /Users/arungupta/tools/jruby-1.2.0RC1/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/dispatcher.rb:122:in `dispatch'
        /Users/arungupta/tools/jruby-1.2.0RC1/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/dispatcher.rb:132:in `dispatch_cgi'
        /Users/arungupta/tools/jruby-1.2.0RC1/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/dispatcher.rb:39:in `dispatch'
        file:/Users/arungupta/tools/glassfish/v3/b39/glassfishv3/glassfish/modules/grizzly-jruby.jar!/rack/adapter/rails.rb:82:in `serve_rails'
        file:/Users/arungupta/tools/glassfish/v3/b39/glassfishv3/glassfish/modules/grizzly-jruby.jar!/rack/adapter/rails.rb:109:in `call'
        file:/Users/arungupta/tools/glassfish/v3/b39/glassfishv3/glassfish/modules/grizzly-jruby.jar!/jruby/rack/rails.rb:81:in `call'
        file:/Users/arungupta/tools/glassfish/v3/b39/glassfishv3/glassfish/modules/grizzly-jruby.jar!/rack/handler/grizzly.rb:55:in `call'
        :1

    This resulted in filing issue #7266.
  5. GlassFish v3 allows an application to be deployed/redeployed on a different context root by specifying "--contextroot" switch. Lets try to deploy the app using a different context root as shown below:

    ~/tools/jruby-1.2.0RC1/samples/rails >~/tools/glassfish/v3/b39/glassfishv3/bin/asadmin deploy --contextroot runlog --force=true runner

    Command deploy executed successfully.

    Even though the application is deployed successful, but now "http://localhost:8080/runlog/runners" and "http://localhost:8080/runner/runners" give a 404. This resulted in filing issue #7270 and issue# 7271. The context root strippping does not happen correctly if a Rails application is deployed. But the good news is that a fix is already in progress. A workaround is to create exactly the same application with a different name.
  6. Recreate the application using a name different from the controller. Lets use the name "runlog" and redeploy the application as:

    ~/tools/jruby-1.2.0RC2/samples/rails >~/tools/glassfish/v3/b39/glassfishv3/bin/asadmin deploy runlog

    Command deploy executed successfully.

    After adding few entries the page at "http://localhost:8080/runlog/runners" looks like:


So test #3 fails if the Application and Controller name are same but passes if they are different. Our original application did not run so test #3 failed.

Later blogs will show the remainder of tests. The current set of tests are available using the tags rubyonrails+glassfish+integrationtest.

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 rubyonrails glassfish v3 jruby gem integrationtest

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

http://blogs.sun.com/arungupta/date/20090305 Thursday March 05, 2009

TOTD # 71: JRuby and GlassFish Integration Test #2: JRuby 1.2.0 RC1 + Rails 2.2.x + GlassFish v3 Prelude


TOTD #70 shows the first integration integration tests that I typically run to ensure that the latest JRuby and GlassFish versions work nicely with each other.  The second test (explained in this blog) ensures that the same application can be deployed using GlassFish v3 Prelude.

GlassFish v3 Prelude allows Rails applications to be deployed natively, i.e. without any packaging.

Lets begin integration test #2.

  1. Download and unzip GlassFish v3 Prelude. Fire up GlassFish v3 Prelude as:

    ~/tools/glassfish/v3/glassfishv3-prelude/glassfish >./bin/asadmin start-domain
    Name of the domain started: [domain1] and
    its location: [/Users/arungupta/tools/glassfish/v3/glassfishv3-prelude/glassfish/domains/domain1].
    Admin port for the domain: [4848].
  2. Add JRUBY_HOME as "jvm-option" using the following command:

    ~/tools/glassfish/v3/glassfishv3-prelude/glassfish >./bin/asadmin create-jvm-options -DJRUBY_HOME="/Users/arungupta/tools/jruby-1.2.0RC1"
    created 1 option(s)

    Command create-jvm-options executed successfully.

    This tells the GlassFish runtime to pick JRuby and related libraries from the directory specified in JRUBY_HOME.
  3. Deploy the application as:

    ~/tools/jruby-1.2.0RC1/samples/rails >~/tools/glassfish/v3/glassfishv3-prelude/bin/asadmin deploy runner

    Command deploy executed successfully.

  4. The application should now be accessible on "http://localhost:8080/runner/runners". But instead the logs (located in "domains/domain1/logs/server.log) shows the following exception:

    Caused by: java.lang.NumberFormatException: For input string: "0RC1"
            at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
            at java.lang.Integer.parseInt(Integer.java:456)
            at java.lang.Integer.parseInt(Integer.java:497)
            at com.sun.grizzly.jruby.RailsAdapter$JRubyVersion.<init>(RailsAdapter.java:137)
            at com.sun.grizzly.jruby.RailsAdapter$JRubyVersion.<init>(RailsAdapter.java:131)
            at com.sun.grizzly.jruby.RailsAdapter.<init>(RailsAdapter.java:110)
            at com.sun.grizzly.jruby.RubyRuntime.<init>(RubyRuntime.java:48)
            ... 30 more

    This is filed as issue #7235 in GlassFish Issue Tracker.
  5. Lets try with the JRuby trunk.
    1. Check out JRuby trunk and build the workspace as shown below

      ~/workspaces >svn co http://svn.codehaus.org/jruby/trunk/jruby/
      A    jruby/bench
      A    jruby/bench/bench_tak.rb
      A    jruby/bench/bench_struct.rb

      . . .

      A    jruby/.settings/org.eclipse.jdt.core.prefs
      A    jruby/.settings/org.eclipse.jdt.ui.prefs
       U   jruby
      Checked out revision 9347.
      ~/workspaces >cd jruby/
      ~/workspaces/jruby >ant
      Buildfile: build.xml

      init:

      jar:

      . . .

      _update_scm_revision_:
            [jar] Building jar: /Users/arungupta/workspaces/jruby/lib/jruby.jar
            [jar] Warning: selected jar files include a META-INF/INDEX.LIST which will be replaced by a newly generated one.

      BUILD SUCCESSFUL
      Total time: 1 minute 21 seconds
    2. Install Rails

      ~/workspaces/jruby >./bin/jruby gem install rails
      JRuby limited openssl loaded. gem install jruby-openssl for full support.
      http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
      Successfully installed rake-0.8.4
      Successfully installed activesupport-2.2.2
      Successfully installed activerecord-2.2.2
      Successfully installed actionpack-2.2.2
      Successfully installed actionmailer-2.2.2
      Successfully installed activeresource-2.2.2
      Successfully installed rails-2.2.2
      7 gems installed
      Installing ri documentation for rake-0.8.4...
      Installing ri documentation for activesupport-2.2.2...
      Installing ri documentation for activerecord-2.2.2...
      Installing ri documentation for actionpack-2.2.2...
      Installing ri documentation for actionmailer-2.2.2...
      Installing ri documentation for activeresource-2.2.2...
      Installing RDoc documentation for rake-0.8.4...
      Installing RDoc documentation for activesupport-2.2.2...
      Installing RDoc documentation for activerecord-2.2.2...
      Installing RDoc documentation for actionpack-2.2.2...
      Installing RDoc documentation for actionmailer-2.2.2...
      Installing RDoc documentation for activeresource-2.2.2...
  6. Delete the previously added jvm-option as

    ~/tools/glassfish/v3/glassfishv3-prelude/glassfish >./bin/asadmin delete-jvm-options -DJRUBY_HOME="/Users/arungupta/tools/jruby-1.2.0RC1"
    deleted 1 option(s)

    Command delete-jvm-options executed successfully.

    and add a new jvm-option pointing to the the new JRUBY_HOME as

    ~/tools/glassfish/v3/glassfishv3-prelude/glassfish >./bin/asadmin create-jvm-options -DJRUBY_HOME="/Users/arungupta/workspaces/jruby"
    created 1 option(s)

    Command create-jvm-options executed successfully.
  7. Deploy the application as:

    ~/tools/jruby-1.2.0RC1/samples/rails >~/tools/glassfish/v3/glassfishv3-prelude/bin/asadmin deploy --force=true runner

    Command deploy executed successfully.

    The "NumberFormatException" as seen above is shown again in this case.

    If the application is deployed correctly then "http://localhost:8080/runner/runners" will show the scaffold page. The final JRuby 1.2 release will not have any text letters in the version and so you'll be able to deploy a Rails application using JRuby 1.2 (final release) on GlassFish v3 Prelude.
But for now our test #2 has failed.

Subsequent blogs will show the remainder of tests. The current set of tests are available using the tags rubyonrails+glassfish+integrationtest.

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 rubyonrails glassfish v3 jruby gem integrationtest

del.icio.us | furl | simpy | slashdot | technorati | digg |
|
Main | Next page »

Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.