lunes, 12 noviembre 2007

Reading UTF-8 encoded documents in java

Reading the contents of a file in Java is a very straight forward operation. The java tutorial explains completely how you can find your way to read different types of streams.

However when you read an UTF-8 encoded file your fight will start. Most of the UTF-8 and UTF-16 encoded files contain a character at the beginning called BOM (byte-order mark). The BOM consists of a character  (U+FEFF) at the beginning of the stream used to define the byte order and the encoding of the stream. UTF encoded files may or may not containg the BOM.

The problem with Java comes when you read a unicode file with a byte-order mark. Java doesn't detect the BOM by itself so when you represent the data contained in the file, the BOM contaminates it. There is an open BUG in sun's bug database with the explanation and some workaround users have made.

The solution is as simple as as reading the first bytes of an UTF encoded file and check if those a are a BOM or not. If they are, just remove them and continue reading the file. This is not so complicated because there are not so many types of BOM (5) and they are easy to identify.

Bytes Encoding Form
00 00 FE FF UTF-32, big-endian
FF FE 00 00 UTF-32, little-endian
FE FF UTF-16, big-endian
FF FE UTF-16, little-endian
EF BB BF UTF-8

When one of this characters is identified you just have to remove it so your program can interpret the file as it should be. A user has contributed with two helper classes that can do the job for you.

Related links:

Technorati Tags:

Posted by admin at 9:55 AM in Java

jueves, 13 septiembre 2007

Viewing and storing images from an IP Camera

So you bought an IP camera and would like to store/see images from the camera using java. Recently I bought a couple of IP Cameras for testing purposes. I noticed that each IP camera has different surveillance tools and web interfaces. But most of them have in common that you can access the actual picture by entering an url in your browser.

In this post I'll show you how to see that image and store it using a very simple jav application. The camera I'll use for the test is a LinkSys WVC200 "Wireless PTZ Internet Camera with Audio". This is the cheapest wireless IPcam I found with at least
some decent features.

WVC200

This camera has a nice web interface but for visualization purposes you will need to be sitting in front of a windows desktop. This camera as many others uses an activeX control to show/control the image. The thing is that LinkSys is kind enough to offer the camera's Firmware source code.

If you analyze the source code you can find some clues to get the URL where the static image is served (there's an url for video too ASF format, with some time you can develop an app to store and play the video). In the case of this camera is "http://CAMERAIP/img/snapshot.cgi?size=640x480".

With this information we can build an application to grab the image and show/store the image. If you have another type of camera, you can adapt the program by specifying the url.

>try {
    /* Build a new URL specifying the path to where the image
    * is served */
    URL url = new URL ("http://192.168.10.80/img/snapshot.cgi?size=640x480");
    /*String with the user and password to access the camera interface
    *(userName and password that you would enter in the browser*/
    String userPassword =  "USER:PASSWORD";
    /* We must encode with Base64 to supply it with the header.*/
    String encoding = new Base64Encoder(userPassword).processString();
    /*Open the connection*/
    URLConnection uc = url.openConnection();
    /* Specify the authorization*/
    uc.setRequestProperty ("Authorization", "Basic " + encoding);
    /* Load a copy of the image into memmory */
    BufferedImage img = ImageIO.read(uc.getInputStream());
    /* Show the image in a JLabel */
    jLImagen.setIcon(new ImageIcon(img));
    /* Store the image in the specified path*/
    ImageIO.write(img, "jpg", new File("pathToFile"));
} catch (MalformedURLException ex) {
    ex.printStackTrace();
} catch (IOException ex) {
    ex.printStackTrace();
}

Extending this simple application or adding some functionality can bring a very good surveillance application. If you analyze most commercial surveillance applications to use with different ipCameras you'll notice that although they are very expensive the core of the application is similar to the 10 lines of code above.

Technorati Tags:

Posted by admin at 12:19 PM in Java

viernes, 3 agosto 2007

Updated: Displaying a jTable inside another jTable // JTable cellRenderer

After some users asking for answers in my past post, I updated the code of the embedded JTable to make it less buggy and more stable.

This is the "new" code:

/* We initialize the Objects where we'll store our data */
/* First an array Object which will be our main table */
Object[][] data = null;
/* We create an Array String to hold the name of the main table columns In this example case we are going to store a contact name, his email address(es) and his phone numer(s) We're also going to store the creation date.*/
String[] columns = {"Name", "E-Mail","Phone","Creation Date"};
/* First thing is  to populate our data object with some example values*/
    public void populateData(){
        /* Two contacts*/
        data = new Object[3][columns.length];
        data[0][0] = "Peter";
        String[] emails = {"peter@yahoo.com", "strange@name.com"};
        data[0][1] = emails;
        String[] phones = {"555 35 25 65" , "555 35 24 63"};
        data[0][2] = phones;
        data[0][3] = new Date();
        data[1][0] = "Jackson";
        data[1][1] = "Jack@hotmail.com";
        String[] phones2 = {"555 35 24 33" , "555 11 88 88", "332 55 25 34"};
        data[1][2] = phones2;
        data[1][3] = new Date();
        data[2][0] = "Robert";
        data[2][1] = "rob@hotmail.com";
        data[2][2] = "555 28 95 81";
        data[2][3] = new Date();
        /* AS you can see, we've stored two contacts one with two e-mail
         accounts and two phone numbers, and another member with three phone
         numbers*/
    }
    /* Next we create our table models */
    public void createModel(){
        /* First we create the main model
         We overide the AbstractTableModel necessary methods*/
        AbstractTableModel  modelo = new AbstractTableModel() {
          public String getColumnName(int col) {
                return columns[col].toString();
            }
          public Class getColumnClass(int col) {
              if(getRowCount() <1)return null;
            return data[0][col].getClass();
          }
          public int getRowCount() { return data.length; }
          public int getColumnCount() { return columns.length;}
          public Object getValueAt(int row, int col) {
                return data[row][col];
          }
          public boolean isCellEditable(int row, int col){ return true; }
          public void setValueAt(Object value, int row, int col) {
            data[row][col] =  value;
            fireTableCellUpdated(row, col);
          }};
          /* We apply the model to the main jTable */
          jTableData.setModel(modelo);
          /* We create a cell Renderer to display the data of the multivalue
           fields*/
          TableCellRenderer jTableCellRenderer = new TableCellRenderer() {
              /* Magic Happens */
              public Component getTableCellRendererComponent(JTable table,
                      Object value, boolean isSelected, boolean hasFocus,
                      int row, int column) {
                  /* If what we're displaying isn't an array of values we
                   return the normal renderer*/
                    if(!value.getClass().isArray()){
                       return table.getDefaultRenderer( 
                               value.getClass()).getTableCellRendererComponent(
                               table, value, isSelected, hasFocus,row, column);
                    }
                    else{
                        final Object[] passed = (Object[])value;             
                        /* We create the table that will hold the multivalue
                         *fields and that will be embedded in the main table */
                        JTable embedded = new JTable(
                            new AbstractTableModel() {
                                public int getColumnCount() {
                                    return 1;
                                }
                                public int getRowCount() {
                                    return passed.length;
                                }
                                public Object getValueAt(int rowIndex, int columnIndex) {
                                    return passed[rowIndex];
                                }
                                public boolean isCellEditable(int row, int col){ return true; }
                        });
                         
                        if(isSelected){
                            embedded.setBackground(jTableData.getSelectionBackground());
                            embedded.setForeground(jTableData.getSelectionForeground());
                        }
                        if(hasFocus){
                            embedded.setRowSelectionInterval(0,1);
                        }
                        /* If this is what you plan to enable mouseClick detection,
                            in your table, IT WONT WORK. Have a look at TableCellEditor.*/
                        embedded.addMouseListener(new MouseAdapter() {
                            public void mouseClicked(java.awt.event.MouseEvent evt) {
                                System.out.println("PEPE");
                            }
                        });
                        
                        setPreferredSize(embedded.getPreferredSize());
                         if(getPreferredSize().height != table.getRowHeight(row))
                            {
                                table.setRowHeight(row, getPreferredSize().height);
                            }

                        return embedded;
                    }
              }
          };
          /* Finally we apply the new cellRenderer to the whole table */
          TableColumnModel tcm = jTableData.getColumnModel();
          for(int it = 0; it < tcm.getColumnCount(); it++){
              tcm.getColumn(it).setCellRenderer(jTableCellRenderer);
             // tcm.getColumn(it).setCellEditor(jTableCellEditor);
          }
          /*Note: if we need to edit the values inside the embedded jtable
           * we will need to create a TableCellEditor too. */
          
    }

JTable with another embedded JTable

In the above image you can see the result.

Technorati Tags:

Posted by admin at 8:41 AM in Java

lunes, 16 julio 2007

Getting started with JasperReports // Printing reports from your java app (Part III)

In the past 2 entries (Part I and Part II) we learnt how to develop a basic report and how to fill it with data from a database with a jdbc connector. Now we will learn how to call a report from within a Java application and how to set some basic parameters.

The most important thing when running your reports from within a java application is to have all the necessary jar libraries available from your classpath. The basic ones for running the sample report will be commons-logging-*.jar, commons-collections-*.jar, jasperrerports-*.jar and yourJDBCconnector.jar. All of them (except the jdbc connector) can be found in the iReport ./lib directory.

Next thing you'll need is a compiled version of your report. This you can find in the same folder you saved your report when you developed it in iReport. It will have the same name as the report source but the extension will be .jasper.

Now we are ready to call our report from Java. The most important class now is JasperPrint. The basics for this class are to specify a report and a datasource to fill it. In the following lines you'll find the code to run our report. The example simply creates a postgresql datasource and gives the path to the compiled jasper file. Then with some simple parameters it specifies the number of copies and tells the program to print the report.

try {
            /* Number of copies to print */
            int numberOfCopies = 1;
            /* Create the jdbc datasource
             * you'll have to change this code to your database vendor specific 
             * jdbc */
            Class.forName("org.postgresql.Driver");
            Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres?user=postgres&password=PASSWORD1");
            ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM pg_tables ORDER BY 1");
            /* Create a Jasper DataSource */
            JRDataSource ds = new JRResultSetDataSource(rs);
            /* Fill the report with the new datasource */
            JasperPrint print = JasperFillManager.fillReport("C:\\Documents and Settings\\Administrador\\Mis documentos\\test.jasper", new HashMap(), 
                ds);
            PrintRequestAttributeSet printRequestAttributeSet = new HashPrintRequestAttributeSet();
            /* Set the number of copies */
            printRequestAttributeSet.add(new Copies(numberOfCopies));
            printRequestAttributeSet.add(new JobName("Job Name", null));
            
            net.sf.jasperreports.engine.export.JRPrintServiceExporter exporter;
            exporter = new net.sf.jasperreports.engine.export.JRPrintServiceExporter();  
            exporter.setParameter( JRExporterParameter.JASPER_PRINT, print);
            exporter.setParameter( JRPrintServiceExporterParameter.PRINT_REQUEST_ATTRIBUTE_SET, printRequestAttributeSet);
            exporter.setParameter( JRPrintServiceExporterParameter.DISPLAY_PAGE_DIALOG, Boolean.FALSE);
            exporter.setParameter( JRPrintServiceExporterParameter.DISPLAY_PRINT_DIALOG, Boolean.TRUE);
            exporter.exportReport();
            rs.close();
            conn.close();
            rs = null;
            conn = null;
            exporter = null;
            print =null;
            printRequestAttributeSet = null;
        } catch (SQLException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        } catch (JRException ex) {
            ex.printStackTrace();
        }

Technorati Tags:

Posted by admin at 7:59 AM in Java

viernes, 29 junio 2007

Getting started with JasperReports // JDBC connections (Part II)

This is the second part of a series of articles to get people started with JasperReports. In the second part I'll explain how to access your database to run simple queries and show them in a very simple report created with iReport.

The first thing we need to do to get moving is to have iReport ready. So if you haven't got it installed do so. Next step is to have the database driver in your iReport library folder. This means that you will need a jdbc jar packaged driver copied to the ./lib/ directory of iReport's base folder. This step is really important not doing so will not allow you to connect to the database. Most databases provide their own jdbc driver, there are many tutorials and references that speak about jdbc.

Now is the time to configure access to your database. You have to go to the menu "Data -> Connections/Datasources". Then you must click the "New" button.

iReport Connection Dialog

When you get this dialog, the first thing to do is to give a name to the connection "Name". Next is to specify the driver to connect to your database.Then you'll have to modify the JDBC URL to access your database (You can use the wizard to do this too). Finally you must specify the username and password with permission to get access to the database. It's convenient to test the connection before saving.

With your connection ready, is time to query the database. In my case I will be using PostgreSQL and I will build a simple query to get the database table names. For this you must go to the menu "Data -> Report Query".

iReport Data -> Report Query

When you insert your SQL query, in my case "SELECT * FROM pg_tables ORDER BY 1" iReport automatically gets the metadata for your query and stores them as report fields so you can use them during the development of your report.

Finally with the retrieved report fields we can now create our report. This is the result:

iReport final Result

Technorati Tags:

Posted by admin at 9:05 AM in Java

martes, 19 junio 2007

Getting started with JasperReports // Reporting in Java (Part I)

This is the first of a series of articles to get you started with JasperReports. In first place, JasperReports is one of Java's reporting engines. It's very powerful and has lots of features that makes it comparable to commercial reporting solutions such as Crystal Reports.

The first thing you need to do to start using this great peace of software is go to the project page and download it (wait). In the project page there is some documentation that will help you getting started.

You must know that JasperReports is a reporting engine that integrates many capabilities. Reports are developed using JasperReports own markup language (jrxml). You can define datasources to access databases, report variables, fields and parameters. All of these can then be used to populate and display data in your report. Once the report is done you must compile it. Compiled reports can then be processed by JasperReport's engine to be output in different formats (html, rtf, pdf, xls, printer...)

Reports can be developed either by hand, editing the report's source in an editor (jrxml) or with an ide (GUI). There are several GUI editors for JasperReports there even is a NetBeans plugin (still beta). The one I use and in my opinion the best is iReport. Downloading iReport will be the easiest way to get started with jasper. There is some documentation available on the project's page too. There you will find very good tutorials and quick start articles. The iReport package includes every library/jar you need, so its not necessary to download JasperReports package.

iReport Main Frame

Now that you have iReport installed its time to practice report development (learn about bands, groups, fields, variables, parameters, datasources... In further articles I will show you some of the advanced capabilities of these components). If you just want to build reports for data stored in a database (JDBC accessible) you won't need anything else, just iReport, so don'T worry about integrating jasperreports with your application yet. By now you can get used to run your reports by using the menu option “Build -> Run Report”

Technorati Tags:

Posted by admin at 8:45 AM in Java

jueves, 7 junio 2007

Replacing Apostrophes from Strings // Cleaning String to pass them as SQL statements

Such a simple thing as replacing an apostrophe with an escape character from a string sometimes can become a very tedious process, more if you're using String's replaceAll(...) function. Replacing apostrophes from Strings may be very useful when creating Statements to pass to an SQL database, preventing SQL injection. Many may say that using PreparedStatements is easier and safer, but in many occasions you can't use prepared statements to accomplish what you need.

The problem with the replaceAll function comes because of the arguments the function expects. In first place you must pass a regular expression that suits what you want to replace. Secondly, the function expects another regular expression with the String's replacement. In postgreSQL when passing apostrophes and other special characters as text, you must use the backslash as an escape character, just like in java. So if you want to insert "John's hand" as an argument to an Insert statement you must write something such as 'John\'s hand'.

If you refer to Pattern javadoc you can read:

The backslash character ('\') serves to introduce escaped constructs, as defined in the table above, as well as to quote characters that otherwise would be interpreted as unescaped constructs. Thus the expression \\ matches a single backslash and \{ matches a left brace.

Here is the answer to the problem. When replacing ' for \' you need to place 4 backslashes before the apostrophe.

String replacedString = "John's hand";
replacedString.replaceAll("'","\\\\'");

Technorati Tags:

Posted by admin at 8:25 AM in Java

miércoles, 6 junio 2007

Detecting Tab Key Pressed Event in JTextField 's // Event.VK_TAB KeyPressed

Adding a KeyListener to a JTextField to detect KeyPressed events is pretty straight forward. Buy maybe you have encountered some problems when trying to detect special key such as TAB's. This issue is due to LowLevel keyEvents captured by Swing's default FocusTraversalKeys. What we need to do to capture the VK_TAB KeyEvent is to remove the default FocusTraversalKeys from the component.

        myJTextField.setFocusTraversalKeys(
                KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.EMPTY_SET);

Once we've done this with the component, the tab KeyEvent will not be captured by swing's default focus traversal keys and we will be able to add events normally.

myJTextField.addKeyListener(new java.awt.event.KeyAdapter() {
    public void keyPressed(java.awt.event.KeyEvent evt) {
        if(evt.getKeyCode() == evt.VK_TAB){
            /* PUT YOUR STUFF HERE OR CALL A FUNCTION */
            doSomething();
            /* If you want to change the focus to the next component */
            nextJComponent.grabFocus();
    }
});

Technorati Tags:

Posted by admin at 12:50 PM in Java

miércoles, 30 mayo 2007

Dynamic icons for your JComponents // Create an icon JButton with dynamic icons.

Internet offers many opportunities and possibilities for developers with imagination. Today, most search engines and specialized sites count with API's to access their data from other software, sites, devices...

Today I'm going to show you a dirty example of how this apis can benefit your program. In less of ten lines of code (someone intelligent would have done it in less) I will add an Icon to a jButton with an image stored in the net.

To do this I will use yahoo's Image Search API, documentation can be found here. For demonstration purposes I will use the YahooDemo applicationId, you will need to create one if you intend to use this api in your programs.

In brief, what the program does is decode what the browser gets when it reads an url constructed with the api guidelines. The response is an XML inputStream where you can get the url of a thumbnailed image which you can then pass to the JButton.

try {
            URL pepe = new URL("http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=YahooDemo&query=client%20icon&results=1&format=gif");
            BufferedReader br = new BufferedReader(new InputStreamReader(pepe.openStream()));
            String text ="";
            String line = null;
            while((line = br.readLine()) != null){
                text += line+"\n";
            }
            text = text.substring(text.indexOf("<Thumbnail>"));
            text = text.substring(text.indexOf("<Url>")+5, text.indexOf("</Url>"));
            BufferedImage img = ImageIO.read(new URL(text));
            jButton1.setIcon(
                    new ImageIcon(img));
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

When you run this code this is what you get:
Customer

As you can see the program is quite simple. In the first part, you generate an URL with the desired variables. In this case, we want a customer icon in a gif format. You can refer to the api guide to customize your URL. In second place, we get the contents of the URL and parse it to get the location of the thumbnail image. Finally we get the thumbnailed image using ImageIO.

You can download a running version of the code here.

Technorati Tags:

Posted by admin at 9:16 AM in Java

miércoles, 23 mayo 2007

JTable, detecting selection changes // ListSelectionListener /*Selection Changed Event*/

When working with tables, it may be useful to detect selection changes. If for example, you need to sum the values of a specified column in a selection range, this method will be most essential.

If you explore the available methods to add listeners to a JTable, you will notice there's no such thing as a selectionListener. This is because the JTable has its own selection model, where you can add the listener.

The following code illustrates the way to go to add a selection listener:

JTable jtable = new JTable();
jTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
    public void valueChanged(ListSelectionEvent e) {
        /*TODO: Add whatever you need to do when the selection changes */
    }
});

Technorati Tags:

Posted by admin at 5:25 PM in Java

lunes, 21 mayo 2007

SimpleDateFormat to check user date input // parsing String to dates in java

When developing user interfaces for management software you usually need to check what the user inputs in order to store the values in a database or a file. Java offers different alternative to parse String (normally the way user inputs values to the system) to other data types.

The class SimpleDateFormat from the package java.text offers a simple method to do this. You just have to call parse(String youDate) in order to get a java.util.Date.

Following you can find some code which explains this method and some of its particularities:

/* We create the SimpleDateFormat object with the desired patter */
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        /* This is very important. If you need strict parsing, (i.e. January
         * will only have 31 days you must set this to false.
         * If you don't do this when you parse "32/01/2007" the date you'll
         * you'll get really be 01/02/2007*/
        sdf.setLenient(false);
        try {
            System.out.println(sdf.parse("25/12/2022"));
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        /* This first parse offers no problem, when run you will get
         * Sun Dec 25 00:00:00 CET 2022
         * in the console*/

        try {
            System.out.println(sdf.parse("34/15/2002"));
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        /* In this case, the date is wrong thus we will get the correspondant 
         *  exception */
        try {
            System.out.println(sdf.parse("28/02/202"));
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        /* This time we will not get an exception, but in some cases we would like
         to get the exception, because this date although valid, has an uncommon
         length and may be due to an input error.*/

    /*To solve the above proble, we could create the following function:*/
    public Date parseDate(String date) throws ParseException{
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        sdf.setLenient(false);
        if(date.length() != 10){
            throw new ParseException("Date with wrong length: "+date, 0);
        }
        return sdf.parse(date);
    }

Technorati Tags:

Posted by admin at 11:09 AM in Java