From now there is a new project in google code related to Text Mining: WordnetAPI.
WordnetAPI is a Java interface to the famous WordNet database of lexical relationships.
It converts the Wordnet Dictionary in an embedded H2 Database and access the data through the Java Persistence API (currently Toplink essential implementation), providing a stictly object-oriented interface, instead of the procedural one in the original Wordnet C library.
Friday, November 28, 2008
Friday, October 31, 2008
Manage amounts in Java with BigDecimal
What result do you expect from this sum?
The correct value is 0.01 but in Java the result is 0.009999999999999998!
This is the reason why the JDK provides the class BigDecimal: use it always for financial calculation!
Anyway you have to pay some attention to 5 simple rules:
1) Don't forget the operations return always the new value, for example don't do this:
because the right way is
2) When you create a new object use the string constructor, that means new BigDecimal("10.50") instead of new BigDecimal(10.50).
3) To compare never use the .equals() method, because it will compare also the scale and not only the mathematical value. Instead, use the .compareTo() and .signum() methods.
4) When dividing BigDecimals, be careful to specify the rounding in the .divide(...) method. Thus, you should always do:
5) Finally the gold rule for everything: read carefully the API Reference!
double x = 0.009;
double y = 0.001;
double z = x + y;
The correct value is 0.01 but in Java the result is 0.009999999999999998!
This is the reason why the JDK provides the class BigDecimal: use it always for financial calculation!
Anyway you have to pay some attention to 5 simple rules:
1) Don't forget the operations return always the new value, for example don't do this:
amount.add( thisAmount );
because the right way is
amount = amount.add( thisAmount );
2) When you create a new object use the string constructor, that means new BigDecimal("10.50") instead of new BigDecimal(10.50).
3) To compare never use the .equals() method, because it will compare also the scale and not only the mathematical value. Instead, use the .compareTo() and .signum() methods.
4) When dividing BigDecimals, be careful to specify the rounding in the .divide(...) method. Thus, you should always do:
a = b.divide(c, decimals, rounding);
5) Finally the gold rule for everything: read carefully the API Reference!
Wednesday, October 29, 2008
Remove elements in a List safely
As the javadoc for the interface List states, it provides two methods to efficiently remove entries. But when you remove and entry during iteration a ConcurrentModificationException may occur. To avoid this, use the methode remove in the interface Iterator instead of the one in List. But remember, we're talking about interfaces, thefore there is no warranty that the concrete implementation take care of this behaviour.
Anyway with ArrayList you can use Iterator.remove() without problem. See the example
Also if you synchronize the list with List list = Collections.synchronizedList(new ArrayList(...));, it will throw a ConcurrentModificationException.
Anyway with ArrayList you can use Iterator.remove() without problem. See the example
@Before
public void setup() throws Exception {
list = new ArrayList();
int len = 100;
for (int i = 0; i < len; i++) {
list.add(i);
}
}
@Test(expected = ConcurrentModificationException.class)
public void removeWrong() throws Exception {
for (Iteratoriterator = list.iterator(); iterator.hasNext();) {
Integer i = iterator.next();
if (i >= 50) {
// wrong can throw ConcurrentModificationException
list.remove(i);
}
}
}
@Test
public void removeRight() throws Exception {
Assert.assertEquals(100, list.size());
for (Iteratoriterator = list.iterator(); iterator.hasNext();) {
Integer i = iterator.next();
if (i >= 50) {
iterator.remove();
}
}
Assert.assertEquals(50, list.size());
}
Also if you synchronize the list with List list = Collections.synchronizedList(new ArrayList(...));, it will throw a ConcurrentModificationException.
Subant: Calls a given target in another build file
There is a very useful ant task, the subant task. It allows to call a target in an external build file.
It requires this syntax:
It requires this syntax:
<subant buildfile="../subproject/build.xml"The best way to use this task, is to invoke it in another target in the current build file.
target="mytarget"
buildpath="../subproject" />
Wednesday, July 16, 2008
JSF: put an object in the request map
You can put everything into the request scope througt the ExternalContext
then can you show the data in the jsp page with the EL syntax as usual:
ExternalContext ctx = FacesContext.getCurrentInstance().getExternalContext();
Map map =ctx.getRequestMap();
map.put("person", new Person("John", "Smith"));
then can you show the data in the jsp page with the EL syntax as usual:
<h:outputText value="#{person.name}" />
Sunday, July 6, 2008
Installing Eclipse Plugins in a separate path
It may be very practical to install Eclipse extensions anywhere on your hard disk and not necessarily in the Eclipse installation folder.
To do this, create a folder named for example
Put there in other folders your plug-ins and create inside every plug-in folder a directory named eclipse. For example:
Assure that Eclipse is closes and then go to your Eclipse directory and create a folder named
Create there a file with the extension .link for each of your plug-ins and write in this file just the following line:
You've done, now can you start eclipse and the plug-ins are installed.
To do this, create a folder named for example
eclipse-addons.Put there in other folders your plug-ins and create inside every plug-in folder a directory named eclipse. For example:
~/eclipse-addons/myplugin/eclipse
Assure that Eclipse is closes and then go to your Eclipse directory and create a folder named
links.Create there a file with the extension .link for each of your plug-ins and write in this file just the following line:
path=~/eclipse-addons/myplugin
You've done, now can you start eclipse and the plug-ins are installed.
Friday, May 30, 2008
Extending JBoss Classpath
In $JBOSS_HOME/server/{instance}/lib can you put all the external jar that you need, but if you want to put them separatly into another path, add the following entry in your $JBOSS_HOME/server/{instance}/jboss-service.xml
Then you can set
This approach my be very practical to manage jar files, but also configurations files.
<classpath codebase="file:///${jboss.myserver.lib.ext}" archives="*" /> Then you can set
jboss.myserver.lib.ext simply in your JBoss start script as Java System Property, for exampleexport JAVA_OPT="$JAVA_OPT -Djboss.myserver.lib.ext=/to/path
This approach my be very practical to manage jar files, but also configurations files.
Wednesday, May 21, 2008
Transform a sequence of text in a Java String Array
When your input text sound like:
than you will get the following String Array:
by using this sed script:
It performs this tasks:
oil sunflowerse tonn march said tender import trader egypt may
than you will get the following String Array:
{"oil", "sunflowerse", "tonn", "march", "said", "tender", "import", "trader", "egypt", "may"}
by using this sed script:
sed 's/^ *//; s/ *$//; s/ \{1,\}/ /g; s/ /\", \"/g; s/^/{"/; s/$/"}/' filenameIt performs this tasks:
- Remove all multiple spaces at the start
- Remove all multiple spaces at the end
- Remove all multiple spaces between the words
- Replace all single spaces with ", "
- Add {" at the start
- Add "} at the end
Saturday, May 10, 2008
Tranforming a text into Java String
Sometimes you may need, for example for unit-tests, to hard-code text in you java classes.
The following sed command can help you:
It performs respectively this tasks:
For example:
will be:
A very goldmine of "cooking tips" on sed can be found here
To distribute a long string across multiple lines:
The following sed command can help you:
sed 's/"/\\"/g; s/^/"/; s/$/\\n"+/; $ s/\\n"+/";/' filename
It performs respectively this tasks:
- Replace all occurencies of " with \"
- Insert " at the begininng of each line
- Insert \n"+ at the end of each line
- Replace the last occurency of \n"+ with ";
For example:
A woman's face with nature's own hand painted,
Hast thou, the master mistress of my passion;
A woman's gentle heart, but not acquainted
With shifting change, as is false women's fashion:
An eye more bright than theirs, less false in rolling,
Gilding the object whereupon it gazeth;
A man in hue all hues in his controlling,
Which steals men's eyes and women's souls amazeth.
And for a woman wert thou first created;
Till Nature, as she wrought thee, fell a-doting,
And by addition me of thee defeated,
By adding one thing to my purpose nothing.
But since she prick'd thee out for women's pleasure,
Mine be thy love and thy love's use their treasure.
will be:
"A woman's face with nature's own hand painted,\n"+ "Hast thou, the master mistress of my passion;\n"+ "A woman's gentle heart, but not acquainted\n"+ "With shifting change, as is false women's fashion:\n"+ "An eye more bright than theirs, less false in rolling,\n"+ "Gilding the object \"whereupon\" it gazeth;\n"+ "A man in hue all hues in his controlling,\n"+ "Which steals men's eyes and women's souls amazeth.\n"+ "And for a woman wert thou \"first\" created;\n"+ "Till Nature, as she wrought thee, fell a-doting,\n"+ "And by addition me of thee defeated,\n"+ "By adding one thing to my purpose nothing.\n"+ "But since she prick'd thee out for women's pleasure,\n"+ "Mine be thy love and thy love's use their treasure.";
A very goldmine of "cooking tips" on sed can be found here
To distribute a long string across multiple lines:
fmt [filename] | sed 's/"/\\"/g; s/^/"/; s/$/\ " +/; $ s/\ " +/"/'
Wednesday, April 16, 2008
Simple injection util
Dependency injection is really a mainstrem in today's Java Programming. There are entire Framework, that are based on it, like Spring, Google Guice or Picocontainer.
Also called inversion of control, this pattern helps to reduce dependecies and is especially useful in unit testing.
By the way, we'll now introduce a simple Utility class to inject instances of object at field level.
This approach has a big disadvantage: it doesn't catch the attributes, that belog to superclasses, because of
I thought that Class#getField(String) could help in this case but I was wrong, because this method retrieves recursively only the fields, which are public.
This article gives me the right solution, that is:
So in order to get the desired result, you can now use this implementation.
Also called inversion of control, this pattern helps to reduce dependecies and is especially useful in unit testing.
By the way, we'll now introduce a simple Utility class to inject instances of object at field level.
static public void injectField(Object objectToBeInjected, String fieldName,
Object objectToInject) throws NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
Class clazz = objectToBeInjected.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(objectToBeInjected, objectToInject);
}
This approach has a big disadvantage: it doesn't catch the attributes, that belog to superclasses, because of
clazz.getDeclaredField(fieldName).I thought that Class#getField(String) could help in this case but I was wrong, because this method retrieves recursively only the fields, which are public.
This article gives me the right solution, that is:
static public Field getDeclaredField(Object object, String name)
throws NoSuchFieldException {
Field field = null;
Class clazz = object.getClass();
do {
try {
field = clazz.getDeclaredField(name);
} catch (Exception e) { }
} while (field == null & (clazz = clazz.getSuperclass()) != null);
if (field == null) {
throw new NoSuchFieldException();
}
return field;
}
So in order to get the desired result, you can now use this implementation.
Thursday, April 10, 2008
toString() methods generation
If you want to generate quick a
Anyway, if your are doing some refactoring, there some probability that you will forget to add new or renamed fields to your
The people of GridGain have thought a very clever solution to this common issue.
You can simply write a generic impementation as follows
to obtain the desired result.
Besides you have also the flexibility to exclude/include attribute or set the right order by using the following annotaions:
toString() method for your domain-objects, with all the attributes and relative values a good solution is the eclipse plug-in jutils.Anyway, if your are doing some refactoring, there some probability that you will forget to add new or renamed fields to your
toString() method... but don't care!The people of GridGain have thought a very clever solution to this common issue.
You can simply write a generic impementation as follows
@Override
public String toString() {
return ToStringBuilder.toString(MySimpleClass.class, this);
}
to obtain the desired result.
Besides you have also the flexibility to exclude/include attribute or set the right order by using the following annotaions:
- @GridToStringInclude Annotation This annotation can be attached to any field in the class to make sure that it is automatically included even if it is excluded by default.
- @ToStringExclude AnnotationThis annotation can be attached to any field in the class to make sure that it is automatically excluded even if it is included by default.
- @ToStringOrder(int) Annotation This annotation provides custom ordering of class fields. Fields with smaller order value will come before in toString() output. By default the order is the same as the order of field declarations in the class.
Tuesday, April 1, 2008
SCBCD for Java EE 5
I'm very proud to comunicate your that since March 25, 2008 I'm a Sun Certified Business Component Developer (SCBCD) for the Java Platform, Enterprise Edition 5.
This is my Score Report (total score: 72%):
This is my Score Report (total score: 72%):
| Section Analysis | Score % |
|---|---|
| EJB 3.0 Overview | 66% |
| General EJB 3.0 Enterprice Bean Knowledge | 83% |
| EJB 3.0 Session Bean Component Contract & Lifecycle | 85% |
| EJB 3.0 Message-Driven Bean Component Contract | 75% |
| Java Perisitence API Entities | 71% |
| Java Perisitence Entity Operations | 80% |
| Persistence Units and Persitence Contexts | 83% |
| Java Persistence Query Language | 50% |
| Transactions | 40% |
| Exceptions | 80% |
| Security Management | 75% |
Java 6 support wildcards in classpath
With java 6 you don't need anymore to specify all jar files in classpath.
For example, if all your jar are in lib folder, you can start your program in a very simple manner:
Besides, if your classes are in a directory named
Take care: subdirectories are not searched recursively! That means,
For example, if all your jar are in lib folder, you can start your program in a very simple manner:
java -cp lib/* MyClass
Besides, if your classes are in a directory named
bin:java -cp bin;lib/* MyClass
Take care: subdirectories are not searched recursively! That means,
foo/* looks for JAR files only in foofoo, not in foo/bar, foo/baz, etc...
Wednesday, February 20, 2008
Some useful ant tasks
Call another target within another buildfile
Call another target within the same buildfile. It can be used also for imported buildfile.
The complete list of Ant core tasks can be found here.
<ant antfile="../AnotherProject/build.xml" target="mytarget">
Call another target within the same buildfile. It can be used also for imported buildfile.
<antcall target="mytarget">
The complete list of Ant core tasks can be found here.
String Concatenation Comparison
I've concatenate two strings, an integer and a double in five different ways.
Here are the results (in nanosecs):
Here are the results (in nanosecs):
StringBuilder 37708
StringBuffer 95319
String 5389877
C-Like 10690022
MessageFormat 30410260
Saturday, February 16, 2008
The Java Logging API in brief (part II)
Now I'd like to debate with you about some logging best practise.
If your log messagge would not be logged with the current settings and it contains relative expensive operation like a string concatenation, it's better to precede it with a less expensive operation like a check:
To log an exception and its stacktrace use:
You can also you when you enter in a method and with which parameters, if you throws exception in the method and when you exit and with with return value.
This is an example:
Note that this approach is very intrusive and inquinates you code logic, therefore it would be better to do this using an interceptor.
If your log messagge would not be logged with the current settings and it contains relative expensive operation like a string concatenation, it's better to precede it with a less expensive operation like a check:
if (logger.isLoggable(Level.FINEST)) {
logger.finest("log this: "+value);
}To log an exception and its stacktrace use:
try {
// Test with an exception
throw new Exception();
} catch (Throwable e) {
// Log the exception
logger.log(Level.SEVERE, "your message", e);
}You can also you when you enter in a method and with which parameters, if you throws exception in the method and when you exit and with with return value.
This is an example:
public int myMethod(String p1, int p2) {
log.entering(MyClass.class.getName(), "myMethod",
new Object[] { p1, p2 });
if (p2 < 0) {
Exception ex = new IllegalStateException();
log.throwing(this.getClass().getName(), "myMethod", ex);
}
int result = p2 * 2;
log.exiting(MyClass.class.getName(), "myMethod", result);
return result;
}
Note that this approach is very intrusive and inquinates you code logic, therefore it would be better to do this using an interceptor.
The Java Logging API in brief (part I)
In my previous post I've suggested a very primitive way to log error. Of course the right way to log your error, but also other information, is to use a really logger.
The most famous logger for the java environment is sure log4j but also the core jdk provides a logging api. The vantage of using the embedded java logging api is that you need no external jar.
If you already know the the log4j levels, this comparison table can help you:
To create a logger with the Java Logging API:
Note that I've called this logger as the package because this be my very practical in case of refactoring. Of couse, you are free to use the name that best fits your needings, for example the module name.
You can configure log level and everything else programmatically but the best and less intrusive way to do this is the
A standard configuration is already in every java distribution in the folder
This is the standard configuration as for jdk 6
This configuration is pretty self-explanatory, note as you can set different log level for different logger.
You can write your own log formatter by subclassing the abstract class
The most famous logger for the java environment is sure log4j but also the core jdk provides a logging api. The vantage of using the embedded java logging api is that you need no external jar.
If you already know the the log4j levels, this comparison table can help you:
| log4J | Java Logging |
|---|---|
| log4j.fatal("msg"); | - |
| log4j.error("msg"); | logger.severe("msg"); |
| log4j.warn("msg"); | logger.warning("msg"); |
| log4j.info("msg"); | logger.info("msg"); |
| log4j.debug("msg"); | logger.config("msg"); |
| - | logger.fine("msg"); |
| - | logger.finer("msg"); |
| - | logger.finest("msg"); |
To create a logger with the Java Logging API:
private static final Logger log =
Logger.getLogger(MyClass.class.getPackage().getName());
Note that I've called this logger as the package because this be my very practical in case of refactoring. Of couse, you are free to use the name that best fits your needings, for example the module name.
You can configure log level and everything else programmatically but the best and less intrusive way to do this is the
logging.properties file.A standard configuration is already in every java distribution in the folder
$JAVA_HOME/jre/lib/ but you can use a different file by specifying a filename with the java.util.logging.config.file system property (for example java -Djava.util.logging.config.file=/path/to/log.properties).This is the standard configuration as for jdk 6
############################################################
# Default Logging Configuration File
############################################################
############################################################
# Global properties
############################################################
# "handlers" specifies a comma separated list of log Handler
# classes. These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler
# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers. For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
This configuration is pretty self-explanatory, note as you can set different log level for different logger.
You can write your own log formatter by subclassing the abstract class
java.util.logging.Formatter and overriding the method format(LogRecord).
Redirect Std Error to a file
Sometimes may be convenient to save all outcomes from standar error to a file.
This is very easy to do and you need the following lines of code
The problem with this approach is that there is no timestamp, like for normal log.
A simply workaround may be to redirect the standard error at every launch to a different file named with the timestamp and to save all the log files in the same folder.
and your exception will be saved in file like this:
This is very easy to do and you need the following lines of code
String filename = "mylog.log";
PrintStream stream = new PrintStream(filename);
System.setErr(stream);
The problem with this approach is that there is no timestamp, like for normal log.
A simply workaround may be to redirect the standard error at every launch to a different file named with the timestamp and to save all the log files in the same folder.
String logFolderName = "log";
File logFolder = new File(logFolderName);
// Create the log folder if it non already exists
if (!logFolder.exists()) {
logFolder.mkdirs();
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH:mm");
StringBuilder sb = new StringBuilder();
sb.append(logFolderName);
sb.append(System.getProperty("file.separator"));
sb.append("mystderr");
sb.append("_");
sb.append(df.format(new Date()));
sb.append(".log");
PrintStream stream = new PrintStream(sb.toString());
System.setErr(stream);
and your exception will be saved in file like this:
log/mystderr_2008-02-16_22:09.log
Self Made Reports Alternative
There are many Reporting Tool for Java, here can you find an almost complete overview.
Anyway, if you're looking for a low-level, very flexible and self-made solution, can you consider to do your reports in XHTML (with or without a WYSWYG editor), populate it with data with template engine like Velocity.
Then you can trasform your XTML output in PDF with Flying Saucer. The Flying Saucer ist a XTML+CSS renderer to view or convert such document to pdf. It provide also very useful pagination capabilities, like page format, page number, page breaks, header and footer.
Last but not least, can you view or silent print your pdf report with another higt-quality open-souce tool like PDF-Renderer.
Anyway, if you're looking for a low-level, very flexible and self-made solution, can you consider to do your reports in XHTML (with or without a WYSWYG editor), populate it with data with template engine like Velocity.
Then you can trasform your XTML output in PDF with Flying Saucer. The Flying Saucer ist a XTML+CSS renderer to view or convert such document to pdf. It provide also very useful pagination capabilities, like page format, page number, page breaks, header and footer.
Last but not least, can you view or silent print your pdf report with another higt-quality open-souce tool like PDF-Renderer.
JUnit 4 in 30 seconds
JUnit is one of the most used Unit Testing Frameworks for java.
Beginning from the version 4, it provides some very intuitive annotations to write your test:
@BeforeClass
Methods are executed once before the first of the series of tests. External resources that are used by all tests should be initialised here (i.e.: a database connection).
@AfterClass
Methods are executed once after the last test has been run.Resources used by the tests that need to be released such as streams etc. should be set free here.
@Before
Methods are executed before every single test. For example can you init your test data.
@After
Methods are executed after every single test. For example can you delete the output of your test.
@Test
Methods are the actual test methods. Here can you use the Assertion.
@Test (expected = ArrayIndexOutOfBoundsException.class)
The Test Annotation can be extended by stating what exception should be thrown when the test is executed, the test fails if no exception or if the wrong exception is thrown.
@Ignore
Don't run tests, that are not yet implemented.
Beginning from the version 4, it provides some very intuitive annotations to write your test:
@BeforeClass
Methods are executed once before the first of the series of tests. External resources that are used by all tests should be initialised here (i.e.: a database connection).
@AfterClass
Methods are executed once after the last test has been run.Resources used by the tests that need to be released such as streams etc. should be set free here.
@Before
Methods are executed before every single test. For example can you init your test data.
@After
Methods are executed after every single test. For example can you delete the output of your test.
@Test
Methods are the actual test methods. Here can you use the Assertion.
@Test (expected = ArrayIndexOutOfBoundsException.class)
The Test Annotation can be extended by stating what exception should be thrown when the test is executed, the test fails if no exception or if the wrong exception is thrown.
@Ignore
Don't run tests, that are not yet implemented.
Tuesday, January 22, 2008
Read PDF on your PDA - pdfcrop
I've a lot of pdf - books, tutorial an so on - collected everywhere in internet.
My dream was to read them on my Nokia 770 when I'm not home like a normal book, but they were too small and hard to read.
Now I've found a wonderful small tool that solves this problem: pdfcrop.
According to his guide:
I've tryed it until now with dozens pdf and I've to say that it does his job very well1!!!
My dream was to read them on my Nokia 770 when I'm not home like a normal book, but they were too small and hard to read.
Now I've found a wonderful small tool that solves this problem: pdfcrop.
According to his guide:
PDFCROP takes a PDF file as input, calculates the BoundingBox
for each page by the help of ghostscript and generates a output
PDF file with removed margins.
I've tryed it until now with dozens pdf and I've to say that it does his job very well1!!!
Tuesday, January 15, 2008
The easiest way to print text
The most of us use System.out.println to print to the screen but maybe a more conveniet way is
because if you want to redirect your output to a file, you have simply to change the construction of PrintStream as follows:
Remember that, if you're writing a command-line program that can be executed everywhere in the filesystem, to precede your filename with the complete path of the working dir
PrintStream out = System.out;
out.println("print something");
because if you want to redirect your output to a file, you have simply to change the construction of PrintStream as follows:
File myfile = new File("myfile.txt");
PrintStream out = new PrintStream(myfile);Remember that, if you're writing a command-line program that can be executed everywhere in the filesystem, to precede your filename with the complete path of the working dir
String workingDir = System.getProperty("user.dir")
+ System.getProperty("file.separator");
File myfile = new File(workingDir+"myfile.txt");
Sunday, January 13, 2008
Java Command Line apps under Linux
Your java command line apps cannot properly work under linux because of the spaces beetwen arguments.
For example the following bash script gives you wrong results:
This is instead the right way:
As you can see, we concatenate first the arguments (enclosed in "...") and then we execute the command.
For example the following bash script gives you wrong results:
#!/bin/sh
java -classpath $CLASSPATH eu.kostia.ejb.client.SendEmail $*
This is instead the right way:
#!/bin/sh
# concatenate args and use eval/exec to
# preserve spaces in paths, options and args
args=""
for arg in "$@" ; do
args="$args \"$arg\""
done
CLASSPATH=lib/commons-cli-1.1.jar:bin
cmd="java -classpath $CLASSPATH eu.kostia.ejb.client.SendEmail $args"
eval "exec $cmd"
As you can see, we concatenate first the arguments (enclosed in "...") and then we execute the command.
Subscribe to:
Posts (Atom)