martes, 18 noviembre 2008

BeansBinding Performance (Issue 37)

Since the release of NetBeans 6.0, BeansBinding (JSR 295) framework popularity has increased. Personally I'm using it now in all my projects. Ease of development and the increase of productivity are worth it. The counterpart is that this project looks dead and hasn't been updated for more than a year now. Even more, recent news about Swing core is not very encouraging.

In my opinion I believe that Sun's budget is very limited and their recent javaFx has consumed all their resources in the past year. Bearing in mind that BeansBinding is now included in netbeans and that javaFx is based in swing, I don't think that neither of the projects is going to be abandoned.

Getting into the subject, BeansBinding has not been updated for a while now, and has some bugs that are really annoying. If you use beans binding to bind a form with more than 20 fields you'll notice how the form takes a lot to load. If you profile your application, you'll quickly notice that the bottleneck is in the statement bindingGroup.bind() in the initComponents() section of your code (if you are using Netbeans + matisse). Taking a deeper look with the netbeans profiler tool we get to our point. If you examine carefully BeanPropery or ElPropery class, the method getBeanInfo(Object object) is calling Introspector.getBeanInfo(object.getClass(), Introspector.IGNORE_ALL_BEANINFO); which takes a lot of time. I Googled to see if I could get any clue about what was happening and if someone else was experiencing the same problem. I found a 2 mail message thread. Not very popular for such a big performance problem. The thread informs of the created Issue (Issue 37) the and suggest a possible solution using USE_ALL_BEANINFO (which by the way is the default flag used if you call the Introspector.getBeanInfo(Class class) directly).

The slow dialog opening is really pissing me, so I've implemented a solution. Your first approach can be by getting the source code and replacing the code fragment you need and then recompile the library. There is a great tutorial (Hacking Java Libraries) which teaches you how to do this if you don't know how to do it by yourself. The article is an exception of "Covert Java" by Alex Kalinovsky (Sams Publishing, May 2004) (recommended reading).

I don't really like the approach above. With these technique you can't keep track of the changes you've made and further updates of the library will need to be modified and recompiled again (until the bug is corrected). I prefer to manipulate the bytecode at runtime to reflect the changes I need (BCEL). For this purpose I'm going to use the javassist library which is very light and straightforward. In the next code fragment you have the code needed to get the modification working.

try {
            ClassPool cp = ClassPool.getDefault();
            CtClass cc = cp.get("org.jdesktop.beansbinding.ELProperty");
            CtMethod m = cc.getDeclaredMethod("getBeanInfo");
            m.setBody("{"+
                    //"assert $1 != null;" +
                    "try {" +
                    "return java.beans.Introspector.getBeanInfo($1.getClass());" +
                    "} catch (java.beans.IntrospectionException ie) {" +
                    "throw new org.jdesktop.beansbinding.PropertyResolutionException(\"Exception while introspecting \" + $1.getClass().getName(), ie);" +
                    "} }");
            Class c = cc.toClass();
            cc = cp.get("org.jdesktop.beansbinding.BeanProperty");
            m = cc.getDeclaredMethod("getBeanInfo");
            m.setBody("{"+
                    //"assert $1 != null;" +
                    "try {" +
                    "return java.beans.Introspector.getBeanInfo($1.getClass());" +
                    "} catch (java.beans.IntrospectionException ie) {" +
                    "throw new org.jdesktop.beansbinding.PropertyResolutionException(\"Exception while introspecting \" + $1.getClass().getName(), ie);" +
                    "} }");
            c = cc.toClass();
        } catch (NotFoundException ex) {
            ex.printStackTrace();
        } catch (CannotCompileException ex) {
            ex.printStackTrace();
        }

What the above code does is replace the method body of getBeanInfo in ElPropery and BeanPropery with the modified code that suits our needs. In this case, instead of calling Introspector.getBeaninfo(Class class, int flag) it calls Introspector.getBeanInfo(Class class) which by default uses gets the cached information improving performance. For all of this to work its very important to run this code before any other code which uses the beansbinding library is called. If you can't do that, read the javassist tutorial to build a loader or use HotSwapper.

I don't know why Shannon decided to use the Introspector.IGNORE_ALL_BEANINFO flag in the first place, maybe there's a good reason. I can't really think why we shouldn't use the cached info, there's no reason why a bean should change its structure during runtime (Unless someone is using dynamic bytecode engineering BCEL).

I hope this code helps you. Please if you have any comments, suggestions or improvements, please post them. Thank you..

Technorati Tags:

Posted by admin at 9:53 AM in Java

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

lunes, 7 mayo 2007

Numbers to Strings with custom symbols // DecimalFormat - DecimalFormatSymbols

When printing reports or casting Strings to Numbers, its very useful to use the DecimalFormat class found in java.text. This class is pretty straightforward and easy to use, but some problems may be found when your work with this class in computers from other countries. Internationalization will cause your program to behave in a way you may not expect in some cases.

If you use these class to parse a number to a String, you may find that when a user enters a number in a french computer you will be getting a ParseException, because the computer is expecting different symbols. Here is where the DecimalFormatSymbols class becomes very useful.

With the following code I'll show you how easy is to change the symbols and make them independent of different Locales.


/* We create our formatter using a DecimalFormat Instance.
         * We use these method instead of (new DecimalFormat(String pattern))
         * because in computers with different locales, we may have problems when
         * setting the pattern. This way we assure we always work with the same variables.
         **/
        DecimalFormat format = (DecimalFormat)DecimalFormat.getInstance(Locale.ENGLISH);
        /* We set the typical pattern with thousand separator and two decimal places */
        format.applyPattern("#,##0.00");
        /* Now we do the work to change the formatting symbols 
         * We will set the typical spanish symbols*/
        DecimalFormatSymbols dfs = format.getDecimalFormatSymbols();
        dfs.setDecimalSeparator(',');
        dfs.setGroupingSeparator('.');
        format.setDecimalFormatSymbols(dfs);
        /* We do two simple tests */
        System.out.println(format.format(1000234234.56772345d));
        try {
            System.out.println(format.parse("1.258.254,25"));
        } catch (ParseException ex) {
            ex.printStackTrace();
        }

Technorati Tags:

Posted by admin at 6:49 AM in Java

miércoles, 18 abril 2007

Java recursive functions explained // Using recursion to sum an array of numbers

Java is a very powerful object oriented language. If you search for recursion in wikipedia you will find this definition "Recursion, in mathematics and computer science, is a method of defining functions in which the function being defined is applied within its own definition." This means, that the function will call itself again and again until it gets the correct answer.

There are many pages where you can find great explanations to recursion theory. Most of them use the example of the Towers of Hanoi:

What I'm going to show you is an easy way to sum arrays of numbers. This example lets you see how easy can recursion be and how useful it is.

public class recursive {
    public recursive() {
                /** We create the array of numbers we want to sum
                    It can be any subclass of java.lang.Number*/
                Double[] test = {100d, 0.05d, 88d, 99d, 0.05d, 88d, 99d, 0.05d, 88d, 99d};
                /* We call our function */
                System.out.println(sum(test));
    }
    /* This is the initial function, it calculates the starting fields and results
     *automatically*/
    public Number sum(Number[] numbers){
        return sum(numbers[numbers.length - 1], numbers, numbers.length - 2);
    }
    /* This is our RECURSIVE FUNCTION */
    public Number sum(Number initialValue, Number[] numbers, int location){ 
        /* If we've reached the end of the array we return the final RESULT */
        if(location < 0){
            return initialValue;
        }
        /* Or else we are recursive */
        else{
            /*First we cast the java.lang.Number to its subclass so we can do the 
             *sum */
            if(numbers instanceof BigInteger[]){
                return sum(
                        ((BigInteger)initialValue).add((BigInteger)numbers[location]),
                        numbers,
                        (location - 1) );
            }
            else if(numbers instanceof  BigDecimal[]){
                return sum(
                        ((BigDecimal)initialValue).add((BigDecimal)numbers[location]),
                        numbers,
                        (location - 1) );
            }
            else if(numbers instanceof  Byte[]){
                return sum(
                        ((Byte)initialValue) + (Byte)numbers[location],
                        numbers,
                        (location - 1) );
            }
            else if(numbers instanceof  Double[]){
                return sum(
                        ((Double)initialValue) + ((Double)numbers[location]),
                        numbers,
                        (location - 1) );
            }
            else if(numbers instanceof  Integer[]){
                return sum(
                        ((Integer)initialValue)+ ((Integer)numbers[location]),
                        numbers,
                        (location - 1) );
            }
            else if(numbers instanceof  Long[]){
                return sum(
                        ((Long)initialValue)+ ((Long)numbers[location]),
                        numbers,
                        (location - 1) );
            }
            else if(numbers instanceof  Short[]){
                return sum(
                        ((Short)initialValue)+ ((Short)numbers[location]),
                        numbers,
                        (location - 1) );
            }
            else{
                return sum(
                        ((Float)initialValue)+ ((Float)numbers[location]),
                        numbers,
                        (location - 1) );
            }
        }   
    }
    /* THis is our main method */
    public static void main(String[] args) {
        new recursive();      
    }
}

Technorati Tags:

Posted by admin at 10:10 AM in Java

miércoles, 4 abril 2007

Displaying a jTable inside another jTable // JTable cellRenderer

Java is one of the greatest object oriented languages. This can easily be seen when using swing components. JTables are a great example. Briefly, jTables are just a base to display a matrix of JComponents. So inside a JTable you can embed any object which extends the JComponent class.
Today I'll show you an easy way to display a JTable inside another jTable as a cellRenderer. If you've ever worked with multivalued data models this can be of great help. In this simple example I'll create a small contact manager where the name, phones, and e-mail addresses of the contact can be stored. If the contact has more than one e-mail address or phone number, then they'll be displayed using an embedded jTable.

/* 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() {
/* These are necessary variables to store the row's height */
private int minHeight = -1;
private int currHeight = -1;
/* 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 calculate the row's height to display data
* THis is not complete and has some bugs that
* will be analyzed in further articles */
if(minHeight == -1){
minHeight = table.getRowHeight();
}
if(currHeight != passed.length*minHeight){
currHeight = passed.length * minHeight;
table.setRowHeight(row,currHeight);
}
/* We create the table that will hold the multivalue
*fields and that will be embedded in the main table */
return 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; }
});
}
}
};
/* 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);
}
/*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. The code will only allow you to display the data, but you won't be able to edit. If you want to edit the data you must also create a table cell editor. I'll analyze this in further posts.

Technorati Tags:

Posted by admin at 1:20 PM in Java

Google
 
« February »
SunMonTueWedThuFriSat
   1234
567891011
12131415161718
19202122232425
26272829