Showing posts with label JSE5. Show all posts
Showing posts with label JSE5. Show all posts

Thursday, December 15, 2011

Java Tip of the Day: Using ProcessBuilder to Make System Calls

A few years ago I posted an article on how to execute OS level system calls using the Runtime class. When I wrote that article I was using a methodology which has been around since the 1.0 days of Java. In Java 5 Standard Edition, and subsequently improved in Java 6 and Java 7, is a class called ProcessBuilder. This class is a significant improvement over using the Runtime class. It provides complete flexibilty around the system call in terms of environment including directories, input and output streams, and execution.

Here is the NetBeans 7.1 Apache Maven project: process-builder-example.zip


When I execute it from NetBeans I get something like this:
[exec:exec]
total 24
drwxr-xr-x  12 jyeary  staff   408B Dec 15 08:19 .hg
-rw-r--r--   1 jyeary  staff    52B Dec 15 08:08 .hgignore
-rw-r--r--   1 jyeary  staff   1.7K Dec 15 07:59 nbactions.xml
-rw-r--r--   1 jyeary  staff   2.0K Dec 15 08:19 pom.xml
drwxr-xr-x   4 jyeary  staff   136B Dec 14 23:31 src
drwxr-xr-x   4 jyeary  staff   136B Dec 15 08:35 target
Exit Status : 0

Saturday, June 28, 2008

Java RandomAccessFile Example

Here is another example of how to use a common file handling mechanism in Java. RandomAccessFile is very powerful tool to open a file and find specific items in it. It also allows you to update, delete, or append data to the file. Developers become accustomed to using File for a number of operations, but I contend that using RandomAccessFile is more powerful and flexible.

In the code example and Netbeans project that follow, I create a file and append data to it. I print the data out, and then add the class name to the beginning of the file, append the existing data, and print it back out again.

I originally came across my work on it when I was learning Java many years ago. I re-examined it, tweaked it, and converted it to a Netbeans project.

1 /*
  2  * 
  3  * Blue Lotus Software, LLC
  4  * 
  5  * Copyright 2008. All Rights Reserved.
  6  * 
  7  * $Id$
  8  * 
  9  */
 10 /*
 11  * Copyright (C) 2008 Blue Lotus Software. All Rights Reserved.
 12  *
 13  * THIS SOFTWARE IS PROVIDED "AS IS," WITHOUT A WARRANTY OF ANY KIND.
 14  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 15  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 16  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 
 17  * BLUE LOTUS SOFTWARE, LLC AND ITS LICENSORS SHALL NOT BE LIABLE 
 18  * FOR ANY DAMAGES OR LIABILITIES
 19  * SUFFERED BY LICENSEE AS A RESULT OF  OR RELATING TO USE, MODIFICATION
 20  * OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
 21  * BLUE LOTUS SOFTWARE, LLC OR ITS LICENSORS BE LIABLE FOR ANY LOST 
 22  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, 
 23  * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED 
 24  * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE 
 25  * OF OR INABILITY TO USE SOFTWARE, EVEN IF BLUE LOTUS SOFTWARE, LLC 
 26  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 27  *
 28  * You acknowledge that Software is not designed, licensed or intended
 29  * for use in the design, construction, operation or maintenance of any
 30  * nuclear facility.
 31  */
 32 package com.bluelotussoftware.j2se.examples;
 33
 34 import java.io.FileNotFoundException;
 35 import java.io.IOException;
 36 import java.io.RandomAccessFile;
 37 import java.util.logging.Level;
 38 import java.util.logging.Logger;
 39
 40 /**
 41  *
 42  * @author John Yeary
 43  * @version 1.0
 44  */
 45 public class RandomAccessFileExample {
 46
 47     private static final String CLASSNAME = RandomAccessFileExample.class.getName();
 48     private static Logger logger = Logger.getLogger(CLASSNAME);
 49
 50     /**
 51      * @param args the command line arguments
 52      */
 53     public static void main(String[] args) {
 54
 55         if (args.length < 1) {
 56             System.err.print("You must provide at least a file name with path!");
 57             logger.log(Level.WARNING, "You must provide at least a file name with path");
 58             System.exit(0);
 59         }
 60
 61         RandomAccessFile raf = null;
 62
 63         try {
 64             raf = new RandomAccessFile(args[0], "rw");
 65         } catch (FileNotFoundException e) {
 66             logger.log(Level.SEVERE, null, e);
 67             // Error, set return to 1, and exit 
 68             System.exit(1);
 69         }
 70
 71         for (int i = 1; i < args.length; i++) {
 72             try {
 73                 raf.seek(raf.length());
 74                 raf.writeBytes(args[i] + "\n");
 75             } catch (IOException e) {
 76                 logger.log(Level.SEVERE, null, e);
 77             }
 78         }
 79
 80         try {
 81             raf.close();
 82         } catch (IOException e) {
 83             logger.log(Level.SEVERE, null, e);
 84         }
 85
 86         RandomAccessFileExample.readRAF(args[0]);
 87
 88         try {
 89             raf = new RandomAccessFile(args[0], "rw");
 90
 91             /* If you call seek() before you read, it will not work
 92              * as expected. The read operation will move the cursor
 93              * to the end of the read method.
 94              */
 95             //raf.seek(0); 
 96
 97             byte[] b = new byte[(int) raf.length()];
 98             raf.read(b);
 99
100             /* Here we place the seek() method to append to
101              * start writing at the beginning of the file.
102              */
103             raf.seek(0);
104             raf.writeBytes(CLASSNAME + "\n");
105
106             // Append the original content of the file.
107             raf.write(b);
108             raf.close();
109         } catch (IOException ex) {
110             logger.log(Level.SEVERE, null, ex);
111         }
112         RandomAccessFileExample.readRAF(args[0]);
113     }
114
115     public static void readRAF(String fileName) {
116         try {
117             RandomAccessFile raf = new RandomAccessFile(fileName, "r");
118             String line = null;
119             while ((line = raf.readLine()) != null) {
120                 System.out.println(line);
121                 logger.log(Level.INFO, line);
122             }
123         } catch (FileNotFoundException ex) {
124             logger.log(Level.SEVERE, null, ex);
125         } catch (IOException ex) {
126             logger.log(Level.SEVERE, null, ex);
127         }
128     }
129 }

UPDATED 12/29/2009
The Netbeans project is here: RandomAccessFile.zip

Here is an example of how to delete a String value from the file.

public static void deleteRAF(String value, String fileName) {
        try {
            RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
            long position = 0;
            String line = null;
            while ((line = raf.readLine()) != null) {
                System.out.println("line::line.length()::position::getFilePointer()");
                System.out.println(line + "::" + line.length() + "::" + position + "::" + raf.getFilePointer());
                logger.log(Level.INFO, line);

                if (line.equals(value)) {
                    //Create a byte[] to contain the remainder of the file.
                    byte[] remainingBytes = new byte[(int) (raf.length() - raf.getFilePointer())];
                    System.out.println("Remaining byte information::" + new String(remainingBytes));
                    raf.read(remainingBytes);
                    //Truncate the file to the position of where we deleted the information.
                    raf.getChannel().truncate(position);
                    System.out.println("Moving to beginning of line..." + position);
                    raf.seek(position);
                    raf.write(remainingBytes);
                    return;
                }
                position += raf.getFilePointer();
            }
        } catch (FileNotFoundException ex) {
            logger.log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

Friday, June 27, 2008

Putting the Current Directory in the CLASSPATH

Someone from our users group posed a good question. Should you put the current directory in the CLASSPATH? Does it represent any security issues like on UNIX?

Here is the answer...depends, but it is generally a bad idea. Here is an example. I created a class called TestCase. It calls another class called ClassA in a jar file called ExampleJar.jar. I put another class called ClassA in the current directory and set the CLASSPATH as a passed parameter

java -classpath .:./lib/ExampleJar.jar TestCase
Here are the classes:


1 public class TestCase {
2
3 public TestCase() {
4 }
5
6 public static void main(String[] args) {
7 ClassA a = new ClassA();
8 a.print();
9 }
10 }


1 public class ClassA {
2
3 public void print() {
4 System.out.println("I am ClassA in a jar.");
5 }
6 }


1 public class ClassA {
2
3 // Bad apple!!!
4 public void print() {
5 System.out.println("I am ClassA in the wild...");
6 }
7 }


The question becomes which one of the ClassA files gets called? The legitimate one, or the bad apple?

[sundev:Desktop:root]#java -classpath .:lib/ExampleJar.jar TestCase
I am ClassA in the wild...
If I reverse the order to java -classpath lib/ExampleJar.jar:. TestCase

I get the expected result:

[sundev:Desktop:root]#java -classpath lib/ExampleJar.jar:. TestCase
I am ClassA in a jar.
The Classloader finds the first instance of the class which matches the appropriate signature and loads it. Subsequent classes of the same name and signature are not loaded.

Why does it matter?

The inclusion of the current directory into the CLASSPATH represents a potential security risk, also it may produce unexpected results from similarly named classes. The second item may be a bit more contrived in general terms, i.e. com.abc.ClassA and com.cba.ClassA are called ClassA, but are in different packages. This will not represent a problem.

The security issue can be real. A lot of programs that do installs on Windows specifically, add the CLASSPATH variable to the Windows environment and put the . (period) first. I checked my installation and found it to be the case. I would not knowingly put it there myself. Also I checked a couple of tutorials which suggest that you should do it for convenience. That piece is quickly forgotten 200 pages ago.

ADDENDUM:

Java 6 SE (J6SE) has added some additional enhancements around classpath. You can use the * (asterisk) wildcard to include all files in the classpath:

java -cp "*"; TestCase (Windows)
java -cp '*' TestCase (Unix/OS X)

Mark Reinhold has a blog entry entitled Class-Path Wildcards in Mustang which details it.

Friday, February 01, 2008

Java Generics and Collections

The Java Generics book provides an in-depth analysis of the new Generics and Collections APIs in Java 5 and 6. The book provides a level of detail on this new technology that can not be found elsewhere. This book is generally not for a novice programmer due to the level of architectural details and theory. It provides a seasoned programmer with a comprehensive examination of why and how the Generics and Collections APIs were modified, as well as, the design decisions and impact. The book provides the programmer with the information they need to make informed decisions on which type of Collection to use, and the associated pitfalls based on design decisions.

The only issue I found with the book was that it did not provide enough concrete examples. The code was provided generally in code snippets which do not provide enough detail.

The book is a definite choice for the advanced Java programmer and architect. If you are serious about learning these new technologies: this is the book to get.

Thursday, May 24, 2007

Java EE5 Persistence and Generics

The new Java EE5 Persistence provides some really cool functionality. It was designed with backwards compatibility in mind. This has resulted in some interesting issues. For example if you perform a Query which returns more than one object, the objects are returned as a List. The List is a very generic Object List. Generally we know that if we perform a query that it should return specific types back to us. For example we expect it to return a collection of the entity itself. If we accept the default which is to return a List, the compiler will report an unchecked warning. If you use the -Xlint:unchecked option, it will point out that we are getting a generic Object List and it can not verify the type of the Object.

The Solution... is simple...

When you get the List back cast it into a specific type. For example:

Query q = em.createQuery("SELECT OBJECT(p) FROM PuzzleBox p");
List puzzles = q.getResultList();
A rather elegent solution... alternatively you can have a more complex version such as

ArrayList puzzles = new ArrayList(q.getResultList);

This works because an ArrayList can accept a Collection as noted in the Javadocs:

ArrayList(Collection<? extends E> c)


The last and most inelegent solution is to annotate the methods which use the generic List of Objects to suppress the complier warnings with a @SuppressWarnings("unchecked") annotation.

Friday, November 03, 2006

Coding for Performance

Here are some performance tips gathered from various sources and personal experience. I have sorted them by category (General, J5SE, J5EE)

General
  1. Always use the simplest classes possible to get the Job Done.

  2. Never code your own frameworks unless the performance is lacking. Reuse code and frameworks.

  3. Use open source frameworks which are established and tested.

  4. "Never do today what can be put off till tomorrow. " - Aaron Burr


    • If a class proves difficult to code, put it off until you have a rest. You can then look at it with a fresh set of eyes

    • Delegate the hard parts to code to another class

    • Do not attempt to resolve all scenarios while coding, i.e., Wait to do locale specific encodings until after the initial code is complete.


  5. Place design notes in your code. Explain the performance requirements in your comments. If there are specific SRS requirements, note the number, date, and revision of the SRS document.

  6. Avoid object creation and destruction except as necessary. Reuse existing objects.

  7. Learn Collections and use them correctly. Use "lightweight" collections and avoid "heavyweight" collections where synchronization is not required.

  8. Initialize objects using a constructor with the least amount of requirements. If you need to use a number of parameters other than the default values, consider using the inverse of the object. In other words, if the object contains an int which is initialized to zero (0), then use the object with the default value and treat initialization parameters as the exception.

  9. Use findbugs to find common errors and performance problems.

  10. Reduce the distance between objects during operation. It is better to perform complex operations locally.

  11. Use System.currentTimeMillis() for performance measurements to determine execution time

  12. Use the -verbose:gc flag on the JVM to determine if the heap size is too small.

  13. Use constants where possible by using static final in the variable declaration.

  14. Use Enum instead of integer constants. Enums are more flexible and are typesafe.

  15. Avoid casting and using instanceof

  16. Use synchronized methods instead of code blocks.

  17. Avoid synchronized calls within a synchronized method or code block.

  18. Avoid using synchronization over IO operations except as required to maintain correct operation. For example: JPA inside a servlet.

  19. Turn off auto-commit and use transactions to improve throughput.

  20. Use -Xms and -Xmx flags to set the minimum and maximum heap sizes. Try to size appropriately to prevent wasting resources.


J5SE

Looping


  1. Do not recalculate constants inside a loop.

  2. "Fast Fail" - If a method fails, or throws an exception have it exit the loop quickly. Break loops early.

  3. Use local variables in loops. javac can assign an exact location of a local variable for a method at compile time.


Strings


  1. Avoid using Strings when you are modifying them. Strings are immutable. Therefore to "modify" a String, object creation and destruction must occur. Use StringBuilder and StringBuffer when Strings must be modified.

  2. Create Strings using the short form syntax to avoid creating additional objects.

    For example use: String s1 = "ABC";

    instead of: String s1 = new String("ABC");

  3. Never use String or StringBuffer for parsing characters. Use a character array.

  4. Try to set the StringBuilder or StringBuffer to the size required, or maximum size required during initialization to prevent a performance penalty while resizing.

  5. Avoid using StringTokenizer if there is a performance requirement. Use a more specific (custom) tokenizer to split Strings. StringTokenizer is a generic utility that is synchronized internally.

  6. Use StringBuilder instead of StringBuffer unless synchronization is required.


Collections


  1. Avoid using generic object collections. Use generics with collections to avoid having to cast objects.

  2. Use a LinkedList over an ArrayList if there a large number of insertions and deletions.

  3. Use a HashMap instead of a TreeMap unless there is a requirement to maintain a sort order.

  4. Use a HashSet over a TreeSet unless there is a requirement to maintain a sort order.

  5. When using Vector, try to set the initial size to the expected maximum size to prevent having to grow the Vector. If you must grow a Vector use a reasonable value to increase the size.

  6. It is extremely important to try to appropriately size a HashTable to prevent reorganization.


J5EE


  1. Reduce the number of network operations by returning complete results rather than smaller intermediate results.

  2. If database design constraints impose a specific database, use the advantages of the database where possible.


    • If operations are performed on the database, consider using stored procedures and making JDBC calls.

    • Do not use Entity Beans unless you must, use Java Persistence API (JPA) instead.

    • Do not use Java Persistence API (JPA) unless you need it, or want to use some of its advanced capabilities.

    • Limit the subset of data required to the minimum required for your program. Do not pull a whole row of data from table when you require only a few fields.


  3. When given a choice use local interfaces and local method calls on EJBs

  4. Shorten the distance between servers. Try to maintain dependent servers as close as possible. In clustered environments, try to keep remote communications on a separate private network interface.

  5. It is generally better to use a coarser stateless session bean to avoid JNDI lookups for fine grained operations.
  6. Avoid stateful session beans except as necessary.

  7. Set timers for non-activity on stateful session beans as low as possible to prevent "dead" connections waiting to timeout.

  8. Use Data Transfer Objects (DTO) to maintain granularity. DTOs must be Serializable.

Popular Posts