Skip navigation
ANNOUNCEMENT: community.oracle.com is currently Read only due to planned upgrade until 29-Sep-2020 9:30 AM Pacific Time. Any changes made during Read only mode will be lost and will need to be re-entered when the application is back read/write.

I wanted to trace exactly what happens when a JSF page uses a redirect. Here are my experiences with the HTTP and TCP/IP monitors in NetBeans and Eclipse, and why I ended up using Wireshark instead.

Consider the usual JSF flow. The client makes a GET request for the first page. That's a special case, but from then on everything follows a pattern. The server renders a page containing an HTML form that is to be posted back to the same URL. The client makes a POST, the server navigates to a new page and renders it. The problem is that the browser requested the new page with the old URL, and so the browser bar URL is always one step behind.

 

You can fix that with a redirect. If you use JSF 2.0 “EZ navigation”, you produce outcome strings like this.

if (...) return "success?faces-redirect=true"
else return "failure?faces-redirect=true"

So, what exactly happens now? That's where HTTP monitoring comes in.

In Netbeans, you activate HTTP monitoring by checking “Enable HTTP monitor” in the GlassFish server properties.

You can then see the traffic in the HTTP Server Monitor tab. For example, here you can see the initial GET, the POST to/faces/index.xhtml, and the GET to/success.xhtml.

Unfortunately, NetBeans doesn't show you what the server returns to the client, so you don't see why that second GET request was made.

The Netbeans HTTP monitor modifies thedomain1/config/default-web.xml file, adding a filter to every web application. That filter is left in place after Netbeans exits. If you run the application from inside Eclipse, the filter will throw an exception. The remedy is to turn monitoring off before exiting Netbeans.

Eclipse uses a different approach. It can monitor arbitrary TCP/IP traffic. With Glassfish, right-click on the server in the Servers tab and select Monitoring > Properties. Then click on Add and select port 8080. Select Start to actually start monitoring. Then you need to point your browser tolocalhost:8081/contextRoot/faces/index.xhtml. Eclipse routes the packets from port 8081 to port 8080, which gives it a chance to monitor them.

As you can see here, Eclipse shows what the server sends back to the client.

Well, almost. What you don't see are the HTTP headers, so you don't see how the browser knows where to go. (The browser doesn't parse the HTML that you see in the screen capture—that's for people who turned off automatic redirect in their browser.)

To really see what is going on, I used Wireshark. It captures all TCP/IP traffic, doesn't install any filters in your app server, and doesn't make you change port numbers. It decodes HTTP, showing you the entire response:

As you can see, the server sets the Location header to the redirect location.

Executive summary: The HTTP and TCP/IP monitors that are built into the IDEs are useful for routine traffic monitoring, but for hardcore sniffing, Wireshark is hard to beat.

In the relentless fight against configuration boilerplate, JSF and Glassfish have taken yet another small step forward. As of Glassfish v3 build 68, you no longer need to declare the faces-servlet in WEB.XML.

<servlet>
   <servlet-name>Faces Servlet</servlet-name>
   <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
   <servlet-name>Faces Servlet</servlet-name>
   <url-pattern>/faces/*</url-pattern>
</servlet-mapping>

In fact, you can omit web.xml altogether, except then you don't get to set javax.faces.PROJECT_STAGE toDevelopment. (Since I am a developer, I think it's too bad that's not the default.)

GlassFish automatically provides a JSF servlet mapping for the/faces/*, *.faces, and *.jsfpatterns, provided that any of the following conditions applies:

  • Any of the classes in the web application uses a JSF 2.0 annotation
  • Any initialization parameters start withjavax.faces
  • The WEB-INF/faces-config.xml file is present

Isn't it grand? Now you can have a JSF app without web.xml or faces-config.xml, just a bunch of .xhtml pages and Java classes annotated with @ManagedBean.

The only fly in the ointment is that, if you really want to be thoroughly modern and use web beans, erm, JSR 299 Contexts and Dependency Injection, then you should still leave something in place to trigger the servlet mapping.

Another nifty step forward: NetBeans 6.8 Milestone 2 now does autocompletion on JSF 2.0 facelets pages, including tags, attributes and even EL expressions.

For example, here, Netbeans has found a@ManagedBean(name="user") and locatedname and password properties.

It might be a good idea to filter out the uselessObject methods—when is the last time you wanted to call notifyAll in an EL expression? Or worse,wait :-)

After EE5 came out, I did all my EE development in Netbeans. It gave me one-stop shopping, bundling everything that I needed in a single download. I moved to Eclipse when Netbeans couldn't deal with EE6 improvements such as the simplified packaging. It worked in Eclipse (out of ignorance, not some grand plan), and that's what I used for the last 12 months or so. I was reasonably satisfied, thanks to the Glassfish Eclipse plugin, but Eclipse's support for editing JSF pages is extremely basic. Now I am very tempted to go back to Netbeans—I am a sucker for autocompletion.

And now for something entirely different...one of my students asked how to write a recursive function in Scala with varargs. Apparently, the internet has lots of articles complaining about the challenge of calling Java varargs methods from Scala, but this particular issue didnot google well. Here goes...

In Scala, you declare varargs like this:

def sum(args: Int*) = {
  var result = 0
  for (arg <-args.elements) result += arg
  result
}

Think of Int* as a sequence of 0 or more integers. In Java, an int... is transformed into anint[], and in Scala, an Int* becomes aSeq[Int].

Of course, you can call

sum(1,2,3,4,5)

 

But you can't call

sum(1 to 5)

What gives? 1 to 5 is a Range[Int], and that's a subtype of Seq[Int]. But unlike Java, Scala insists that you pass a sequence of Int tosum, not a Seq[Int].

The remedy, as explained in the Scala Reference Section 4.6.2, is to call

sum(1 to 5 : _*)

that is, 1 to 5 as a sequence of something.

My students ran into this when trying to write a recursive function with varargs. The obvious

def sum(args: Int*) : Int = 
  if (args.length == 0) 
    0 else 
    args.head + sum(args.tail)

doesn't work. The trick is again to insert the : _*cast:

def sum(args: Int*) : Int = 
  if (args.length == 0) 
    0 else 
    args.head + sum(args.tail : _*)

I got a blogger pass for Oracle OpenWorld. Here is my report from the show floor.

Yesterday, I wrote that Oracle OpenWorld seemed a bit bigger than Java One. Today when I saw the crowds during daytime I realized how naive I was. This is a HUGE conference, filling the main Moscone building, Moscone West, and two hotels. Talks range from “Virtualize your enterprise and cut costs with Oracle VM” to “Win Big with Government Contracts and PeopleSoft ESA”. The bookstore didn't carry Core Java but instead featured books on Sarbanes-Oxley and self-motivation, in addition to the usual Oracle DBA fare. There were a few talks on Java, JDBC programming, JSF, ADF Faces, and the BEA app server.

Alex Buckley and John Rose gave a beautiful presentation “Towards a Universal VM” in which they described the path taken by the Java VM towards supporting programming languages with very different execution models than Java. John described theinvokedynamichref="http://openjdk.java.net/projects/mlvm/" instruction in detail and briefly reviewed potential future enhancements, such as tail call elimination and continuations, that are currently explored in the DaVinci project. The vision is that one day the Java VM will be truly universal, able to efficiently execute any programming language. Unfortunately, attendance was very sparse—this is clearly not a topic that was on the radar screen for the typical database person :-)

Afterwards, Alex and I talked a bit about the slow pace of Java evolution. I told him that I am using Scala for some new projects, and he said I am far from the only one. And I am also not the only one who complains about confusing Scala code in which some macho coder removed all optional dots, parentheses, and semicolons. So, I do want Java to continue evolving, and I have very specific ideas how that should happen, and no, I don't want to pay for it. Alex talks to hundreds, if not thousands, of people all the time who are just like me. So, it did make me think about what it means for Java to be free, and who should pay for designing, developing, and testing future versions.

The afternoon talks on Java EE 6, GlassFish, and JSF 2.0 were much better attended. Java EE 6 and GlassFish 3 are scheduled to be final in December. There is one last refactoring of EE6 components. Now the managed bean and interceptor facilities are generic mechanisms—see this blog for details. And, of course, JSR 299 (formerly known as “web beans”) is a part of the spec. As Roberto Chinnici said, it is the glue that puts JSF and EJB together for much higher programmer productivity.

I cannot overemphasize how much simpler EE6 is than just about any web programming model I know. All of the bad parts of the old EJB are gone. No XML. No crazy packaging of WARs and JARs inside EARs. Annotate your beans and persistent objects, and let the container worry about the database, transactions, clustering, and so on. This was, of course, the vision when EJB was first designed, and it has taken a long time to actually get there. But so what, now it is here, and it would be foolish not to take advantage of it just because some previous versions weren't so great.

Similarly, if you haven't given GlassFish v3 a try, you are in for a very pleasant surprise. It is fast. Startup is not just faster than JBoss, but faster than Tomcat! Hot deployment works great, there is a nice admin UI and a scriptable command line interface, and the Eclipse and Netbeans integrations are first-rate. I can't see myself going back to Tomcat—there just would be no point.

Jim Driscoll and Andy Schwarz (the latter from Oracle) gave a superb presentation about JSF 2.0. Normally, presenters try to cram all the fact about topic A on one slide, then move on to topic B, and so on. In contrast, Jim and Andy did a great job showing the interconnections between the topics. I always believed that a "spiral" approach to learning works much better than the usual taxonomic style, and the effectiveness of their presentation reinforces my belief.

By now, the changes in JSF 2.0 are well-known: Annotations and ez-navigation instead of faces-config.xml. Ajax that I can do. Nice support for GET requests. Easier component authoring. A decent page composition system. Standard bean validation. Much, much, much better error handling. There are still some warts that should be addressed in JSF 2.1, but JSF 2.0 is in great shape. And fundamentally it is easy. David Geary and myself are rewriting our Core JSF book, and it is very gratifying to be able to erase pages full of cruft.

Andy held out the possibility that JSF 2.1 may include some additional components to round out the standard component set. I very much hope that happens. It is great that RichFaces, IceFaces, etc. are working hard on JSF 2.0 versions, but a few more components such as calendars, fileupload, and trees, surely could be a part of the standard. Andy recommends that anyone who wants to comment on JSF 2 should use the JSR 314 discussion board—a well-kept secret since it currently has 2 posts :-)

It turned out to be a very productive afternoon for me since I was able to ask a large number of intricate technical questions after these presentations, something that is pretty hard to do in the madding crowds of Java One.

On a more sobering note, regression to the mean meant that the food for today's evening party was unimpressive. Drinks were still free, though.

Aaron Houston, the fearless leader of the Java Champions, got me a blogger pass to Oracle OpenWorld. Here is what I learned on the opening night.

If you thought Java One is big, Oracle OpenWorld seems bigger. The keynote was packed—and that on a Sunday night! The party afterwards was not in the cavernous Moscone center, but in tents on Howard Street and around Yerba Buena Gardens. The food was better than at Java One, and drinks were free, just like in the good old days of Java One.

http://blogs.sun.com/theaquarium/resource/OracleOpenWorld2009-245_75px.gif

But, and that's a big but, you've got to love red. Red was everywhere. Scott McNealy presided over the evening keynote, and even he wore a maroon sweater, the closest he could come to red, he said.

After a not-very-funny top-10 list that I will not repeat, he listed what he considered the top ten innovations that happened at Sun. Here they are:

10. NFS. 9. SPARC. 8. #1 Open Source Contributor. 7. Solaris.6. Java. 5. E10K 64 way Sparc Chip. 4. ZFS/Open Storage/Flash (Exadata). 3. Data center in shipping container. 2. SunRay. 1. “Cool threads” chip multithreading.

Hmmm, that puts us Java folks in perspective...

He reminisced that in his years at Sun, they kicked butt, had fun, didn't cheat, loved their customers, and changed technology forever.

Which they did. But not with SunRay...

He asked the question that was on everyone's mind: What is going to happen?

With SPARC? Solaris? MySQL? Java?

Oracle has run ads confirming their commitment to SPARC and Solaris.

The MySQL issue that is explored by the European Community may have some potential merit, and it could of course be easily dealt with by spinning off MySQL. I suspect there is stubbornness on both sides. The Europeans may be miffed that Oracle took their sweet time asking them to approve the merger. Anyway, what we care about is what will happen to Java. Scott McNealy quotes Larry Ellison as saying “Java speaks for itself.”

They don't call that company “Oracle” for nothing...

http://weblogs.java.net/blog/cayhorstmann/archive/delphi-oracle.jpg

James Gosling went on stage to tell us that he thinks that Oracle will be good for Java. He is looking forward to working for a software company :-) He mentioned that Oracle may be a bit underprepared for the size, enthusiasm, and rambunctiousness of the Java developer programs—there seem to be 100x more Java user group members than Oracle has.

James also remarked somewhat cryptically that San Francisco might be big enough to host both the Oracle conference and Java One at the same time if they commandeered some ships, which should be no problem during Fleet Week.

If they are seriously considering combining the conferences, I wonder if it will work. The attendees I talked to were very nice, but they weren't, well, coders. I mean it is all good and well for people to come to Oracle OpenWorld to find out how to replace an aging Oracle Whatsis sytem, but I go to a conference to meet people who care about what I care, and that is Java and not Oracle Whatsis.

Larry Ellison, who joined the stage later, was a very confident speaker who talked a good game about how SPARC and Solaris run Oracle much better than IBM, and I don't doubt that they do. There was a lot of talk about how engineering everything from the network to the processor, storage, operating system, and database makes for a more compelling offering. I hope it does, so that it makes a lot of money for developing Java further :-)

Afterwards, I joined a meeting of representatives of Oracle and Java user groups. (Kathleen McCasland, the executive director of the Oracle Dev Tools User group, turns out to have much in common with me. She also has twins, and she too lived in the beautiful San Francisco Presidio.) When it comes to user groups, I sensed a bit of a culture difference. Sun has been extremely good in fostering diverse and opinionated groups. Oracle seems more revenue-driven and top-down. We'll just have to see how all that goes.

When you need to produce lots of fairly straightforward graphs, Java2D is your friend. In this blog, I show you how you can render simple images as crisp-looking PDF or EPS files, provided you can draw them on a Graphics2D object.

Recently, I had to draw a bunch of simple images, such as this one

or this PDF

Of course, you can do these drawings in Illustrator or Inkscape. But if you are a coder like me, a graphics program may not be your cup of tea. It takes me about 15 seconds to code

   for (int i = 0; i < 6; i++)
      for (int j = 0; j < 6; j++) {
         g2.setColor(2 <= i && i <= 3 && 2 <= j && j <= 3 ? Color.GREEN : Color.RED);
         g2.fillRect(i * 30, j * 30, 29, 29);
      }

(Or at least it feels like 15 seconds :-))

To do the same in Inkscape would take me a seriously long time, and I would be bored to tears.

What about that maze? I had to set it up anyway for a CS1 lab, using Alice, and it wasn't much extra trouble to add a draw(Graphics2D g2) method to each Robot, Wall, and Beeper object. I really enjoyed having an image with perfect lines and circles, with only a few minutes of work.

Once you can draw your image on a Graphics2D, it is a routine matter to turn it into a PostScript or image file, using standard Java 2D operations. You can then process the PostScript output into PDF or EPS using ps2pdf orps2eps. Java 2D seems to have fallen out of fashion, and there doesn't seem to be a lot of useful information (outsideCore Java, Filthy Rich Clients, and the Sun Java tutorial). That's too bad—it is a very powerful framework and it isn't hard to learn. So, here is the program outline that I use. Feel free to use it for your 2D rendering needs.

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.print.*;
import java.io.*;
import javax.imageio.*;
import javax.print.*;
import javax.print.attribute.*;
import javax.swing.*;

public class Image {
   // Set your image dimensions here
   private static int IMAGE_WIDTH = ...;
   private static int IMAGE_HEIGHT = ...;

   public static void draw(Graphics2D g2) {
      // Your drawing instructions go here
      ...
   }

   // No need to touch anything below this line
   public static void main(String[] args)
   {
      final JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      final JComponent component = new JComponent() {
            public void paintComponent(Graphics g) {
               draw((Graphics2D) g);
            }
            public Dimension getPreferredSize() {
               return new Dimension(IMAGE_WIDTH, IMAGE_HEIGHT);
            }
         };
      frame.add(component);
      JMenuBar menuBar = new JMenuBar();
      frame.setJMenuBar(menuBar);
      JMenu menu = new JMenu("File");
      menu.setMnemonic('F');
      menuBar.add(menu);
      JMenuItem item = new JMenuItem("Save", 'S');
      menu.add(item);
      item.setAccelerator(KeyStroke.getKeyStroke("ctrl S"));
      item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
               JFileChooser chooser = new JFileChooser();
               if (chooser.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION)
                  try {
                     saveImage(component, chooser.getSelectedFile().getPath());
                  } catch (Exception ex) {
                     ex.printStackTrace();
                  }
            }
         });      
      frame.pack();
      frame.setVisible(true);
   }

   private static void saveImage(final JComponent comp, String fileName) throws IOException, PrintException {
      if (fileName.endsWith(".ps")) {
         DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
         String mimeType = "application/postscript";
         StreamPrintServiceFactory[] factories = StreamPrintServiceFactory.lookupStreamPrintServiceFactories(flavor, mimeType);
         FileOutputStream out = new FileOutputStream(fileName);
         if (factories.length > 0) {
            PrintService service = factories[0].getPrintService(out);            
            SimpleDoc doc = new SimpleDoc(new Printable() {
                  public int print(Graphics g, PageFormat pf, int page) {
                     if (page >= 1) return Printable.NO_SUCH_PAGE;
                     else {
                        double sf1 = pf.getImageableWidth() / (comp.getWidth() + 1);
                        double sf2 = pf.getImageableHeight() / (comp.getHeight() + 1);
                        double s = Math.min(sf1, sf2);
                        Graphics2D g2 = (Graphics2D) g;
                        g2.translate((pf.getWidth() - pf.getImageableWidth()) / 2, (pf.getHeight() - pf.getImageableHeight()) / 2);
                        g2.scale(s, s);
                        
                        comp.paint(g);
                        return Printable.PAGE_EXISTS;
                     }
                  }
               }, flavor, null);
            DocPrintJob job = service.createPrintJob();
            PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
            job.print(doc, attributes);
         }
      } else {
         Rectangle rect = comp.getBounds();
         BufferedImage image = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_RGB);
         Graphics2D g = (Graphics2D) image.getGraphics();
         g.setColor(Color.WHITE);
         g.fill(rect);
         g.setColor(Color.BLACK);
         comp.paint(g);
         String extension = fileName.substring(fileName.lastIndexOf('.') + 1);
         ImageIO.write(image, extension, new File(fileName));
         g.dispose();
      }
   }   
}

The next edition of my CS1/Java book is going to print soon. At the last minute, we decided to put the real estate of the inside covers to good use and include a “cheat sheet” with the most important Java control structures and libraries. Since it would be particularly embarrassing to have a typo here, I am hoping to enlist the aid of the community.

PDFs for the inside covers are here and here. If you spot a typo, please let me know in the blog comments. (But don't tell me about s.length—which should bes.length()—in the String Operations section. That is the only one I managed to spot.)

If you have other comments about what should be included/excluded in the cheat sheet, please let me know too. Your suggestions may not make it into this edition, but I do keep track for the next edition...which always comes sooner than I think. (But don't tell me that the switch statement must be included. Not only would it chew up a lot of real estate, but it is also something that one can do without in CS1. Students are supposed to learn computer science, not language minutiae.)

Thanks for your help! When the book goes into print, I'll update the cheat sheet links with the final versions so you can point the Java learners among your friends and family to them.

I just learned how to make Flash screencasts on my Linux system and deliver them (with GlassFish) on a server that the computer science department received as a donation (thanks Sun!!!).

Why am I doing this? My publisher wants me to develop screencasts for my books, and I thought it could be useful for my students if I record my lectures. I use a smart board for the lectures, and a screencast that records the “smart” pen and voice works tolerably well.

On Windows, you can use Camtasia for making screencasts, and it works very nicely out of the box. In Linux, it is definitely “roll your own”, but you get a bit more control over the process. Here are the details.

  • To record, I use XVidCap. (Many people like gtkRecordMyDesktop, but it produces Ogg files and when I tried it on a lecture, the sound was out of sync with the video after a while.) I record at 1024x768, 10 fps.
  • I use Gromit to write on the screen. This is very nifty—a hot key turns the mouse into annotation mode, and you can circle and annotate stuff. I attached a Bamboo tablet to make it even easier. (You can have the same effect in Compiz, but I found that Compiz occasionally overwhelmed the screen capture software, so I turned if off. On a Windows tablet PC, there is Ink Desktop. If you can install it. On my Windows 7 machine, the installer complained that my laptop vendor didn't pay enough clams to Microsoft...)
  • With the Bamboo tablet, Xournal is pretty nice for doing a quick graph 

  • Pulseaudio is both a problem and your friend. Tip #1. Usepadsp for programs that use the old-fashioned OSS protocol, such as XVidCap. Tip #2. If you switch microphones (I use different ones on my desk and in the classroom, but never the built-in laptop mike), use the Recording tab in Volume Control, click on the v button next to the recording stream, and select Move stream.
  • To splice out dead parts of video segments, I use Avidemux. For more advanced video editing, Linux doesn't seem to have good choices.
  • To convert MPEG to Flash, I use ffmpeg, followed by Yamdi to inject the metadata that are needed for seeking. Here is my conversion script: 
    in=$1
    out=${in/.mpeg/.flv}
    ffmpeg -i $* -f flv -r 10 -s 512x384 -qscale 5 -ar 44100 /tmp/${out}
    yamdi -i /tmp/${out} -o ${out}
    

Now on to serving the stuff to the public. YouTube isn't a solution for lectures—you can only upload 10 minutes worth of video. So, let's assume you have a server where someone else pays for the bandwidth :-)

  • You need to supply a player. (This came as a suprise to me. I thought that Flash did this automatically, but what do I know...) I used the free JW FLV player. Really, I would like to supply a JavaFX player, being a Java guy, but I didn't have the time to fuss with it. I looked atthis post, and the player worked fine on Linux, but it didn't do seeking. (If you move the slider forward, it doesn't jump to a later part of the movie until that part has actually been downloaded. This might be because the movie doesn't have the metadata, or because the player doesn't know how to seek. I'd like to know...) You really, really need seeking for lectures so students can quickly move past the dullest parts.
  • You need to install a script to support seeking on the server, as explained here. I used our donated Sun server on which I run Glassfish. The canonical choice seems to be xmoov-php, but I was in no mood to install Apache just to run a PHP script. (Could I have done that in Glassfish? If so, I'd like to know how.) Fortunately, I found a translation to a servlet here, and now I am all set. Here is a sample screencast for my next book, and here is a sample lecture