Sunday, September 20, 2009

Copy image of applet to clipboard

Apparently this can only be done if you have a signed applet, because otherwise the Security Manager blocks the call to Clipboard.setContents. There are several steps to getting this to work:

First we add a PopupMenu to the applet's init() method:

popup = new PopupMenu();
popup.add("Copy to clipboard");
popup.addActionListener( new PopupActionListener(this) );
addMouseListener( new RightMouseListener(this) );
add( popup );

Here we create a popup menu with a single entry that says "Copy to Clipboard". There's also a listener for the right mouse button, which for historical reasons is button number 3:

public class RightMouseListener extends MouseAdapter
{
 Monitor applet;
 public RightMouseListener( Monitor applet )
 {
  this.applet = applet;
 }
 public void mouseClicked( MouseEvent e )
 {
  int button = e.getButton();
  if ( button==MouseEvent.BUTTON3 )
  {
   applet.popup.show( this.applet, e.getX(), e.getY() );
  }
 }
}

Pretty simple. This just shows the popup menu whenever the user clicks the right mouse button. Here's the PopupActionListener class, which fires when any item is selected:

public class PopupActionListener implements ActionListener
{
 Monitor applet;
 PopupActionListener( Monitor applet )
 {
  this.applet = applet;
 }
 public void actionPerformed( ActionEvent e )
 {
  BufferedImage image = new BufferedImage( applet.getWidth(), 
   applet.getHeight(), BufferedImage.TYPE_INT_RGB );
  Graphics g = image.getGraphics();
  applet.paint( g );
  Clipboard clipboard =
   Toolkit.getDefaultToolkit().getSystemClipboard();
  ImageSelection imageSelection = new ImageSelection( image );
                clipboard.setContents( imageSelection, null );
 }
 class ImageSelection extends TransferHandler implements Transferable 
 {
  private static final long serialVersionUID = 1L;
  Image image;
  ImageSelection( Image image )
  {
   this.image = image;
  }
  public Object getTransferData( DataFlavor flavor ) 
   throws UnsupportedFlavorException, IOException
  {
   return image;
  }
  public DataFlavor[] getTransferDataFlavors() 
  {
   DataFlavor[] flavors = new DataFlavor[1];
   flavors[0] = DataFlavor.imageFlavor;
   return flavors;
  }
  public boolean isDataFlavorSupported( DataFlavor flavor ) 
  {
   return flavor == DataFlavor.imageFlavor;
  }
 }
}

Here's where it gets slightly interesting. We create a buffered image the same size as the Applet. Then we get the image's Graphics object, and use it to call the Applet's paint method. Then we just call setContents on the system clipboard. The ImageSelection class is required boilerplate. We just subclass TransferHandler.

Now paste the image into a graphics program like GIMP and you have your image. Et voilĂ !

Monday, September 14, 2009

Roundtripping Form Parameters

So you have a form, and each of the fields has a name and a value. In HTML when you press a submit button or call Javascript to submit the form all the names and values get POSTed or added to the URL as GET parameters. In a JSP things are more complex. You are supposed to define a `bean' that gets attached to the JSP file so you can access the parameters that way:

<jsp:useBean id="user" class="au.edu.qut.ddos.monitor.AppletData" scope="session"/>

This creates the bean "user" and associates it with the session. When the form is reloaded after a submit, the parameters are available and can be used to set the form elements. To copy them into the bean you can say:

<jsp:setProperty name="user" property="*"/>

This copies all the passed-in parameters into the bean "user", provided the bean has correctly named get and set methods for them. Now, to set the actual elements of the form we use the JSP EL or "Expression Language":

<mytag:namedlist name="intf" value="${user.intfList}" selected="${user.intf}"/>

I should explain that the "namedlist" tag creates a <select> element and populates it from the comma-separated list supplied as the "value". The EL expression "${user.intf}" sets the selected property of the tag to the value of the intf instance variable in the AppletInfo class. Each such property needs a get and a set method for this to work: in this case the getIntf and setIntf methods.

Meanwhile, in the GenericPortlet class we define a method processAction:

    public void processAction(ActionRequest request, ActionResponse response) 
        throws PortletException, java.io.IOException
    {
        Enumeration names = request.getParameterNames();
        while ( names.hasMoreElements() )
        {
            String param = names.nextElement();
            String value = request.getParameter(param);
            response.setRenderParameter( param, value );
        }
    }

All this does is read the passed-in parameter names and their values and copy them to the response object. We can of course change these before doing so. They then appear in the JSP and get copied into the bean thanks to the <jsp:setProperty id="user" property="*"/> statement.

Note that the portlet code knows nothing of beans. It just sees parameters.

Monday, September 7, 2009

Portlet Edit View with a single dropdown menu

Getting edit view (when you select "Edit" in the portlet title bar) to display dynamically calculated information can be done via a taglib. I'm going to create a tag called snmphosts using a manual method. There is probably a way to define this in Netbeans using a standard template.

First, create a taglib.tld (it's got to be called this I think).

<?xml version="1.0" encoding="ISO-8859-1"?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
  <tlib-version>1.0</tlib-version>
  <short-name>snmp-hosts</short-name>
  <description>
    A tag to display a set of snmp-reachable hosts as a dropdown menu.
  </description>
  <!-- display a set of reachable hosts as a HTML select element -->
  <tag>
   <name>snmphosts</name>
   <tag-class>examples.taglibs.SNMPHostList</tag-class>
    <attribute>
     <name>intf</name>
     <required>yes</required>
    </attribute>
   <body-content>empty</body-content>
  </tag>
</taglib>

What this specifies is the name of the tag, "snmphosts" and associates it with a Java class in the package examples.tablibs. I also declared an attribute, which is an argument to the tag that is required whenever we use it in HTML: the name of the interface to probe. In simple cases though, you may not need to define an attribute. Here is the SNMPHostList.java file that does the work:

package examples.taglibs;
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
public class SNMPHostList extends TagSupport
{
 private static final long serialVersionUID = 1L;
 String intf;
 public int doStartTag() throws JspException
 {
  JspWriter out = pageContext.getOut();
  try
  {
   out.println( "<select>" );
   String[] hosts = inetaddr.getSubnetHosts( intf );
   for ( int i=0;i<hosts.length;i++ )
   {
    out.print("<option>");
    out.println( hosts[i] );
    out.print("</option>");
   }
   out.println("</select>");
  }
  catch ( Exception ioe )
  {
   throw new JspException( ioe );
  }
  return SKIP_BODY;
 }
 public int doEndTag() throws JspException
 {
  return EVAL_PAGE;
 }
 /**
  * Get the interface name
  * @return intf the name of the interface
  */
 public String getIntf()
 {
  return intf;
 }
 /**
  * Set the interface name
  * @param intf the name of the interface in the scenario, 
  * e.g. "eth1"
  */
 public void setIntf( String intf )
 {
  this.intf = intf;
 }
}

This is mostly boilerplate stuff from the TagSupport class (check the Java API documentation). By providing the setIntf and getIntf methods the JSP engine will automatically set the intf instance var for you when it is provided via an attribute. You could equally call them setBanana and getBanana if you had a instance var called "banana". For empty tags as in this case you just do the start tag and "skip" the body. That's what the return values are for. doEndTag hence does nothing. In doStartTag all we do is write out a HTML <select> element with embedded <option>s. We get the options from the inetaddr class which computes a list of available snmp (or pingable) hosts on the network.

To build the library all you do is compile the SNMPHostList.java file using appropriate libraries on the classpath, which you can get from Pluto: I used servlet-api.jar, jsp-api.jar and portlet-api_2.0_spec-1.0.jar. Then place the .class file in a folder called anything, e.g. "hello". Also in that folder create a META-INF directory and copy the taglib.tld file into it. Then cd into hello and make a jar out of it:

jar cf ../hello.jar .

Just drop the taglib into the lib folder inside a WEB-INF folder inside a web application (like a portlet) and the tag should now be available.

Using the tag

You should already have an edit.jsp file inside your portlet. Change it so that it calls the tag:

<%@ taglib uri="/WEB-INF/lib/hello.jar" prefix="mytag" %>
<html>
<body>
<mytag:snmphosts>
 <jsp:attribute name="intf">eth1</jsp:attribute>
</mytag:snmphosts>
</body>
</html>

"mytag" is just a namespece abbreviation and can be anything. The key is that we define mytag to BE hello.jar so when we invoke it using <mytag:snmphosts> the java class file gets called to produce its output. The attribute is passed in using the ugly XSLT-type syntax because it is more flexible, but you can also use a direct attribute in simple cases.

When you select Edit mode now in the portlet you should get a dropdown list of computed hosts.

Sunday, September 6, 2009

Deploying Portlets (to Pluto) with Netbeans

Continuing on with the topic of my previous post, I have set up Netbeans to deploy the portlet's WAR file directly to the Pluto portal implementation without having to copy a file to the 'webapps' folder manually.

You'll need the bundled version of Pluto, or at least have Pluto installed on top of Apache Tomcat, and the plugin for Netbeans that supports Tomcat as an application server. I won't go through the process of setting up Tomcat as a server in netbeans, suffice to say it's very straight forward once you have installed the plugin (Tools -> Plugins -> Tomcat, install). Configure you're previously created portlet project to use the Tomcat server as a deployment point and you're done.

A few side points:
The default Context Path (url) is '/Hello'. If you want something more meaningful, just go to the properties for your project, and in the 'Run' section, change the context path to something better, eg NetworkStatusPortlet

You'll still need to configure the layout and page for your portlet in Pluto. So go into Pluto admin, and find you're recently deployed portlet and add it to an existing page or a new one.

Thursday, September 3, 2009

Creating custom tags in EDIT view on Pluto

Imagine you have a portlet, and you want to have an EDIT view that displays a form, and on the form you want some precalculated content, such as a dropdown list of available hosts. But how would you do it? You could compute a <select> element and fill it with available hosts by using some Java, but that would clutter up the JSP file. But with a custom tag library you could just do something like:

<mytag:hostlist subnet="192.168.200.0"/>

And that would produce a list of hosts that respond to PING or HTTP or SNMP on the specified subnet. Now how do you do that?

Define a taglib

As in the last post, these are manual instructions. A taglib is just a jar containing at least one .tld file in META-INF. You need a tld file to link the classes in the taglib to their names. Here's an example:

<?xml version="1.0" encoding="ISO-8859-1"?>
<taglib xmlns="htp://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
  <tlib-version>1.0</tlib-version>
  <short-name>hello</short-name>
  <description>
    An example Hello World tag.
  </description>
  <tag>
    <name>hello</name>
    <tag-class>examples.taglibs.HelloWorldTag</tag-class>
    <body-content>empty</body-content>
  </tag>
</taglib>

This can go into a directory META-INF inside a directory tld:

  • tld
    • META-INF
      • hello.tld

Now it's time to build the tag class:

package examples.taglibs;
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;
public class HelloWorldTag extends TagSupport
{
 private static final long serialVersionUID = 1L;
 public int doStartTag() throws JspException
 {
  JspWriter out = pageContext.getOut();
  try
  {
   out.println( "<h1>Hello World!</h1>");
  }
  catch ( IOException ioe )
  {
   throw new JspException( ioe );
  }
  return SKIP_BODY;
 }
 public int doEndTag() throws JspException
 {
  return EVAL_PAGE;
 }
}

This doesn't yet generate a <select> element, but you get the idea how to do it. Compile the java thus:

javac lib/jsp-api.jar tld/src/examples/taglibs/*.java -d tld

which puts HelloWorldTag.class into tld/examples/taglibs, surprisingly. Then make a jar of the taglib, by cd-ing into the tld directory:

jar cf ../hello.jar META-INF examples

Put your hello.jar taglib into the WEB-INF/lib directory of your web application and you can then call it up from edit.jsp:

<%@ taglib uri="/WEB-INF/lib/hello.jar" prefix="mytag" %>
<html>
<body>
<mytag:hello/>
</body>
</html>

That gives you <h1>Hello world!</h1> in EDIT mode. To get a dropdown list just modify the java code to generate a list and enclose it in <select> tags.

Wednesday, September 2, 2009

Creating Portlets (for Pluto) using Netbeans

Upon my inclusion in this project, I decided to use Netbeans for all my development. I'd had more experience using it than Eclipse, and it seemed to have the right level of simplicity and functionality for what I needed. However, it had no built in project templates for creating portlets. So following the instructions Desmond put on this blog for creating the hello world portlet, I went about using Netbeans to create it.

Firstly create a new project using the Java Web -> Web Application template. Give it a a name in the next screen, keep clicking next leaving most of the settings default. You can delete or modify the created index.jsp under the Web Pages section of the project. Also in this section, in the WEB-INF folder, open web.xml and copy in the information from the tutorial below. Create a new xml file in WEB-INF and call it portlet.xml and copy in the code from below for that file. Right click on the Web Pages section and add a new folder calling it META-INF. Create a new xml file underneath that calling it context.xml or hello.xml and copy in the related code from below as well.

To make this project compile we need into include the portlet-api jar file specified below. You can do this by right clicking on the project, selecting properties and going to the libraries section, and adding the portlet-api jar file to the list of included libraries. However this actually packages the library with the portlet in the WAR file, which we don't want because it will conflict with the already inlcuded library in whatever Portal system your using. So once you've selected the jar file to include, you need to uncheck 'Package' for that libary.

Once that's done you can build the project (don't try and deploy), this will produce a war file in the 'dist' directory of the project, which you can then copy into the webapps folder of your portal driver (Pluto in my case).