Wednesday Sep 14, 2011

Automating the Beanstalk Environment

In my last blog, I showed a simple way to get a list of all the configuration options available in an Amazon Elastic Beanstalk environment. These are the options for which no explicit SDK method exists. In this blog, I'll give an example of their use to start up a Beanstalk environment with non-default settings in one step. Using the AWS console, this is normally a two-step process. Note: the AWS command-line tools offer similar capabilities, but using the SDK yields better automation. For instance, after the environment is started, I call a method that waits until the environment is green and all the instances are started.

Before getting to the code, here's a note about how I'm using the credentials. It can be useful to create a separate key pair for each developer or project or however you compartmentalize your work. The AWS key and secret key are tied to an individual account, but commonly are shared within an organization (see the identity faq for more info). You can generate multiple key pairs, however, and can use different pairs for different developers; or use a different key pair for dev vs testing vs production.

By using different key pairs to separate sets of environments, you can perform queries that use the key pair as a filter and thus only act on the environments, instances, etc, that you want. In this example, the code that waits on the Beanstalk environment to come up assumes that there is only one environment per key/secret-key/key-pair combination. To generate more key pairs, click the "Key Pairs" link on the EC2 tab in the AWS console.

The BeanstalkStarter class will start up an environment using the 32 bit Linux OS with Tomcat 7. As of this writing, the solution stack names and AMI IDs in the Beanstalk console are as follows:

Solution Stack AMI
32bit Amazon Linux running Tomcat 7 ami-23de1f4a
64bit Amazon Linux running Tomcat 7 ami-6dde1f04
32bit Amazon Linux running Tomcat 6 ami-39de1f50
64bit Amazon Linux running Tomcat 6 ami-79de1f10

The configuration option for the AMI ID has namespace aws:autoscaling:launchconfiguration and option name ImageId. If you've created your own custom AMI, use your value instead.

The rest of the information for this entry is in comments in the source code. See the code for all the information. In order to focus on setting environment configuration settings, this example starts up a new environment for an existing application. You could do the same thing for creating a new application however.

Wednesday Sep 07, 2011

Querying Amazon Elastic Beanstalk Settings with the AWS SDK

Amazon's Elastic Beanstalk simplifies the tasks of getting a web application deployed in a managed environment. The Java SDK that Amazon provides is easy to use for creating/updating Beanstalk environments. There are accessor methods for the most-used configuration settings, such as setEnvironmentName and setApplicationName.

However, many other configuration settings are not so clear. The SDK uses the generic ConfigurationOptionSetting class for most of a Beanstalk environment's information. This class wraps a namespace, option name, and the option's value. Many of the namespace and option name combinations can be found in the various API references, but there's a simpler way to find them all: ask the environment itself.

The attached BeanstalkConfigQuery class performs a query that lists all the current configuration option settings for your environment. Here are a couple lines of output showing the minimum size of my autoscale group and my AWS access key (which has not yet been set). Spacing was added for readability:

    {Namespace: aws:autoscaling:asg, OptionName: MinSize, Value: 1, }
    {Namespace: aws:elasticbeanstalk:application:environment,
        OptionName: AWS_ACCESS_KEY_ID, Value: , }
Using that information, you can easily create an UpdateEnvironmentRequest object to update a running environment:
        ConfigurationOptionSetting minCOS = new ConfigurationOptionSetting(
            "aws:autoscaling:asg", "MinSize", "3");
        ConfigurationOptionSetting awsKeyCOS = new ConfigurationOptionSetting(
            "aws:elasticbeanstalk:application:environment",
            "AWS_ACCESS_KEY_ID", "my_aws_key_text");
        UpdateEnvironmentRequest updateRequest = new UpdateEnvironmentRequest()
            .withEnvironmentName("my_env")
            .withOptionSettings(minCOS, awsKeyCOS);
        beanstalkClient.updateEnvironment(updateRequest);

The BeanstalkConfigQuery class also outputs all the configuration option descriptions, which shows more information about each of the options that you can set. See the comments in the class file for more information, but here are the two descriptions that match the settings listed above. Total, there are close to 50 of these listed when I run against my Beanstalk environment.

    {Namespace: aws:autoscaling:asg, Name: MinSize, DefaultValue: 1,
        ChangeSeverity: NoInterruption, UserDefined: false,
        ValueType: Scalar, ValueOptions: null, MinValue: 1,
        MaxValue: 10000, MaxLength: null, Regex: null, }
    {Namespace: aws:elasticbeanstalk:application:environment,
        Name: AWS_ACCESS_KEY_ID, DefaultValue: ,
        ChangeSeverity: RestartApplicationServer, UserDefined: false,
        ValueType: Scalar, ValueOptions: null, MinValue: null,
        MaxValue: null, MaxLength: 200,
        Regex: {Pattern: ^\S*$, Label: nospaces, }, }

With this information available, the Beanstalk AWS SDK is straightforward to use. In a future post, I'll show an example of programmatically setting up an environment using options like the above. That saves you the step of having to start the environment, wait for it to come up, and then separately update the environment to include the desired settings.

Monday Jul 18, 2011

The GlassFish Upgrade Tool: End of the Line

In the 2.X timeframe of GlassFish, there was an upgrade tool that would transform your existing configuration information and move you to a newer version of GlassFish. This tool did all the work of mapping one version's configuration information to another.

Starting with GlassFish v3, the application server became modular, and components became responsible for their own part of the configuration upgrade. See the upgrade one pager for more details on how configuration upgrades work.

With the real work of the upgrade happening in the application server itself, the job of the upgrade tool became smaller and smaller until it now does the following:

  1. Copies the source domain to the target app server.
  2. Runs asadmin start-domain --upgrade.

When the steps are that simple, there isn't much value in having the tool. If you read the Oracle GlassFish Server 3.1 Upgrade Guide, you'll see that there are several upgrade uses cases that do not involve the upgrade tool at all. One example is an in-place upgrade using the update center.

For this reason, and to avoid confusion between the upgrade tool and update center, we'll be removing the upgrade tool from versions of GlassFish after 3.1.X. Upgrades should still be a simple affair. After all, the tool is just doing a copy and starting the server. If it can, you can.

Friday Mar 04, 2011

Validating Multicast Transport: Where Did My Instances Go?

For cluster health information and communication of high-availability state, GlassFish 3.1 depends on GMS. To dynamically discover the members of a cluster, GMS depends on UDP multicast. So if there's something about your network preventing multicast communication among hosts, instances will become isolated from each other.

As I wrote in my last blog on the 'asadmin get-health' command, it's a good idea after starting your cluster to make sure everything is working correctly. With the asadmin validate-multicast command, you can diagnose issues with intra-instance communication or plan your cluster deployment before creating the cluster instances.

This asadmin subcommand is used to send and receive UDP multicast information, and so acts to validate that various hosts can all communicate with each other. The usage is simple in concept: run the tool on each host at the same time, using the same multicast address and port, and verify from the tool's output that each host receives messages from the others. So if you're running on hosts 1, 2, and 3, then you should see this when running on host 1:

    Listening for data...
    Sending message with content "host1" every 2,000 milliseconds
    Received data from host1 (loopback)
    Received data from host2
    Received data from host3

Likewise, hosts 2 and 3 should see messages from all 3 machines. Make sure you're not running the DAS and instances at the same time, or else there will be interference with the UDP traffic. Here is a video showing some features of the tool:

Debugging, Step 1: Use Same Multicast Port/Address as Cluster

While this tool can be useful to check your network before deploying your cluster, it is most helpful when one instance is not communicating with the DAS/other instances. You may see this if you run the 'get-health' command described in the previous blog. If you know that an instance is up according to its server log, but it's showing up as "not started" in the get-health output, then it's likely that the DAS and the instance are not seeing each others' UDP multicast messages. In this case, you want to run asadmin validate-multicast with the following options:

  • --multicastport The value of gms-multicast-port for your cluster in domain.xml.
  • --multicastaddress The value of gms-multicast-address for your cluster in domain.xml.

Using those options will make the tool use the same values as the members of your cluster, in effect simulating the GMS traffic between the DAS and instances. To find the values for those options, you can read them from the attributes on the <cluster> element in domain.xml. For instance:

  <clusters>
    <cluster name="mycluster"
        gms-multicast-port="22262"
        gms-multicast-address="228.9.244.214"
        [etc.] >
      <server-ref ref="instance1"></server-ref>
      <!-- [etc.] -->
    </cluster>
  </clusters>

Debugging, Step 2: TTL

Unless specified on the command line, the validate-multicast tool and GMS use the default MulticastSocket time-to-live for your operating system or 4, whichever is greater. You can see this in the tool's output if you run with the --verbose flag. For example:

    McastSender: The default TTL for the socket is 1. Setting it to minimum 4 instead.

You can try increasing this value to see if it is the limiting factor that prevents packets from reaching the cluster members with your network configuration. To specify a different value, use the following option with the tool (in addition to --multicastport and --multicastaddress):

  • --timetolive Sets the time-to-live value of the multicast packets sent by the tool.

If you are now seeing all the instances you expect, you can change your cluster configuration so that GMS uses this TTL value. It is simple to pass this value into the asadmin create-cluster command. See the "To Create a Cluster" section of the High Availability Administration Guide for an example. If your cluster is already running, however, you can set this value with asadmin set. See the "To Change GMS Settings After Cluster Creation" section of the HA guide. The property to be set is GMS_MULTICAST_TIME_TO_LIVE, and it is listed in the "Dotted Names for GMS Settings" section.

Debugging, Step 3: Specifying the Network Adapter

On a multi-home machine machine (possessing two or more network interfaces), you may need to specify the local interface that should be used for UDP multicast traffic. You can use ifconfig, or the equivalent on your system, to list the network interfaces and obtain the local IP address of the interface you wish to use. This address can then be used with the following command line parameter (along with any you're already specifying):

  • --bindaddress Sets the local interface used to receive packets.

Note that this value will be different on each machine where you are running the tool. If you are now seeing all the instances you expect, you can set the GMS bind interface for each instance following the instructions in the "Traffic Separation Using Multi-Homing" section of the HA guide.

If one or more machines are still missing in the output, then it may be that they are located on different subnets from each other. Or it could be that UDP multicast is not enabled on the network. You may need to ask the network administrator to verify that the network is configured so that the UDP multicast transport is available.

For more information, see the validate-multicast man page. A copy of the help information is attached here as well. The validate-multicast tool is also covered in more depth in the HA guide referenced above.

Monday Feb 28, 2011

State of the Cluster With Get-Health Command

GlassFish 3.1 uses GMS, part of Project Shoal, to provide dynamic membership information about a cluster, including the state of its instances and the DAS. The asadmin subcommand "get-health" gives you a snapshot of this state. For example, here is my cluster ready to be started:

  hostname% ./asadmin get-health mycluster
  instance1 not started
  instance2 not started
  instance3 not started
  Command get-health executed successfully.

...and after the cluster has started:

  hostname% ./asadmin get-health mycluster
  instance1 started since Fri Feb 25 16:27:16 EST 2011
  instance2 started since Fri Feb 25 16:27:15 EST 2011
  instance3 started since Fri Feb 25 16:27:15 EST 2011
  Command get-health executed successfully.

Besides this basic information, the GMS-based system can give you information about instances that have been shut down or that have failed (see instances 1 and 2 in the next example). Because this information comes from the GMS group members (instances or DAS), information from the instances is still correct even if the DAS is restarted. In the following, notice the "stopped" and "failed" messages. After the DAS restarts, the startup time for instance3 is still valid. Because instances 1 and 2 are stopped, they cannot communicate when they failed/stopped:

  hostname% ./asadmin get-health mycluster
  instance1 stopped since Fri Feb 25 16:57:56 EST 2011
  instance2 failed since Fri Feb 25 16:58:26 EST 2011
  instance3 started since Fri Feb 25 16:27:15 EST 2011
  Command get-health executed successfully.

  hostname% ./asadmin restart-domain
  Successfully restarted the domain
  Command restart-domain executed successfully.

  hostname% ./asadmin get-health mycluster
  instance1 not started
  instance2 not started
  instance3 started since Fri Feb 25 16:27:15 EST 2011
  Command get-health executed successfully.

Note that you can see these events in the server.log as well. Here are some of the messages related to the shutdown and failure above:

  • GMS1017: Received PlannedShutdownEvent Announcement from member: instance1 with shutdown type: INSTANCE_SHUTDOWN of group: mycluster
  • GMS1007: Received FailureSuspectedEvent for member: instance2 of group: mycluster
  • GMS1019: member: instance2 of group: mycluster has failed

The asadmin get-health command is not new, but there is one new feature in GlassFish 3.1. If you have an instance configured as a service that is automatically restarted, it could fail and restart quickly before the system has a chance to process that it has failed for certain. In this case, you could see a message such as:

  hostname% ./asadmin get-health mycluster
  instance1 rejoined since Fri Feb 25 17:01:14 EST 2011
  ...

In a case like this, it is important to find out what is happening in that instance. If an instance fails and stays down, it becomes obvious quickly. But if an instance fails and restarts often, it may not be obvious unless you look through the server logs. So seeing an instance in the "rejoined" state could signal a problem that the instance in questions is constantly failing. Here are some of the messages you would see in server.log related to the rejoin:

  • GMS1053: member: instance1 was restarted at 3:45:41 PM EST on Feb 26, 2011.
  • GMS1054: Note that there was no Failure notification sent out for this instance that was previously started at ....
  • GMS1024: Adding Join member: instance1 group: mycluster StartupState: INSTANCE_STARTUP rejoining: missed reporting past FAILURE of this instance that had joined the group at ....

Whenever you create and start a cluster, it's a good idea to use the asadmin get-health command to make sure communication is working properly among the instances and the DAS. In my next blog, I'll show how you can use the "validate-multicast" subcommand to help diagnose a problem if one or more instances are not being found by asadmin get-health.

For more information on the get-health subcommand, run asadmin get-health --help. A version of it is attached here as get-health.txt. For more information on clusters and GMS, please see the article "Clustering in GlassFish Version 3.1".

Moving On Up: Upgrading to GlassFish 3.1

GlassFish 3.1 is here, and once you're done playing around with it, it might be time to do some work. If you already have an earlier GlassFish installation working for you, this blog will walk you through the steps to upgrade it to GlassFish 3.1. Specifically, I'm going to upgrade a v2.1.1 installation with a two-instance cluster.

If you're upgrading from a v2 developer profile or a 3.0.1 installation, then the upgrade process is mostly the same. You're just done after the upgrade tool exits, since you won't have cluster instances to recreate. If you're upgrading from a v2 enterprise edition installation, then please see the Upgrade Guide for more information. The upgrade process is the same, but there are some manual steps you will need to perform because GlassFish 3.1 does not support NSS.

All of the steps in this example are included in this video, and I'll describe them below:

Step 1: Upgrade the DAS

First, make sure the DAS, node agent, and instances are all stopped. If you have any 3rd-party libraries installed in glassfish/lib (not domainX/lib), you'll need to copy those over to the 3.1 installation. Then you can use the upgrade tool located in the bin directory: bin/asadmin/asupgrade. While you don't need to give it any options, the following are the most useful (use --help for the full list):

  • -c or --console This will start the tool in console mode instead of GUI mode.
  • -s or --source This will specify the source domain to be upgraded.
  • -t or --target This will specify the target domains directory into which the source domain will be copied. This is only really needed when using the console mode. In the GUI mode, it is filled in for you.

When we say "upgrading the DAS," what you're really doing is upgrading the domain that is running in the DAS. This process hasn't really changed since GlassFish v3. Later, this information will be synchronized with the cluster instances. What the upgrade tool does for you is copy the old domain to the 3.1 server, and then it runs asadmin start-domain --upgrade <domain_name> to upgrade the configuration in the domain. Just like with GlassFish v3, the server itself performs the upgrade duties.

Step 2: Recreate the Cluster Instances

Because the cluster information is stored in domain.xml, we don't have to do any other steps to create the 3.1 cluster. However, we need to recreate the instances. I'm using the asadmin create-local-instance command to create my instances. See Jennifer's blog for more information on the command.

In the video, I specify the --node and --cluster options when creating the instances. These values, along with the instance name, match the node agent, cluster name, and instance names that were used in the v2 cluster. When the cluster is started, all of the configuration and application data in the DAS will be synchronized with the instances. The original instances do not store any per-instance data (with one exception below), so there is no separate "upgrade instances" step.

The one extra step you need before starting up the cluster is to copy the IMQ directories from the old instances to the newly-created ones. This persistent JMS information is not part of the domain configuration, and you don't want to lose it during the upgrade process. For instance, copy the directory:

    glassfish/nodeagents/<agentname>/<instance>/imq

To:

    glassfish3/glassfish/nodes/<agentname>/<instance>/imq

Then you're ready to start everything up with asadmin start-cluster <cluster_name> and the upgrade of your cluster is complete. Please see the upgrade guide linked above for full information. Happy upgrading!

Tuesday Mar 30, 2010

Authentication Without the Form

The nice thing about form-based authentication is that it allows a simple way for an application to let the container handle common security tasks. The bad thing about it is that, well, you need an HTML form. For a "Rich Internet Application" (RIA) that doesn't normally use JSPs or HTML pages, this means tacking on some extra files that don't have a natural fit in your application: the JSPs and/or HTML pages themselves, along with a deployment descriptor to specify the security settings. With the new features of the Servlet 3.0 spec, form-based login is no longer needed. Instead, your application can collect username and password credentials however you'd like and simply pass them to the container during an HTTP request. (Logout is equally simple.)

With form-based authentication, you would normally select some set of URLs and protect them with a security constraint. To access these URLs, a user would have to be authenticated and properly authorized. In some RIAs, this pattern no longer makes sense. For example, there may be few (or one) URL for the entire application. Instead, you can apply declarative security at the EJB level to protect any sensitive information (remember that EJBs can be used within a war file in Java EE 6!)

In this blog, I'll show an example of user authentication that doesn't involve an HTML form (or any JSP or HTML pages). There is a simple session bean acting as our back end service, and one of the two "hello world" style methods can only be called by a caller in the 'ADMIN' role:

    @RolesAllowed("ADMIN")
    public String getAdminMessage() {
        return String.format("Hello again '%s', it's great to see you!",
            context.getCallerPrincipal().getName());
    }

While the entire application is available in this zip file, you can see the full session bean, copiously commented, here. The rest of the sample application is simple as well: there is a main, servlet-based application class using Vaadin that includes these two panels (the authentication panel has been broken out into a separate class). See the code in the authentication panel for the full details, but the code to log the user in is this simple:

    String name = // retrieved from web UI
    String pass = // retrieved from web UI
    
    // exception handling omitted here
    // app.getRequest() returns the current HttpServletRequest
    app.getRequest().login(name, pass);

Logging the user out, of course, uses the logout() method instead. Here is the full user interface:

The ee6auth example application

In the "Actions" panel, there are two buttons that call a method in the EJB when clicked. The top button can be used whether there is an authenticated user or not. The other will result in an exception if there is not an authenticated user who is authorized to make the call (a user in the 'ADMIN' role). The exception is popped up in the browser to let you know what happened. Please see the three class files for comments describing the details of each part of the application. Note: while we're keeping this example simple, remember to use SSL any time you're dealing with user credentials such as passwords. The only other file in the application is a deployment descriptor that maps users in the authentication realm to the proper application role.

Before using the application, you need to add some users in the proper group in the default realm in the application server. The group we're using is 'ADMIN_GROUP,' but you can use any group you'd like as long as the mapping is correct in sun-web.xml. To help get you set up, here is a screen cast that shows how to create users in the default realm in GlassFish. We're keeping this very simple by using the file realm in the server, but you could use any realm you'd like. To use a realm other than the default one, add a web.xml file to specify it:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <login-config>
        <realm-name>your-realm-here</realm-name>
    </login-config>
</web-app>

Important note: because of this issue, you need a post-3.0 build of GlassFish v3. You can download a promoted build of v3.0.1 here -- to install, just unzip it. One more time, here's a link to the example application.

To build the application, you can use any IDE that supports Maven or use the command 'mvn clean package' to build it directly. Then deploy with the admin console or use this command (the --force option is only necessary on the 2nd or later deployment):

asadmin deploy --force --contextroot /ee6a <somepath>/ee6auth/target/ee6auth.war

Then you can access the application in a browser with http://localhost:8080/ee6a/. Let me know if you have any problems with the example. For any general questions, you'll get an answer more quickly at users@glassfish.dev.java.net.

I'd like to give a big thanks to Petter Holmström from the Vaadin team for his help, especially the article Creating Secure Vaadin Applications Using JEE6 that explains the steps needed to use regular form-based authentication (and a lot more) with a Rich Internet App such as Vaadin.

Thursday Mar 04, 2010

A Simple UI for Exploring Java EE

Java EE 6 has greatly simplified life for the EE developer. New annotations like @Startup and packaging options such as EJBs inside a war file save time and brain cycles. However, this makes writing the web UI for an application all the more time-consuming by comparison. If you're like me, you may have found yourself creating some entities and a session bean or two for controlling them, and then you just want to test it all out. Maybe step through the code in a debugger. Here's what I've done over and over -- it's simple, but it's silly. Just create a servlet, inject my session bean, and do something when the page is loaded:

    @EJB
    private MyBean myBean;
   
    @Override
    protected void doGet(...) throws ... {
        myBean.someMethod();
    } 

Then it's a simple matter to load the page in a browser and kick off the cool EJB code that you want to try. To check what really happened in the database, I use another tool (e.g., the database explorer in NetBeans). Simple, yes, but almost useless. In this blog, I'll show you a UI for testing Java EE services that is simple to write and trivial to adapt to your own applications. Not only can it provide a slick front end for calling business methods, but also access the database directly to show you what happened after the transactions have committed. As a bonus, it will show you the stack trace when something doesn't go quite right.

Yes, there are a number of tools that provide simple drag-and-drop interfaces for creating things like JSF front ends, but my goal is to create a UI with useful features as easily as I've created the session beans and entities. If you've ever written a Swing application, this should look very familiar. And there are no cryptic deployment descriptors, configuration files, or html/jsp templates needed. The only non-Java file in the application is a simple persistence.xml file.

To give you an idea before diving in, here is a screencast of the application in action.


Part 1: The Application

All of the application code is included in this zip file. I've included a pom.xml file so you can build with maven 2 without any additional setup. If you'd like to compile the sources and create the war another way, you just need the Java EE APIs in your classpath along with Vaadin, which comes in a single jar file that you can download from here. Look for the "Just the jar-file, please" text if you only want the one resource.

The back end consists of two simple entities, a SimplePerson and SimplePet. They both have a name, age, and one-to-one reference to each other. There is a PersonService session bean that has some normal CRUD operations on the person (which are cascaded to the pet). This bean is injected into the web UI -- see below for more details. Finally, there is a singleton bean loaded on startup that simply makes sure there is a pet named "Fred" in the database: FredCreatorBean. All of the classes are fairly simple and include comments to guide the reader. The persistence.xml file is very simple and uses a JTA data source jdbc/EE6Vaadin -- instructions for creating the resource are in part 2 of this blog. If you use a different JNDI name when creating the JDBC resource, make sure you change the name here. Also, after deploying the first time, you may want to comment out this line to avoid some warnings upon subsequent deployments:

    <property name="eclipselink.ddl-generation" value="create-tables"/>

For the presentation layer, I'm using Vaadin, a Java framework for creating rich internet applications. Since it's all Java, you write code that looks like Swing -- there are objects for layouts, widgets, and event handlers. GWT is similar, but with Vaadin the code you write stays on the server rather than being compiled into JavaScript objects. This is why I can inject a session bean into the presentation code to call my business logic. (Vaadin uses GWT for rendering the client in a web browser.) I should note that I'm not a Vaadin expert, so there may be better ways to create the UI. The Vaadin site has a nice forum for discussions like that -- I'll add a link here if there is any related discussion there.

Vaadin applications are loaded by a servlet com.vaadin.terminal.gwt.server.ApplicationServlet that you can configure in your web.xml file. This servlet creates the application object your write, initializes it, and the web page is displayed. In this example, I have included my own subclass of the Vaadin servlet in order to inject the session bean, and then I pass this bean to a custom constructor of my application. This also allows me to avoid having any configuration files except for persistence.xml. Here is the code included at the end of the main application class VaadinEE6App:

    /\*
     \* This code is adapted from the Vaadin example here:
     \* http://vaadin.com/wiki/-/wiki/Main/Hello%20GlassFish%203
     \*/
    @WebServlet(urlPatterns = "/\*")
    public static class Servlet extends AbstractApplicationServlet {

        @EJB
        private PersonService service;

        @Override
        protected Class<? extends Application> getApplicationClass() {
            return VaadinEE6App.class;
        }

        @Override
        protected Application getNewApplication(HttpServletRequest request)
            throws ServletException {
            return new VaadinEE6App(service);
        }
    }

In the application constructor, I store the EJB and create a couple class-level fields such as some panels that handle display and creation of the person/pet POJOs. The init() method creates some simple layouts, adds the panels, buttons, text field, etc., and connects the buttons to some actions for calling the back end. See the (hopefully) well-commented VaadinEE6App.java file for all the details. Everything there should look more or less familiar to a Java developer who has seen any Swing code.


Part 2: Setup and deployment using GlassFish v3

I'm using GlassFish v3 for this example, along with the JavaDB database that is included. In production, we would create the DB tables with SQL, but for a simple demo the JPA provider will do this for us. We just need to create the database connection pool, create a JNDI resource for it, and then build and deploy the application.

If you haven't already, download and unzip GlassFish v3, which supports Java EE 6. The database and server can be started with:

    asadmin start-database
    asadmin start-domain

Then visit the administration console at http://localhost:4848 -- the default username is admin with no password if prompted. On the left side, open the Resources->JDBC node and click Connection Pools. Click the New button and enter the following information, then click Next:

Step 1 of creating JDBC connection pool

In step 2, scroll to the Additional Properties table at the bottom. Delete properties as needed and enter information as shown below. Then click Finish.

Step 2 of creating JDBC connection pool

In the table above, the "create=true" property tells JavaDB to create the database when it is needed. The database name, user name, and password can be set to whatever you'd like, but you'll need to remember to change this information in the com.sun.bobby.ee6vaadin.presentation.SQLPanel class, which access the database directly.

Before moving on, you can check to make sure the database connection is working by clicking your new EE6VaadinPool entry in the Connection Pools list and then click the Ping button.

The last setup step is simple: creating the JDBC resource that points to the connection pool you just created. In the administration console, open the Resources->JDBC node again and click JDBC Resources. Click the New button, enter the following info, and click OK. If you choose a different name here, it has to match the jta-data-source element in the persistence.xml file in the application. That's all there is for setting up the database and server.

Creating the JNDI resource

Now you can create and deploy the war file. If using maven, you can use a simple "mvn package" from the ee6vaadin directory to build the war file. One more time, I'd like to point out that we have EJBs running without an ejb-jar file or an application .ear file! Good stuff.

To deploy, you can use the admin console or the following from the command line. The "--force" option isn't necessary the first time, but it is used in subsequent deployments to overwrite the deployed application. After your first deployment, you may want to comment out the table-creation property in persistence.xml and rebuild. Here is the command, but feel free to use whatever context root you'd like:

    asadmin deploy --force --contextroot /ee6v target/ee6vaadin.war

Assuming deployment proceeds without an issue, you can access the web application at http://localhost:8080/ee6v/ and give it a spin. It's not meant to include every conceivable feature -- there are even a couple "homework" features left for the user. But I hope it's enough to show how easily a web UI can be constructed that a) avoids configuration files, expression languages, templates, etc.; and b) can take full advantage of the Java EE server and use EJBs directly.

Update: I noticed I left an entity manager call in the code that isn't necessary at all. The 'else' block in the only method of FredCreatorBean looks like this:

        } else {
            // doesn't matter which one for this demo
            SimplePet fred = (SimplePet) fredPets.get(0);
            fred.setAge((fred.getAge() % 10) + 1);
            em.merge(fred);
            System.out.println(String.format(
                "Wow, Fred is %s years old already!",
                fred.getAge()));
        }

The 'em.merge(fred);' statement isn't necessary since the entity is still being managed throughout the method.

Monday Feb 08, 2010

Tip: Installing JDeveloper on Mac OS

Having gone through this a couple times now, I wanted to capture a couple tips that make JDeveloper installation easy for MacOS X users. The installation itself is very simple: a 'java -jar <jar_file>' does it all. But there is one helpful and one mandatory step you should take first. Thanks go to Steve DiMilla for trying these steps as well.

1. Set JAVA_HOME in your environment

While not really necessary (AFAIK), your life may be easier if you do. You can always just export the environment variable in a terminal, but you might as well do it properly and make it available to your whole environment. That way any process running as you has the information available. I've covered this in a previous blog, but here it is again, nice and simple. Assuming you haven't already:

  1. Create a directory in your home folder called .MacOSX (note the dot, the capitalization, etc.).
  2. Create a file in that directory called environment.plist.
  3. Copy the following into your ~/.MacOSX/environment.plist file:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
    <plist version="0.9">
      <dict>
    
        <!-- When changing this, also run Java Preferences and change there. -->
        <key>JAVA_HOME</key>
        <string>/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home</string>
    
      </dict>
    </plist>
    
  4. Log out and log back in.
That's it. You can use a different version than I'm using above, but at the time of this writing 1.6 is the latest. Note that Versions/1.6 is a symbolic link to Versions/1.6.0, at least right now on my machine. I prefer setting my home to 1.6 so that, presumably, if Apple removes 1.6.0 at some point and replaces it with 1.6.1, I won't have to change anything. I hope.

2. Create an rt.jar link to classes.jar

The installer for JDeveloper expects the Apple JDK to look like other JDKs. Specifically, it's looking for $JAVA_HOME/jre/lib/rt.jar, which doesn't exist by default. You're going to change that. This information is available as part of the installation insructions (section 6), but they recommend you enable the root user and do the following as root.

(Side note: enabling the root user is different on different versions of MacOS X, so the official instructions may not work for you. Here is Apple's information on enabling root.)

While doing this as root works fine, as long as you have administrative privileges, you can do the same thing with sudo and save yourself a couple steps. Here you go:

  1. cd $JAVA_HOME
  2. sudo mkdir jre (use your login password when prompted)
  3. cd jre
  4. sudo mkdir lib
  5. cd lib
  6. sudo ln -s ../../../Classes/classes.jar rt.jar
There you go. To test, head on into $JAVA_HOME/jre/lib and run a simple 'jar tvf rt.jar' if you'd like.

Now, go ahead and install. Then watch the cool overview demo to see it in action.

Wednesday Jan 20, 2010

Upgrading to GlassFish v3

As you probably know by now, Java EE 6 has made life simpler for developers (ear files not required, local EJB interfaces optional, singletons, all good stuff!). But of course you want to run your old applications as well. With GlassFish v3, moving them over to the newest application server is also a lot easier. In fact, you can upgrade a domain from GlassFish v2.1 or GlassFish v3-Prelude in zero steps. It doesn't get easier than zero, at least until the JSR for "Java API for Mind Reading" gets implemented.

By "zero steps," I mean you can simply start GlassFish v3 with an older domain and it will recognize the domain version and attempt to upgrade it before proceeding with startup. Below is the kind of output you'll see. In this case I've copied a v3-Prelude domain over to my v3 installation and called it "predomain" to not clobber my existing domain1.


hostname% asadmin start-domain predomain
Domain needs to be upgraded before it can be started.
Attempting upgrade now...
Upgrade was successful, starting domain...
Waiting for DAS to start ......
Started domain: domain1
Domain location: /Users/bobby/servers/glassfishv3/glassfish/domains/predomain
Log file: /Users/bobby/servers/glassfishv3/glassfish/domains/predomain/logs/server.log
Admin port for the domain: 4848
Command start-domain executed successfully.

Now before you start upgrading all your previous domains, you should remember that only developer profiles are supported in v3 -- clustering will come later. You should make a copy of your existing domain and upgrade that domain to be safe. Also, if you have installed any 3rd party jars in your glassfish/lib directory (as opposed to the domain's lib dir), you should move those over to your v3 installation as well. In fact, the above is exactly what the asupgrade tool does for you in v3. It will copy over the source domain, making sure not to clobber anything if there is a name collision. It will look for jars to move over, and then will run asadmin start-domain --upgrade <your_domain>. Be sure to check the server.log file for information on the upgrade, especially in case there were warnings or errors.

Check out the Upgrade Guide for more information on upgrading, especially the sections on which previous server version are compatible and notes on application compatibility between Java EE 5 and Java EE 6.

Tuesday Oct 13, 2009

Fun With the 'open' Command

In MacOS (I'm running 10.5), the open command is one of those little tools that keeps giving and giving. Sure, it seems simple enough. From the man page:

     The open command opens a file (or a directory or URL), just as if you had double-
     clicked the file's icon. If no application name is specified, the default applica-
     tion as determined via LaunchServices is used to open the specified files.

But I've discovered I use it more and more while I work. In case you haven't thought of all these already, here are some of the things you can do with open besides the very obvious use opening URLs.

Open windows in Finder that Mac won't let you get to normally:

For instance, if you want to open a Finder window to see your original photos under ~/Pictures, it's simply (am using autocompletion to escape the spaces in the path):

     open ~/Pictures/iPhoto\\ Library/Originals/
Trying to click through this in Finder normally will just bring up iPhoto. Generally, that's the correct behavior, but some of us really want the ability to mess things up manually.

Open compressed archives simply:

This one is nice during development. I work on the GlassFish application server, and often hack it all up and need to reset my installation back to some known snapshot. After installing and doing whatever configuration I need, I can tar/gzip the whole thing up into an archive. Then when I need to "reinstall," it's as simple as:

     rm -rf glassfishv3 && open gf3.tar.gz
Sure, that's not much less typing than unzipping and piping the result to tar, but it's short enough that I don't need to think about it.

Edit text files quickly:

Some file types are, by default, opened with heavyweight apps. Opening an xml file, for instance, brings up OpenOffice on my system. The '-e' flag to open will instead bring whatever file you specify up in TextEdit:

     open -e domain.xml
I'm just as likely to use emacs in this case, but sometimes I want to have that text editor open for a while and not taking up one of my terminal windows (so I don't lose it in the cmd-1, cmd-2, cmd-n shuffle). You can also use the -a flag to specify a particular app, which can also be a modest time saver. Just let autocompletion do the path work for you.

Pipe process output to a text editor:

This is a little time saver when you'd normally pipe output to a file and then open that file for editing.

     svn diff | open -f

Find out when a job is done:

On my Solaris machines, I used to have an alias that would print ctrl-g characters (beeps). So I could start a process and have the terminal beep at me when the process was done. iTunes makes this much more fun. Before you try setting an alias (or adding to a script), do the whole open command by itself to let MacOS handle all the escaped characters for you. Then cut and paste, as in:

     alias go="open -g ~/Music/iTunes/iTunes\\ Music/Israel\\ Kamakawiwo\\'ole/Ka\\ \\'Ano\\'i/03\\ Kainoa.mp3"
Then I can run some long process like mvn -u install && go and the music starts when it's done. The '-g' flag in the open command keeps the application in the background.

Thursday Jul 02, 2009

RIA without XML

One of the cool things I discovered at JavaOne this year was a framework for building rich internet applications (RIAs) called Vaadin. Besides being a very nice tool, they also had the good idea of giving away printed copies of their free book at the booth. Since my laptop battery time is limited, having a hard copy to read gave me plenty of time to learn about it between sessions, while waiting to meet people, while sitting at the bar, etc.

Vaadin is a web application framework that lets you write Java code to create your web pages. No JSP, no HTML (unless you want to), no XML, etc., and only one jar file needed for the framework. Somewhere in my reading or while talking to one of the Vaadin people, I came across the one exception to the "no xml" statement: Vaadin is still a Java EE application, so of course there is still a web.xml file needed to deploy an application. My first thought was, "We can fix that, right?" So for no particular reason, here is how to create a rich internet application with no XML files at all using Vaadin and Servlet 3.0 inside GlassFish v3 Preview.

To get rid of the web.xml file, use the @WebServlet annotation on your servlet class. Vaddin is open-source, so of course you could add it to the class and rebuild it. But let's do the proper thing and subclass the servlet. I've put it in the same package as the parent in case it's looking for any resources relative to the package. Here is the entire class:

package com.vaadin.terminal.gwt.server;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

@SuppressWarnings("serial")
@WebServlet(
    name = "Noxml Application",
    initParams = {
        @WebInitParam(name = "application",
            value = "com.example.noxml.NoxmlApplication")
        },
    urlPatterns = { "/\*" }
)
public class EE6ApplicationServlet extends ApplicationServlet {
    // nothing here
}

Pretty simple stuff. Thank you Servlet 3.0. Now, to give you a sense of what Vaadin is like and to show that this really works, here is the application I wrote. It simply adds a couple blocks of text to the web page and a button. Clicking the button switches the text between the two lines (called "labels" in Vaadin). Here is the entire class:

package com.example.noxml;

import com.vaadin.Application;
import com.vaadin.ui.\*;
import com.vaadin.ui.Button.ClickEvent;

@SuppressWarnings("serial")
public class NoxmlApplication extends Application {	
    /\*
     \* A very simple application with two labels and a button.
     \* To keep this short, I've added an anonymous listener
     \* for the button that calls my very exciting swap method.
     \*/
    @Override
    public void init() {
        // create components
        Window mainWindow = new Window("Noxml Application");
        final Label label1 = new Label("Hello RIA.");
        final Label label2 = new Label("Goodbye XML.");
        Button button = new Button("Very Exciting Button",
            new Button.ClickListener() {
                public void buttonClick(ClickEvent event) {
                    swapText(label1, label2);
                }
            });

        // add 'em
        mainWindow.addComponent(label1);
        mainWindow.addComponent(button);
        mainWindow.addComponent(label2);

        // add window to the application
        setMainWindow(mainWindow);
    }

    // where is my tuple unpacking?
    private void swapText(Label l1, Label l2) {
        Object temp = l1.getValue(); // a string in this case
        l1.setValue(l2.getValue());
        l2.setValue(temp);
    }
}

That's all there is to it. My entire web application contains only three classes (one is the anonymous inner class in NoxmlApplication), a single jar file in the lib directory, and no xml files. It's not much to look at since I kept it simple, but all of the Ajax requests/responses are taken care of for me and I just wrote a little Java code. Speaking of not much to look at, here is a very exciting screen cast of the web application in action.

I've included the Vaadin links above. If you'd like to try out GlassFish v3 and the great developer features of Java EE 6, here are some instructions on setting up the application server with NetBeans and with Eclipse (the latter only shows v3 Prelude, but you can use a v3 server as well). For more on creating a servlet using the 2.0 annotations, see Arun's blog. Have fun.

Tuesday Feb 17, 2009

Switching JDKs on Mac

We've recently been discussing this at work, and now that I have a setup working well for me (and working simply), I wanted to document the steps. My goal was to switch JDKs used by all the tools in my enviornment: NetBeans, ant, maven, command line Java, etc., so that they were all using either Java 5 or 6. After some missteps, here's what works for me.

I'm using Mac OS 10.5.6, but this info should be valid for any nearby version. The Mac comes with, and occasionally updates, JDKs 1.4 through 1.6. You can see the versions you have installed in this directory:

  • /System/Library/Frameworks/JavaVM.framework/Versions
While I initially played with the Current and CurrentJDK symbolic links in that directory to switch the JDK my system was using, I have seen the error of my ways and there is an easier solution. There are two steps, listed below:

1. Command Line Java

My Java is coming from /usr/bin/java, which points off to one of the versions in the 'Versions' dir described above. To change the version of the JDK you're getting here, use the Java Preferences application under Applications -> Utilities -> Java:

You can drag the JDK you'd like to the top and it should be reflected immediately from the command line:

hostname% java -version
java version "1.5.0_16"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b06-284)
Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_16-133, mixed mode)
hostname% java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06-153)
Java HotSpot(TM) 64-Bit Server VM (build 1.6.0_07-b06-57, mixed mode)

2. Scripts and Applications That Use Java

Generally, other built-in applications or one that you install will use the JAVA_HOME environment variable to pick a JDK. By default, you won't have this set, and Mac-specific versions of startup scripts will usually create one by using the CurrentJDK link in the Java 'Versions' directory. The steps to add environment variables are documented in this article, but I can save you a little time. Create a directory .MacOSX in your home directory and add a file called environment.plist. Here are the entire contents of my ~/.MacOSX/environment.plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
  <dict>

    <!-- When changing this, also run Java Preferences and change there. -->
    <key>JAVA_HOME</key>
    <string>/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home</string>

  </dict>
</plist>

With this value set, all processes started as you will have JAVA_HOME available to them. Since this file is read when you log in, you'll have to log out/in once after you create or edit this file.

Special case: NetBeans

The IDE I use is NetBeans, but the following idea probably applies to other large applications as well. When NetBeans is installed, it will pick a JDK to use and hard code it in a properties file. If you want it to rely on the JAVA_HOME that you're now setting in environment.plist, you just need to edit one file. Edit this file:

  • /Applications/NetBeans/NetBeans\\ 6.5.app/Contents/Resources/NetBeans/etc/netbeans.conf
..and you can set the JDK by changing this line:
  • netbeans_jdkhome=$JAVA_HOME

Note that, as the netbeans.conf file points out, you can always force a different JDK to be used by specifying it on the command line when starting the IDE. For your copying and pasting pleasure, here is the command to use to start it from terminal (I'm giving the 'help' option in this case). If you're using a different version, autocomplete ought to help with the version part of the path:

  • /Applications/NetBeans/NetBeans\\ 6.5.app/Contents/MacOS/netbeans --help

Recap

To recap, you can switch JDKs for your whole system by using the Java Preferences application along with changing the value in your environment.plist file. To switch on the fly, use the Preferences app and set a new value for JAVA_HOME in whatever terminal you're using, though some apps like NetBeans will still pick up the system value and you should specify the desired JDK on the command line.


Bonus links:
Just to get some useful info in one place, here are some links I've found very helpful for people first switching to Mac, whether developer or not.

Wednesday Oct 29, 2008

This Spec is My Spec, This Spec is Your Spec....

As OpenSocial is getting ready for version 0.9, a number of changes/clarifications/additions/etc are being proposed on the spec discussion page. I've submitted two of them based on things we're doing in Project SocialSite. Feedback is always welcome, and here's your chance to help shape OpenSocial (and, therefore, Project SocialSite).

The first is a proposal for messaging support. There was already a proposal for sending messages, but after working on the messaging implementation in SocialSite we had a (hopefully) good idea about what else would be useful. The current messaging proposal adds not just the ability to send messages, but also to retrieve, update, and delete them. It includes some changes to the message object to include sender information as well as a way for gadgets to send a payload in cases where this would be useful (e.g., group information in a group join request). Feel free to comment on the discussion thread or vote on the proposal.

The second proposal, discussed here on the spec group page, is about a change to the recipient format used in OpenSocial messages. We're trying to find the best (or at least most acceptable) way to specify not just the ID of the recipient, but whether or not it's a person, a group, or whatever else could be receiving messages in the future. Any input would be good here, or send us a note on the dev mailing list if you'd just like to know more about the implementation of our messaging support.

Thursday Oct 09, 2008

Screen Cast: Developing Project SocialSite

As more and more people are trying out Project SocialSite, we're finding out that some people want to be able to download and use the latest code without waiting for a promoted build. So this blog is for the code-happy developer types who want to build and try things out, and then rebuild and re-try if we (or they!) fix some particular issue. This isn't necessarily the best or only way to install SocialSite and then get into the twiddle/compile/test cycle (twiddle being the technical term), but it works for me.

As background, this blog assumes that you've downloaded the code, have an instance of GlassFish ready, already have ant, etc. There are a couple files that I have ready beforehand in the screen cast. Two are properties files that I edit ahead of time and copy somewhere else. You can do the same if you'd like:

  • socialsite/installer/sjsas.props
  • socialsite/installer/socialsite.props

The other step I mention in the screen cast is to change the socialsite.search.index.path property in socialsite/src/java/com/sun/socialsite/config/socialsite.properties. After that, you're ready to follow along with the screencast.

I use FireFox as my browser, and there are a couple extensions that are very helpful when working on Project SocialSite or pretty much any other web application. You can find them both through FireFox's "Get Add-Ons" functionality, but here are some links as well:

  • Firebug. Can't live without this one. I use it for debugging JavaScript code and for checking the outgoing/incoming messages for requests made by gadgets. If you're working on gadget code and want to see what some generated html is really doing in a page, "Inspect Element" is a handy feature.
  • Web Developer. This extension does a lot more than I use it for, but it's essential for a couple things. The biggest for me is turning off my browser's cache so that it doesn't keep loading an old version of a gadget xml file long after I've made changes. Being able to clear your session data is nice as well when working on login/authentication. This extension does just about anything to a web page that you'd like.
About

Whatever part of GlassFish or the Java EE world that catches my attention. (Also, go Red Sox.)

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today