Desktop sharing using ssh tunnel

Share desktop of A to B with C as the hop. You’ll need access to your own server (C).

Execute on A: (assuming 192.168.1.100 is the ip of machine A)

% ssh -R 3390:192.168.1.100:3389 -l username myserver.com
log in and execute
ping 8.8.8.8 -i 5
to prevent the connection from timing out

Execute on B

% ssh -l username myserver.com -L 3391:localhost:3390

This means that you will be able to connect at localhost:3391 from your home computer and everything will be forwarded to myserver.com:3390.

Point your remote desktop connection to localhost:3391

cropped-DSC_0066-1024x477

Hibernate 4 Integrator pattern and Spring’s DI

Enabling @Autowired in Hibernate entities.

Create an EventListener that kicks in after a Hibernate LOAD event.  Using AutowireCapableBeanFactory to wire @Autowire’d dependencies.

package be.esus.core.infrastructure.hibernate;

import be.core.architecture.common.locator.SpringLocator;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;

// https://jira.spring.io/browse/SPR-9187
public class MyPostLoadEventListener implements PostLoadEventListener {
   @Override
   public void onPostLoad(PostLoadEvent postLoadEvent) {
      Object entity = postLoadEvent.getEntity();

      AutowireCapableBeanFactory spring = SpringLocator.getApplicationContext().getAutowireCapableBeanFactory();
      spring.autowireBean(entity);
   }
}

(SpringLocator is a simple custom class that is ApplicationContextAware in order to have static access to the ApplicationContext)

Register your new listener in Hibernate’s EventListenerRegistry.

package be.esus.core.infrastructure.hibernate;

import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.springframework.stereotype.Component;

@Component
public class MyEventListenerIntegrator implements Integrator {

   @Override
   public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory,
                         SessionFactoryServiceRegistry serviceRegistry) {
      EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );

      eventListenerRegistry.appendListeners(EventType.POST_LOAD, new MyPostLoadEventListener());
   }

   @Override
   public void integrate(MetadataImplementor metadataImplementor,
                         SessionFactoryImplementor sessionFactoryImplementor,
                         SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {

   }

   @Override
   public void disintegrate(SessionFactoryImplementor sessionFactoryImplementor,
                            SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {

   }
}

To register your SPI (see service loader), create
a (text) file called org.hibernate.integrator.spi.Integrator in META-INF/services/ and put the FQCN of your integrator in it:

be.esus.core.infrastructure.hibernate.MyEventListenerIntegrator

Adding a MouseListener to every row in a JTable

Here’s an code sample:

Main.java:

import javax.swing.table.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
 
public class Main extends JFrame {
   public Main() {
      super("TableModel Demonstration");
 
      // create our own custom TableModel
      WineTableModel wineModel = new WineTableModel();
      final JTable table = new JTable(wineModel);
 
      // add rows to our TableModel, each row is represented as a Wine object
      wineModel.addWine(new Wine("Chateau Meyney, St. Estephe", "1994", 18.75f, true));
      wineModel.addWine(new Wine("Chateau Montrose, St. Estephe", "1975", 54.25f, true));
      wineModel.addWine(new Wine("Chateau Gloria, St. Julien", "1993", 22.99f, false));
      wineModel.addWine(new Wine("Chateau Beychevelle, St. Julien", "1970", 61.63f, false));
      wineModel.addWine(new Wine("Chateau La Tour de Mons, Margeaux", "1975", 57.03f, true));
      wineModel.addWine(new Wine("Chateau Brane-Cantenac, Margeaux", "1978", 49.92f, false));
 
      // create the scroll pane and add the table to it. 
      JScrollPane scrollPane = new JScrollPane(table);
 
      // add the scroll pane to this window.
      getContentPane().add(scrollPane, BorderLayout.CENTER);
 
      table.addMouseListener(new MouseAdapter() {
         public void mouseReleased(MouseEvent me) {
            int row = table.rowAtPoint(me.getPoint());
            System.out.println("You clicked at row " + row);
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
   }
 
   public static void main(String[] args) {
      Main main = new Main();
      main.pack();
      main.setVisible(true);
   }
}
 
// a simple object that holds data about a particular wine
class Wine {
   private String  name;
   private String  vintage;
   private float   price;
   private boolean inStock;
 
   public Wine(String name, String vintage, float price, boolean inStock) {
      this.name = name;
      this.vintage = vintage;
      this.price = price;
      this.inStock = inStock;
   }
 
   public String getName()     { return name; }
   public String getVintage()  { return vintage; }
   public float  getPrice()    { return price; } 
   public boolean getInStock() { return inStock; }
 
   public String toString() { 
      return "[" + name + ", " + vintage + ", " + price + ", " + inStock + "]"; }
}
 
class WineTableModel extends AbstractTableModel {
   // holds the strings to be displayed in the column headers of our table
   final String[] columnNames = {"Name", "Vintage", "Price", "In stock?"};
 
   // holds the data types for all our columns
   final Class[] columnClasses = {String.class, String.class, Float.class, Boolean.class};
 
   // holds our data
   final Vector data = new Vector();
  
   // adds a row
   public void addWine(Wine w) {
      data.addElement(w);
      fireTableRowsInserted(data.size()-1, data.size()-1);
   }
 
   public int getColumnCount() {
      return columnNames.length;
   }
         
   public int getRowCount() {
      return data.size();
   }
 
   public String getColumnName(int col) {
      return columnNames[col];
   }
 
   public Class getColumnClass(int c) {
      return columnClasses1;
   }
 
   public Object getValueAt(int row, int col) {
      Wine wine = (Wine) data.elementAt(row);
      if (col == 0)      return wine.getName();
      else if (col == 1) return wine.getVintage();
      else if (col == 2) return new Float(wine.getPrice());
      else if (col == 3) return new Boolean(wine.getInStock());
      else return null;
   }
 
   public boolean isCellEditable(int row, int col) {
      return false;
   }
}

Determining when a page in a JEditorPane has finished loading

Add a PropertyChangeListener and listen for the property page.

   htmlPane.addPropertyChangeListener(new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
         if (!evt.getPropertyName().equals("page")) return;
         System.out.println("Page loaded!");
      }
   });

Main.java:

import javax.swing.text.html.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.net.*;
import java.awt.*;
import java.io.*;
 
public class Main extends JFrame
{
   // need to be final to allow the inner class to access it!
   final JTextField urlTextField = new JTextField();
   final JEditorPane htmlPane = new JEditorPane();
   JButton urlButton = new JButton("Go!");
 
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
 
   public Main() { 
      htmlPane.setEditable(false);
      urlTextField.setText("http://www.yahoo.com");
  
      urlButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            loadPage(urlTextField.getText());
         }
      });
 
      htmlPane.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent evt) {
            if (!evt.getPropertyName().equals("page")) return;
            System.out.println("Page loaded!");
         }
      });
 
      htmlPane.addHyperlinkListener(new HyperlinkListener() {
         public void hyperlinkUpdate (HyperlinkEvent event) {
            if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
               urlTextField.setText(event.getURL().toString());

               if (event instanceof HTMLFrameHyperlinkEvent) {
                  HTMLDocument doc = (HTMLDocument) htmlPane.getDocument();
                  doc.processHTMLFrameHyperlinkEvent ((HTMLFrameHyperlinkEvent) event);
               }
               else {
                  loadPage(urlTextField.getText());
               }
            }
         }
      });
 
      getContentPane().setLayout(new BorderLayout());
      JPanel topPanel = new JPanel(new BorderLayout());
      topPanel.add(BorderLayout.CENTER, urlTextField);
      topPanel.add(BorderLayout.EAST, urlButton);
 
      getContentPane().add(BorderLayout.NORTH, topPanel);
      getContentPane().add(BorderLayout.CENTER, new JScrollPane(htmlPane));
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
 
      setSize(400, 400);
   }
 
   public void loadPage(String url) {
      try {
         htmlPane.setPage(new URL(urlTextField.getText()));
      }
      catch(Exception e) {
         System.out.println(e);
      }
   }
}

Dynamically change the Look and Feel of a Swing application

Invoke UIManager.setLookAndFeel and provide it with the new Look and Feel class. Force components to reflect this new look by calling SwingUtilities.updateComponentTreeUI. All components in the tree of which you specify the parent component will be asked to use the new Look And Feel. Also do a call to frame.pack to ensure the window to be sized to fit the preferred size and layouts of its subcomponents. Here’s an example:

import javax.swing.table.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main implements ActionListener
{ 
   JFrame frame;
   
   public Main() {
      frame = new JFrame("Table one row selection demonstration"); 
      frame.addWindowListener( new WindowAdapter() { 
         public void windowClosing(WindowEvent e) { 
            System.exit(0); 
         } 
      }); 
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("Look and Feel");
      JMenuItem menuItem1 = new JMenuItem("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
      JMenuItem menuItem2 = new JMenuItem("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
      JMenuItem menuItem3 = new JMenuItem("javax.swing.plaf.metal.MetalLookAndFeel");
      menu.add(menuItem1);
      menu.add(menuItem2);
      menu.add(menuItem3);
      menuItem1.addActionListener(this);
      menuItem2.addActionListener(this);
      menuItem3.addActionListener(this);
      menuBar.add(menu);
      frame.setJMenuBar(menuBar);
 
      JTable table = new JTable(35, 3); 
  
      table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 
 
      frame.getContentPane().add(new JScrollPane(table)); 
 
      frame.pack(); 
      frame.show(); 
   } 
 
   public void actionPerformed(ActionEvent ae) {
      try {
         UIManager.setLookAndFeel(ae.getActionCommand());
         SwingUtilities.updateComponentTreeUI(frame);
         frame.pack();
      }
      catch(Exception e) {
         System.out.println(e);
      }
   }
 
   public static void main(String[] args) {
      Main main = new Main();
   }
}

Getting the attributes of an XML Node

Use a NamedNodeMap. The following example shows you how to print out all elements for the tag customer.

customer.xml (!!remove the space between ? and xml):

<? xml version="1.0" encoding="UTF-8"?>
<customers>
   <customer id="C12345" type="prio1">
      <name>Joris Van den Bogaert</name>
      <address>
         <addressline>Handelskaai 3</addressline>
         <zip>1000</zip>
         <location>Brussels</location>
         <country>BELGIUM</country>
      </address>
   </customer>
</customers>

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
 
import java.io.*;
   
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File("customer.xml"));
 
         NodeList nodeList = doc.getElementsByTagName("customer");
         Node node = nodeList.item(0);
  
         NamedNodeMap attributes = node.getAttributes();
         for (int i=0; i<attributes.getLength(); i++) {
            Node attribute = attributes.item(i);
            System.out.println(attribute.getNodeName() + " = " + attribute.getNodeValue());
         }
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

outputs:

id = C12345
type = prio1

To get a specific attribute, you can use the method getNamedItem.

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
 
import java.io.*;
   
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File("customer.xml"));
 
         NodeList nodeList = doc.getElementsByTagName("customer");
         Node node = nodeList.item(0);
  
         NamedNodeMap attributes = node.getAttributes();
 
         Node custId = attributes.getNamedItem("id");
         Node custType = attributes.getNamedItem("type");
         System.out.println("id   = " + custId.getNodeValue());
         System.out.println("type = " + custType.getNodeValue());
         }
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

Get the IP address of the client connecting to a Servlet

Call the method getRemoteAddr on the HttpServletRequest instance.

MainServlet.java:

import javax.servlet.http.*;
import javax.servlet.*;
 
import java.io.*;
 
public class MainServlet extends HttpServlet
{
   public void doGet (HttpServletRequest request,
                      HttpServletResponse response)
      throws ServletException, IOException
   {
      String ip = request.getRemoteAddr();
      
      response.setContentType("text/html");
      PrintWriter out = response.getWriter();
 
      out.println("<html><body>");
      out.println(ip);
      out.println("</body></html>");
      out.close();
   }
}

Saving binary data (eg. images) in a database table

As an example, I created the following table:

mysql> create table images (imageid int(10) not null auto_increment, 
name varchar(30), data blob, length int(6), primary key(imageid));
Query OK, 0 rows affected (0.12 sec)
 
mysql> desc images;
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| imageid | int(10)     |      | PRI | NULL    | auto_increment |
| name    | varchar(30) | YES  |     | NULL    |                |
| length  | int(6)      | YES  |     | NULL    |                |
| data    | blob        | YES  |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+

Main.java:

import java.util.*;
import java.text.*;
import java.sql.*;
import java.io.*;  
 
public class Main {
   public static void main(String []args) throws Exception {
      try {
         Class.forName("org.gjt.mm.mysql.Driver").newInstance();
         Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.0.1/esus", 
                                                       "joris",
                                                       "mypass");
 
         File[] files = new File(".").listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
               if (name.endsWith(".gif")) {
                  return true;
               }
               return false;
            }
         });
 
         for (int i=0; i<files.length; i++) {
            FileInputStream fis=new FileInputStream(files[i]);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte buf[]=new byte[1024];
            int length=-1;
            while((length=fis.read(buf))!=-1) {
               baos.write(buf,0,length);
            }
 
            PreparedStatement insertStmt = conn.prepareStatement(
                                          "INSERT INTO images (name, length, data) " +
                                          "VALUES (?, ?, ?)");
            insertStmt.setString(1, files[i].getName());
            insertStmt.setInt(2, (int) files[i].length());
            insertStmt.setBytes(3, baos.toByteArray());
            insertStmt.execute();
 
            fis.close();
            baos.close();
        }
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

Getting a list of environment variables

You can’t anymore. There used to be a method called getenv(String) in java.lang.System but it’s been deprecated since
1.1.8. The only thing you can do now is to use the -D properties flag on the command line when you start your program.

java -Dproperty=value myapp.class

Where property is the name of the property and value is the value you want to as sign it.

You can then retrieve the value of the property using:

getProperty("property");

If you still want to allow the user to set environment variables you can always use them as the value for the property in the startup batch file or shell script like this:

Windows:

   SET ENVVVAR=value
   java -Dproperty=%ENV_VAR% myapp.class

Unix:

   ENV_VAR=value
   export ENV_VAR
   java -Dproperty=$ENV_VAR myapp.class

Performance gain of using NIO channels as opposed to regular streams for doing file I/O

To test things out, I wrote a couple small Java programs to copy a file:

CopyFile1.java: uses the old approach using BufferedInput/BufferedOutputStreams with the default buffer size of 2048 bytes
CopyFile2.java: uses the NIO libraries with different buffer sizes
CopyFile3.java: uses the NIO FileChannel method transferTo

CopyFile1.java uses BufferedInputStream and BufferedOutputStream. If you look at the source code for these files, the default buffer is an array of 2048 bytes. The first version of the NIO CopyFile2 program is also set to use an internal buffer of 2048 bytes. Other tests have been done with larger buffer sizes. As expected, the more buffer space allocated, the higher the performance (at a cost of more memory usage).

The result of copying the Java SDK file j2sdk-1_4_0-win.exe(37Meg) using JDK1.2.2, JDK1.3 and JDK1.4 on a Win2000/450Mhz machine is plotted here:


(All numbers are seconds)

CopyFile1.java:

import java.io.*;
 
public class CopyFile1
{
   public static void main(String []args) throws IOException {
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile1 source dest");
         System.exit(1);
      }
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
      BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));
 
      int k;
      while ((k = bis.read()) != -1) {
         bos.write(k);
      }
   
      bis.close();
      bos.close();
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }
}

CopyFile2.java:

import java.nio.*;
import java.nio.channels.*;
import java.io.*;
 
public class CopyFile2
{
   public static void main(String []args) throws IOException {
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile2 source dest");
         System.exit(1);
      }
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      FileInputStream fis = new FileInputStream(source);
      FileOutputStream fos = new FileOutputStream(dest);
      
      FileChannel channelIn = fis.getChannel();
      FileChannel channelOut = fos.getChannel();
 
      ByteBuffer buffer = ByteBuffer.allocateDirect(2048); 
 
      int n = channelIn.read(buffer);
      while (n > -1) {
         buffer.flip();
         channelOut.write(buffer);
         buffer.clear();
  
         n = channelIn.read(buffer);
      }      
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }
}

CopyFile3.java:

import java.nio.*;    
import java.nio.channels.*;    
import java.io.*;        
 
public class CopyFile3 
{        
   public static void main(String args[]) throws IOException {                
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile3 source dest");
         System.exit(1);
      }             
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      FileInputStream fis = new FileInputStream(source);            
      FileOutputStream fos = new FileOutputStream(dest);            
      
      FileChannel channelIn = fis.getChannel();
      FileChannel channelOut = fos.getChannel();
 
      channelIn.transferTo(0, channelIn.size(), channelOut);                
 
      channelIn.close();            
      channelOut.close();            
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }    
}