Monday Feb 08, 2010

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

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

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

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

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

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

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.

Wednesday Oct 01, 2008

In a previous SocialSite blog, I had a short screen cast that described in brief what your web site needs to do to include SocialSite gadgets. To save you some clicking, here it is again. In this blog, I'll give some more information, and, if you follow along, a complete working example. A simple example, but a working example.

In a recent email thread on our users list, Dave broke the integration down into three necessary steps:

  1. Add an authentication delegator page to your web app
  2. Add the SocialSite context and Gadgets to pages in your app
  3. Add socialsite_context.xml to SocialSite to specify your app's delegator page
I'll cover the steps here, starting with some pre-work.

Step 0, part A

Have a web site. In this example, I've used NetBeans to create a simple web app. No frameworks, nothing fancy, just a simple web app called SimpleWebApp with the default index.jsp file that is created for you. For this web app, the index.jsp page could be reached at http://localhost:8080/SimpleWebApp/. Start NetBeans, choose New Project, then Java Web -> Web Application and follow the prompts.

Step 0, part B

Install SocialSite. If you haven't done that yet, you're in the wrong blog. However, here are some steps that are necessary for getting gadgets running. When you first install SocialSite and go to the web app in a browser, you'll see a login form in the middle like this:

Login Form

If you already have users in your web application, you can register them here. For this example, I've clicked Want to register? and entered this information (the password, not that it matters, was password):

New User Information

Note: In one email to our user's list, someone tried using the built-in "admin" user in a sample web app. By default, the "admin" user has no profile and so the gadgets won't work until you create a profile. For instance, if you log into SocialSite as the admin you'll see this on the main page:

Admin has no profile

Step 1

Add an authentication delegator page to your web app. In the screen cast, this is the socialsite_context.jsp or context.html.erb file. A request for this file is sent by the SocialSite server, sending the same cookies to your web app that the client would. It's how your site can assert the identity of the current user to SocialSite. A real-life example of this file is in the socialsite workspace. For my simple web app that has no user authentication, I've hard-coded the user for demonstration purposes. Just create a socialsite_context.jsp page in your simple app and add this:

<%@ page language="java" %>
<%@ page contentType="application/json" %>
{
  'attributes': {
    <%-- demonstration only! --%>
    'viewerId': 'newuser'
  }
}

In a real web app, make sure you specify the user here the same way you would in your other web pages, either with request.getRemoteUser() for Java EE container authentication or however you're handling authentication.

Step 2

Add the SocialSite context and Gadgets to pages in your app. Now you can add gadgets to your pages, though first you need to add some context for SocialSite. In this example (save file and open in an editor), I've added two javascript elements at the top to load information from SocialSite and to tell SocialSite where I put the authentication delegator page. These calls need to be in all the pages that are going to include gadgets, so it's a good idea if you have a header jspf file or something similar to put them there. The calls look like this:

    <script type="text/javascript"
      src="http://localhost:8080/socialsite/js/consumer.jsp"></script>
    <script type="text/javascript">
      socialsite.setContext({
        'attributes': {
          'ownerId': 'newuser' <%-- hard coded for demo! --%>
        },
        'delegate': {
          'method': 'GET',
          'url': 'http://localhost:8080/SimpleWebApp/socialsite_context.jsp',
          'headers': {
            'cookie': document.cookie
          }
        }
      });
    </script>

In the body of the page, now you can add the calls to load SocialSite gadgets. For example:

    <script type="text/javascript">
      socialsite.addGadget({'spec':'/local_gadgets/dashboard.xml', 'removable':false});
    </script>

Step 3

Add socialsite_context.xml to SocialSite to specify your app's delegator page. You're almost there. Finally, you need to let SocialSite know that it's ok to communicate with an external app -- specifically, that it's ok to let another site assert the id of the user. To do this, add a socialsite_context.xml file to SocialSite's classpath. For my "SimpleWebApp" example, here is the file to use. Note that it contains the URL of the context delegator page that you added in step 1. One easy way to add this file to your classpath is to copy it to your glassfish/domains/domain1/lib/classes/ directory, which should already contain a socialsite.properties file that was added during installation. Restart GlassFish to pick this up.

More official documentation is on the way, but I hope this helps you get started. Feel free to add comments, and follow along on the SocialSite blog for all the latest information.

Thursday Sep 04, 2008

I was fiddling with a couple sample applications to use with Project SocialSite and found that none of the widgets I added to my pages were working. If you're unfamiliar with our widgets, they're little bits of JavaScript that you can add to your existing web pages in order to add social-networking functionality. Each one is written as a jMaki widget, and internally they each wrap a Google OpenSocial Gadget to provide the social networking UI.

So I had a couple new web apps that I created with NetBeans. With the jMaki plugin, I dragged some SocialSite widgets into the pages and ran the projects. "Unable to create an instance of jmaki.widgets.socialsite.search.Widget. Enable logging for more details.." Oops. Turning on debugging in jMaki's glue.js file at my web root, I see that the gadgetizer-core.js file on which the widgets rely was not found. In fact, it was missing from my project completely, when it should have been copied into /resources/socialsite/resources in my web root as described next.

All of the SocialSite widgets live in /resources/socialsite/widget-name-here, and each depends on a file, by convention, in /resources/socialsite/resources/. I can specify this file in a widget.json configuration file, and two things are supposed to happen. First, the jMaki plugin for my IDE copies this file into the web app when I add a widget. Second, the jMaki runtime loads this file before the widget so that it's available to the JavaScript engine when the page is viewed. In my case, I see that my resources aren't being added properly in my web apps. Even after I add them manually, I still see errors with the file not found in certain web frameworks.

The culprit? Well, I guess I am. I wrote the original widget.json files for our widgets, and somewhere along the way I messed up one tiny detail. Here is the widget.json file for our search widget. This version works:

{
    'name': 'Search Widget',
    'type': 'SocialSite',
    'jmakiVersion': '1.1',
    'version': '1.0',
    'description': 'Let\'s a user search for people and/or groups .',
    'config': {
        'type': {
            'id': 'socialsite',
            'libs': [
                '../resources/gadgetizer-core.js'
            ]
        }
    }   	
}

What I had, however, was a URL in the config entry that was relative to the root of the web app:

    'libs': [
        '/resources/socialsite/resources/gadgetizer-core.js'
    ]

While this worked at runtime for some JSP apps, it failed in other cases where the routing to resource balked at the path I was using. Looking through some existing jMaki widgets (if using NetBeans, you can see all the code in $HOME/.netbeans/<version>/jmakicomplib), I found my mistake. I probably took some hasty notes early in our development, or somewhere along the way the files or jMaki changed.

We hope that Project SocialSite, besides being a useful addition to your own sites, also serves as a good example for writing your own Google Gadgets and/or jMaki widgets. If you're following along, though, make sure you pick up this change. Learning from your mistakes is good; learning from my mistakes saves you time.

Tuesday May 27, 2008

Last week I gave a presentation on GlassFish to the Connecticut Java User's Group. I wanted to answer a couple questions here that came up during the talk. Big thanks to the group for letting me come talk to them, and also thanks to Arun for letting me use his presentation.

One issue that came up was how GlassFish works with other frameworks, applications, etc., and I was asked about setting up GF as the servlet container with Apache as the web server for static content. The user was already using Apache web server in front of Tomcat and wanted to know how it would work with GF. The official docs one the topic are here, and the conversation can be followed on the GlassFish forum.

A related question was about the performance of GlassFish compared to Tomcat when used just as the servlet container with another web server in front. While I can't provide any official answer to this, the email thread can be followed (and continued!) on the forum page.

While talking about scripting support in GlassFish, I asked the group if there were other languages/frameworks that they were using besides the ones already supported. Someone asked about Perl with the Catalyst framework. I've passed along the info to the scripting team for their consideration. Please stay tuned to GlassFish Scripting for continuing information on scripting support.

Thanks again to the CT JUG for having me and for letting me plug my current project, Project SocialSite. I'll update this post with any more information as it comes in.

Monday Apr 28, 2008

I was recently setting up a couple new machines and went through my normal process:

  • Install a new browser or two.
  • Install Java if there isn't a version I want already.
  • Install NetBeans.

Need ant? It's already in NetBeans -- add the ant/bin directory in your NetBeans installation to your path (a good idea so you don't run into version mismatches between command line and IDE). Need cvs? There's already a nice cvs GUI in the IDE. So I'm ready for development, or so I thought.

A project I was working on, as part of the build process, used ant to check out a couple other workspaces under cvs. This failed since ant was expecting cvs to exist in my path. Oops. Ok, I could go download one of the many cvs clients, or on a Mac installation install the large developer bundle. But there's already some form of cvs inside NetBeans, so why can't I use that? No point duplicating bits on my hard drive.

Well, you can use the cvs client inside NetBeans from the command line. There is no executable cvs(.sh, .bat) script, but there's a cvs client jar file that will do the trick: org-netbeans-lib-cvsclient.jar

You can find it easily enough but here are the locations in NB 6.X:

  • 6.0: <netbeans>/ide8/modules/org-netbeans-lib-cvsclient.jar
  • 6.1: <netbeans>/ide9/modules/org-netbeans-lib-cvsclient.jar

So I just create a little script called "cvs" (or cvs.bat) to call the jar file. Here's the one I'm using on a Mac, with the full path left out for readability:
  java -jar <path>/org-netbeans-lib-cvsclient.jar "$@"

Output:

  hostname:~ bobby$ cvs -version
  Java Concurrent Versions System (JavaCVS) 1.9 (client)

That's all there is to it. With this simple cvs script, I can now run all the command line cvs I want and use the GUI to handle the heavy lifting (ok, the heavy, the medium, and most of the light lifting).

Friday Sep 21, 2007

The Sun Tech Days Boston event was held last week. As part of Sun Tech Day on Wednesday, Tom Kincaid gave a talk on Java EE 6 and the future of the EE platform. This blog captures the demonstration that we gave of an early preview of GlassFish v3 (which is implementing Java EE 6). For more information on Sun Tech Days Boston, Ryan Shoemaker has recorded his days at the conference: part 1, part 2.

In the demonstration, we wanted to show four main features of GFv3:

  • The modular nature of GFv3, which results in very fast startup time.
  • Containers for web apps and JRuby apps loading on demand.
  • Simplified deployment of JRuby applications.
  • The inclusion of Java code inside a Ruby application.
Tom said I could have about ten minutes for the demonstration, but GFv3 is so fast I think we only needed five. Hopefully the audience appreciated that -- more of Tom, less of me fumbling around on a laptop.

To put together the demonstration, I borrowed (stole) from a screencast by Jerome Dochez and a blog by Arun Gupta. Add in a daily build of NetBeans IDE and you have just the mix.


The Software

GlassFish v3: The "preview1-b2" build is available here. Installation is simple: just java -jar <filename>. Drop the bin directory into your path and you're all set.

NetBeans and the GFv3 plugin: By now, the Beta 1 version of NetBeans 6 is out. Since it hadn't been released at the time of the conference, I went with a daily build from September 7th and grabbed the GlassFish v3 plugin from the beta update center. When you add GF to the NetBeans's server list, NB gives you a download button to grab the app server:


The version isn't the same as the preview 1 b2 shapshot that I was using, but that combination worked anyway. You don't need to add the GFv3 server to NetBeans for these examples since I give instructions for deploying/undeploying from the command line.

JRuby: Following the directions on Arun's blog, you can install JRuby 1.0, add the bin directory to your path, and install Rails with

      jruby -S gem install rails -y --no-rdoc

After this, just add the JRUBY_HOME value to the end of the asenv.* file in glassfish/config/.


The Demonstration

Running GlassFish v3: In your glassfish/lib directory, you can see all of the jars that make up the kernel and containers of GFv3. That little (less than 15k) jar file called glassfish-10.0-SNAPSHOT.jar is your target. Assuming you are in the glassfish directory, give the Java command:

      java -jar lib\glassfish-10.0-SNAPSHOT.jar

...and you should see something like this:

D:\glassfish>java -jar lib\glassfish-10.0-SNAPSHOT.jar
[#|2007-09-14T16:32:02.589-0400|INFO|GlassFish10.0|javax.enterprise.system.core|_ThreadID=
10;_ThreadName=Thread-2;|Listening on port 8080|#]

[#|2007-09-14T16:32:02.770-0400|INFO|GlassFish10.0|javax.enterprise.system.core|_ThreadID=
10;_ThreadName=Thread-2;|Supported containers : phobos,web,php,jruby|#]

[#|2007-09-14T16:32:02.790-0400|INFO|GlassFish10.0|javax.enterprise.system.core|_ThreadID=
10;_ThreadName=Thread-2;|Glassfish v3 started in 791 ms|#]
Note the startup time, in this case under .8 seconds on a slightly old laptop. You can browse http://localhost:8080 to see that the server has indeed started and is serving static html content. Add another html file to domains/domain1/docroot and you can view it in the browser, or edit index.html (go ahead, it's your app server!) to see changes. Now it's time to add some applications.

 

A web application example: In NetBeans, create a simple web application. Ctrl-Shift-n is one way to bring up the "New Project" window, and you can choose Web -> Web Application to create a simple web app. The index.jsp file will come up automatically in the editor. Just add some text of your choosing and build with F11. We called the project "jsphello" and the war file was built in jsphello/dist/jsphello.war. If you have the GFv3 plugin, you can deploy with NetBeans, but we deployed from the command line in order to watch both the server and asadmin output at the same time. To deploy, use

      asadmin deploy --path <path to jsphello.war>

The asadmin script will call a Java command to deploy the application, and your output should look something like:

D:\examples>asadmin deploy --path jsphello\dist\jsphello.war

D:\examples>java -jar D:\glassfish\bin\\..\lib\admin-cli-10.0-SNAPSHOT.jar deploy --path jsphello\dist\jsphello.war
SUCCESS : Application jsphello deployed successfully

Note that in the GlassFish server log, the web container is loaded when it is needed. If you stop and restart the server now, you will that the web container is loaded at startup since a web application has been deployed. You can undeploy the application with:

      asadmin undeploy --name jsphello

To get a list of deployed applications, use:

      asadmin list-applications

After undeploying the web application and using the "list-applications" command, your output will look like the text below. You can see that the web container is loaded, ready for another web application to be deployed (if you restart the server, it will not load the web container until you need it).

D:\examples>asadmin list-applications

D:\examples>java -jar D:\glassfish\bin\\..\lib\admin-cli-10.0-SNAPSHOT.jar list-applications
SUCCESS : List of deployed applications per container
ContractProvider : web_ContractProvider
        properties=(Connector module=com.sun.enterprise.glassfish:gf-web-connector,
        Sniffer module=class com.sun.enterprise.v3.web.WebSniffer)

 

A JRuby example: In NetBeans, open the New Project window and choose Ruby -> Ruby on Rails Application. On the next page, give the application a name (e.g., "railshello") and click Finish. After the IDE is finished generating the files needed, you can add a controller and view for a simple "Hello World" application. Right-click on the project name and choose Generate. Fill out the resulting dialog as below and click Ok:

NetBeans will then generate say_controller.rb and hello.rhtml files for you. We edited the controller to add a string and then used that string in the "hello" view.

say_controller.rb:

class SayController < ApplicationController

  def hello
    @hello_string = "Hello World"
  end
end
hello.rhtml:
<h1>Say#hello</h1>
<p>Find me in app/views/say/hello.rhtml</p>
<%= @hello_string %>

GlassFish v3 supports a "straight" deployment of JRuby code. To deploy our 'railshello' application, we don't have to first wrap it in a war file. We can simply call asadmin and deploy the application directory (asadmin calls the proper "java -jar ..." command):

D:\examples>asadmin deploy --path railshello

D:\examples>java -jar d:\glassfish\bin\\..\lib\admin-cli-10.0-SNAPSHOT.jar deploy --path railshello
SUCCESS : Application railshello deployed successfully

Watching the server log, you can see that the JRuby/Rails runtime is loaded into GFv3 as needed. Then the application is deployed and is ready to run. To access the page once it's deployed, use http://localhost:8080/railshello/say/hello. This directory deployment of the application makes for a very fast development cycle. For instance, if you change the @hello_string value in say_controller.rb, you only have to save the file and reload the page in your browser.

 

Adding some Java into the Ruby code: Using the same JRuby/Rails application, you can add Java code directly into the say_controller.rb file without any other compilation or deployment steps. For our example, we added some trivial Java code in to create a HashMap and set the value of @hello_string using a value in this map. The new version of say_controller.rb:

require 'java'
include_class 'java.util.HashMap'

class SayController < ApplicationController

  def hello
    myMap = HashMap.new
    myMap.put("key", "Hello from Java code!")
    @hello_string = myMap.get("key")
  end
end

Now simply save the file and reload the page in your browser. The mix of Java and JRuby code works without any other steps since we have done the directory deployment. Finally, to undeploy the application, give the same command that you used to undeploy the jsphello example:

      asadmin undeploy --name railshello

Though this early version of GFv3 does not show anything in the log when you undeploy the app, you can verify that it is no longer deployed with the asadmin 'list-applications' command described above.

Tuesday Apr 24, 2007

In Java EE applications, security roles are used to restrict access to resources. A typical example is to limit access to parts of a business web site to users who are in the role "customers," while allowing users in the role "suppliers" access to other parts of the site. The application developer can specify which URLs or EJB methods can be accessed by users in which roles, and can programmatically make security decisions based on user roles at runtime. So a role is a logical privilege that can be granted to (or withheld from) users to control access within an application.

The identities of the users are stored in the application server as principals (also called "users"), which can belong to groups. Thus the privileges represented by the roles can be mapped to actual users by mapping the roles to principals or groups. This decoupling of the application's roles and the container's principals/groups allows the same application to be deployed on different servers without any changes to the code. Only the security role mapping needs to be changed in the deployment descriptor (for GlassFish, this is in sun-application.xml, sun-web.xml, or sun-ejb-jar.xml). The deployer could map the role "suppliers" (continuing above example) to an existing group "partners," a principal "admin," or even a group with the same name "suppliers." In this last case, a simplification can be made such that the default principal to role mapping is used and no role mapping is required in the deployment descriptor. This can be useful when you are writing an application and already know which groups are used in the server to which you will be deploying.

For more information on the roles and groups, please see Shing Wai's blog assign-groups in GlassFish Security realm.

The following is a simple web example that uses default principal to role mapping and so does not use a <security-role-mapping> element in the sun-web.xml file. In fact, it does not use sun-web.xml at all. To add a user and group for this example, open the admin console (normally localhost:4848) and choose: Configuration -> Security -> Realms -> file in the tree in the left pane. Then, in the right-hand pane, click Manage Users. Click New, enter "sparky" for User ID, add "users" to the Group List, and use "ee" for a password. Click OK.

This application consists of a simple jsp page, and it can only be accessed by someone in the role "users" (which matches the group "users" created above). This is the entire page, index.jsp:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <body>
        <h2>Hello ${pageContext.request.remoteUser}</h2>
    </body>
</html> 
    

This is the entire web.xml file:


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="h
ttp://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>myapp</web-resource-name>
            <url-pattern>/*</url-pattern>
            <http-method>GET</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>users</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>default</realm-name>
    </login-config>
    <security-role>
        <role-name>users</role-name>
    </security-role>
</web-app>
    

To create the application, save index.jsp into a directory, create a subdirectory "WEB-INF" and save web.xml into it, and create the war file: 'jar cvf test.war *' The war file can also be downloaded here.

Because security role mapping happens at deployment time, the default mapping must be turned on before the application is deployed. To turn on the default mapping, choose Configuration -> Security in the admin console. Click Enabled next to Default Principal to Role Mapping and Save.

Then the example war file can be deployed through the admin console or with 'asadmin deploy test.war'. When you attempt to reach the page in your browser (for instance with http://localhost:8080/test), you will be prompted for username and password. Entering "sparky" and "ee" should take you to a page with Hello sparky. The example works because the same string is used for both role and group, and so any user in the group "users" will also be in the role "users."

Friday Sep 22, 2006

The milestone 2 release of WSIT includes some "behind the scenes" changes in the way endpoint metadata can be exchanged. All WSIT endpoints can now respond to metadata exchange ("Mex") requests to obtain the wsdl and schema information. These requests are small soap messages requesting the endpoint's data. They are nothing more than an action header and an empty body, and the endpoint responds with a mex response containing wsdl and schema documents.

On the client side, wsimport can use the mex code to make requests to the service for metadata. While this is normally transparent to the user, if you're running wsimport while using a traffic monitor (such as wsmonitor) you may see these messages.

Normally, wsimport will make mex requests when you give the address of the endpoint itself such as "http://example.com/myservice." In the past, you would have to use a "?wsdl" at the end of the address to specify the WSDL location. With mex, you can still give wsimport the WSDL location, or you can use the endpoint location. In this latter case, wsimport with mex will try various mex requests: for instance, a soap 1.2 attempt followed by a soap 1.1 attempt. If these all fail, meaning that you're trying an endpoint that doesn't support mex, wsimport will default to trying the HTTP Get call to the address with "?wsdl" appended.

These mex requests and responses allow greater flexibility in how metadata is obtained, and pave the way for obtaining metadata with other transports in the future.