Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Saturday, September 12, 2009

Webservices with Axis2/Java - the simple POJO way

There are many ways to create web services in Java; the most common implementation, nowadays, is using Apache Axis2/Java and a servlet container such as Apache Tomcat or Jetty.
On the Axis2 web site, there are a number of tutorials and explanations of the various concepts; yet, somehow, I'm missing a description of the "most easy way" of creating a web service. That's why I write it here. The tutorials are based on using the provided build.xml files instead of explaining how to do it. This makes it very hard to work in a different context.

A POJO in an .aar

Axis2 is able to "interpret" any Plain Old Java Object (POJO) as a web service, given the right hints. A Pojo is just a java class with some public method(s).

A POJO

package tecbites.ws;
public class Echo {
public String echo(String input) {
return input;
}
}

To tell Axis2 that this is a web service, you need additionally

  • a services.xml that defines this class as a POJO RPC web service
  • an echo.aar that contains (at least) the services.xml in the META-INF directory, and usually, the web service code (.class file(s)).

services.xml

<service name="Echo" scope="application" >
<description>
Tecbites Echo POJO web service
</description>
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</messageReceivers>
<parameter name="ServiceClass">tecbits.ws.Echo</parameter>
</service>

Put this file into META-INF. 

creating an .aar - jar

One way to create an .aar is just using the jar-tool that is part of the JDK. Using the following folder structure:
tecbites/ws/
Echo.class
META-INF/
services.xml

, a jar can just be created that is named echo.aar. Check that the jar/aar does not contain the files in a subdirectory named echo!.
javac tecbites/ws/Echo.java
jar cf echo.aar .


creating an .aar - build.xml

Another way of creating an .aar is using build.xml, the same as creating any other .jar. See the following example:

<?xml version="1.0" encoding="UTF-8"?>
<project name="tecbites.echo" default="aar" basedir="."> <target name="build">
<javac debug="true" srcdir="." destdir="." failonerror="true" />
</target> <target name="aar" depends="build">
<property name="aar" value="echo.aar"/>
<delete file="${aar}" failonerror="false"/>
<jar destfile="${aar}">
<manifest>
<attribute name="Built-By" value="Tecbites http://tecbites.blogspot.com/"/>
</manifest>
<fileset dir="." >
<include name="**/*.class" />
<include name="META-INF/**" />
</fileset>
</jar>
</target>
</project>

Just run ant. You have got ant installed, have you?

Deployment

The installation of an Axis2 webapp and the deployment of an .aar is explained quite well on the site. Just a short version here, based on Tomcat6:

  • download the Axis2 webapp
  • deploy (copy) the axis2.war into webapps/ of a servlet container (tomcat, jetty, jboss, glassfish, ...)
And start the servlet container. Then, copy the echo.aar into the webapps/axis2/WEB-INF/services directory (the servlet container should automatically unpack axis2.war into axis2/
If you need additional jars or java code you don't want to pack into the .aar itself, there is space in axis2/WEB-INF/lib (for the jars) and axis2/WEB-INF/classes (for any package/name/Class.class files).
Usually, Axis2 is configured for "hot deployment". This means that any .aar copied newly into the services directory of a running server is directly deployed as a new web service. There is also "hot update" which is usually disabled, but can be enabled in axis2/WEB-INF/conf/axis2.xml. Then, the .aars are automagically reloaded when replaced. Of course, any code in lib/ or classes/ is not.
By the way - it should also be possible to deploy the web service by copying the unjared folder structure into a subdirectory of the services dir, thus creating webapps/axis2/WEB-INF/services/Echo/META-INF/services.xml etc.

Testing

The web service should then be visible on http://localhost:8080/axis2/services/listServices (replace port 8080 with the correct one of your servlet container installation). There, you can see all deployed services and list their methods.
The WSDL can be accessed via http://localhost:8080/axis2/services/EchoService?wsdl.
Axis2 supports a part of REST, named POX - Plain Old XML documents over http. This allows to call the web service via http://localhost:8080/axis2/services/EchoService/echo?input=Good%20Morning. A web page should be returned reading

<ns:echoResponse xmlns:ns="http://ws.tecbites">
<ns:return>Good Morning</ns:return>
</ns:echoResponse>

By the way - the following error message when accessing http://localhost:8080/axis2/services/EchoService means the service is working correctly: ;)

<soapenv:Reason>
<soapenv:Text xml:lang="en-US">
The endpoint reference (EPR) for the Operation not found
is /axis2/services/EchoService and the WSA Action = null
</soapenv:Text>
</soapenv:Reason>



Direct POJO deployment

There is also the description of deploying the POJO .class file directly into a specially configured axis2 directory. In the axis2/WEB-INF/conf/axis2.xml, there is usually a line reading

<!--POJO deployer , this will alow users to drop .class 
file and make that into a service-->
<deployer extension=".class" directory="pojo"
class="org.apache.axis2.deployment.POJODeployer"/>

This should allow to deploy the ws by copying tecbites/ws/Echo.class into the pojo directory. In the context of the jetty servlet container inside the Global Sensor Networks (GSN) project, I was unable to get this to run.

JAXWS @WebService annotations

The JAXWS standard allows to "create" web services by annotating the class with the @WebService tag. In the axis2+service.xml context, this is not necessary, but supported.
Yet, this is helpful when the web service class contains public methods that should not be accessible as web service methods.

package tecbites.ws;
import javax.jws.WebService;
import javax.jws.WebMethod;

@WebService
public class Echo {
public String echo(String input) {
return input;
}
@WebMethod(exclude=true)
public /*static*/ String helper(String input) { return input; }
}


Side note

You might think I'm working for the Apache project, the way I propose their products/projects here. No, I'm not, it's just a fact that "they" are developing open source Java projects for many purposes, from development support (log4j, ant, ...) over utilities (commons, ...) to enterprise technologies (tomcat, axis2).

Eclipse Galileo 3.5.0 as packages for Ubuntu Jaunty


~Yogarine

The eclipse packages delivered with ubuntu are usually very, very old (3.2.x on jaunty). This is mainly due to the rule of debian that everything(!) needs to be compiled by the maintainers. Also, they use a completely different Java compile setup than the eclipse developers - gcj (which is really open source) instead of Sun JDK.
I just found someone who maintains the eclipse-provided binaries as a set of packages for ubuntu jaunty.
https://edge.launchpad.net/~yogarine/+archive/eclipse
Quite easy to install and use - just note that the JEE tools are inside eclipse-wtp (web tools project).
It may be that there is stability problem ... I had one crash so far ... no idea whether this was related to the packages or the Java setup itself on my system (it was somewhere in the subversion->libsvnjavahl->libapr stuff).

Friday, February 22, 2008

Java, PDFRenderer, and the Importance of "Order"

There is a great Java package for displaying PDF files inside your Java application: PDFRenderer, developed as part of the java.net approach (javadesktop/swinglabs). Unfortunately, the order in which you do certain things is very important.
So, you need to do the following (in the Code):

  1. Create the JFrame, and create and add the PagePanel from PDFRenderer
  2. Show the JFrame (setVisible(true))
  3. Show the PDF page you want to show (PagePanel.showPage(...))

This seems trivial, is done this way in the samples, yet ... change the order, and the only thing you get is "no page seleceted".

  • setVisible before adding PagePanel: "no page selected"
  • setVisible after showPage: "no page selected"
  • adding PagePanel to a visible JFrame: "no page selected"
  • showPage in an invisble JFrame: "no page selected"
  • and so on ;-)

Great software, isn't it?
By the way, it can only show pdf version 1.4 (from Acrobat/Reader 5.0), and if there is a problem, you get an exception trace to System.err, yet no way to catch the exception ... the display is running asynchronously in a thread of its own.

Have fun!

Thursday, October 25, 2007

Unit Testing (1): Overview

First article of a series: Use unit testing with open source Java components, in the environment of Swing UIs, J2EE server components, database access (esp. hibernate), web applications, etc. Unit testing is an important part of Test Driven Development (TDD). Admittedly, I have mostliy ignored this topic up to now. Obviously, the overview I have over my own code was enough to detect, place and correct bugs; working with others' code, detecing errors was usually easy, leaving them to fix it ;-) Also, I was always of the opinion that "my" projects were not applicable for Unit Testing ... complicated UIs, enterprise architectures, complex databases, J2EE deployment, etc. Luckily, others have worked on developing frameworks for most of these purposes.

Test-Driven Development

First write the tests, then the structure of the class to implemented, then run the tests. They'll fail, as there is no implementation yet. So, do the coding, test it regularly, until the tests don't fail any longer ... finshed, sort of.

JUnit

JUnit is the most-used Java testing framework. There are so many good tutorials out there, so I don't see the need to write another one. Read one or more of
  • http://www.junit.org/
  • http://junit.sourceforge.net/
  • http://www.ibm.com/developerworks/library/j-ant/
  • http://www.torsten-horn.de/techdocs/java-junit.htm
In the following, I will use JUnit 4.4. Version 4 changed a lot of the usage of Test Cases and such, using Java 5 annotations.
  • http://www.frankwestphal.de/JUnit4.0.html
  • http://www.mm.informatik.tu-darmstadt.de/courses/helpdesk/junit4.html
  • http://radio.javaranch.com/lasse/2006/07/27/1154024535662.html
  • http://www.instrumentalservices.com/content/view/45/52/
I will also make use of the assertThat statement which was introduced with JUnit 4.4, because it makes much of the test code more readable, especially the error messages.
  • http://junit.sourceforge.net/doc/ReleaseNotes4.4.html

Sample

We write a simple utility for concatenating the textual representation of list elements, with a user-defined concatenation string. Having the list ("Hello", "world", "!"), CollectionUtils.collectionToString(list, ", ") should produce "Hello, World, !".

Unit Test for collectionToString

We start with the unit test.
public class  CollectionUtilsTest {
@Test public void testCollectionToString() {
 final List <String> list1 = Arrays.asList("Hello", "World", "!");
 final String comma = ", ";
 final String result1 = CollectionUtils.collectionToString(list1, comma);
 // we can check the complete string
 assertEquals("Hello, World, !", result1);
 // or the items
 for (String s: list1)
   assertThat(result1, containsString(s));
 // and, all items except that last, need to be followed by ", "
 Iterator  it = list1.iterator();
 while (it.hasNext()) {
   String s = it.next();
   if (it.hasNext())
     assertThat(result1, containsString(s+comma));
 }
}
}
assertEquals() is quite easy to understand, imported via import static org.junit.Assert.assertEquals, and compares its two parameters for equality. Usually, a first parameter should be added that contains the message to print, if the two values are not equal.

Code for collectionToString()

Of course, we also need the CollectionUtils class.
public class CollectionUtils {
// for the moment, we don't do anything
public static String collectionToString(List<?> list, String comma) {
 return null;
}
That's enough to run a unit test ... with eclipse, you just need to start either the test case class (CollectionUtilsTest above) with "Run as JUnit Test", or -- alternatively -- the whole project, which runs all unit tests in the selected package.

First test run

java.lang.AssertionError: expected:<Hello, World, !> but was:<null<
...
  at sbr.jut.demo.CollectionUtilsTest.testCollectionToString(CollectionUtilsTest.java:29)
...

Coding collectionToString

public static String collectionToString(Collection coll, String comma) {
StringBuilder sb = new StringBuilder();
String sComma = "";
for (String s: coll) {
  sb.append(sComma);
  sb.append(s);
  sComma = comma;
}
return sb.toString();
}
And, now, the unit test runs through ... until we start some demonic testing ;-)

Special test cases

Of course, null pointers and stuff need to be taken care of, especially ...
assertEquals("collectionToString(null, null)", "",
CollectionUtils.collectionToString(null, null));
assertEquals("collectionToString(null, null)", "",
CollectionUtils.collectionToString(Collections.EMPTY_LIST, null));
final String result2 = CollectionUtils.collectionToString(list1, "");
assertEquals("HelloWorld!", result2);
final String result3 = CollectionUtils.collectionToString(list1, null);
assertEquals("HelloWorld!", result3);
Nice, we start with the first NullPointerException
java.lang.NullPointerException
  at sbr.jut.demo.CollectionUtils.collectionToString(CollectionUtils.java:18)
  at sbr.jut.demo.CollectionUtilsTest.testCollectionToString(CollectionUtilsTest.java:45)
...
, start fixing our implementation, until we end with ... no NPE!
public static String collectionToString(Collection coll, String comma) {
if (coll==null)
  return "";
if (comma==null)
  comma = "";
StringBuilder sb = new StringBuilder();
...
}
So, that is enough for the beginning ...

Tuesday, October 16, 2007

Auto-Repeat of Server Calls

Problem: When doing client/server-programming, the client calls a function on the server -- EJB, RMI, Web-Services, etc., in a language such as Java. Sometimes, the connection to the server gets lost, as the server is restarted, redeployed, network was down and up again, etc. Then, the client's call to the server fails; after reconnecting, it should be possible to repeat the call and get the wanted result. Possibly, the reconnection will take some time, if the network has a longer "outing". How can we ensure that the call is done in any case, even if there are transient network/deployment problems? Solution 1: The client's Business Delegate (you have one, haven't you?) calls a "ping()" or another such method before calling the real business method on the server. If the connection is broken, catch the exception, try to reconnect, until such a ping goes through. Disadvantages:

  • doubles the number of c/s calls
  • if the ping succeeds, but the real call fails due to problems in this nano second, you're out of luck
Solution 2: Wrap the call to the server inside a runnable, and repeat the call until it succeeds. Requires a language like Java, that supports runnable concepts. Let's see ... some code, untested, out of thin air.
 protected IServer mServer;

public ResultObject businessMethod(final int intParam, final String stringParam)
    throws BusinessException {
 class BusinessMethodRunnable implements Runnable() {
   private ResultObject result;
   public void run() {
     // do the server call itself, and store the result.
     result = mServer.businessMethod(intParam, stringParam);
   }
   public ResultObject getResultObject() {
     return resultObject;
   }
 }

 BusinessMethodRunnable runnable = new BusinessMethodRunnable();
 // wraps the call, to ensure successful completion
 callMethod(runnable);
 return runnable.getResultObject();
}

protected void callMethod(Runnable runnable)
   throws BusinessException {
 // repeat, until the loop is left with return after a successful call
 while (true) {
   try {
     if (mServer==null)
       // should block until the connection has been established
       connectToServer();
     // do the real call here.
     runnable.run();
     return;
   }
   // a business exception needs to be passed to the calling code
   catch (BusinessException e) {
     throw e;
   }
   // a runtime exception also needs to be passed to the calling code ...
   catch (RuntimeExceptione ) {
     throw e;
     // alternatively:
     // throw new BusinessException("RuntimeException caught", e);
   }
   catch (Exception e) {
     logException(e);
     // connection down, no resources to be freed(?)
     mServer = null;
   }
 }
}

Thursday, August 16, 2007

Call-by-reference in Java; StringBuilder

Objects are always passed by reference to Java functions. Thus, any change to the objects are reflected after function return. Of course, changes to the object referencs (the variables themselves) are lost on return. This does not apply to primitives (int, boolean, float). Also, several classes, String, Integer, Double, Boolean, are immutables; thus, it is impossible to change them after construction. Thus, they cannot be used for call-by-reference (demonstration). StringBuffer, on the other hand, can nicely demonstrate this:

static void changeStringBuffer(StringBuffer sb) {
  sb.append(" and some more");
}
public static void main(String[] args) {
  StringBuffer sb("A text");
  changeStringBuffer(sb);
  // this one gives "A text and some more"
  System.out.println(sb.toString());
}
In place of StringBuffer, often the simpler an not-thread-safe class StringBuilder can be used. Swapping, though, does not work:
public static void swap(StringBuffer a, StringBuffer b) {
  StringBuffer c = a;
  a = b;
  b = c;
}
does not really do anything. BTW ... when concatenating Strings, it is better to use StringBuilder and .append, as
String s;
for (.;.;.) s += something; 
is pretty inefficient; for each +=, the String's content needs to be copied into a new instance that has a bit more space at the end for "something". Results in O(n^2) "efficiency", while StringBuilder only needs to get more memory when an internal limit is reached.

java.util.ArrayList != std::list

When using "lists" in Java, ArrayList is usally the choice. When using list contructs in C++, using std::list is usually not a good idea, as it is implemented as linked list, and therefore all indexed acesses (list[i]) take linear time, and an iteration such as

for (int i=0; i<list.size(); i++) {...}
takes O(n^2)! (Of course, one should not do this in StdC++/STL anyway, but use the iterators.) Thus, std::vector should be used in most cases. Only exception: regularly adding elements somewhere inside the list, which is far more efficient in a (doubly) linked list.

Wednesday, October 04, 2006

Eclipse quick-fixes and such

There are many refactoring and fixing tools in the eclipse environment. It really helps to have a look at them once, and find out when and how to best use them. The most important: Strg+1 Quickfix - shows a list of solutions when a warning (yellow line) or an error (red line) is selected. This also works when no error/warning is shown, but experience-based process support shows that, in most cases, the developer wants a certain task. Also: Press Strg+Space to complete any "name" - variables, functions, types, imports etc. Often, this also has some nice side effects - such as automatically importing a class when the name is completed this way. Others functions that should be looked at: (C-Control, S-Shift, A-Alt: CS+T -> "Ctrl+Shift T")

Quick fix C+1some of the possibilities offered
varname = value; // where "varname" does exist
Create field "varname"create varname as a field of the current class
Create local variable "varname"create varname as a local variable
''varname.methodname(param); // where methodname does not exist
Create Method "methodname" (in ...)create a method with the name and parameters in the appropriate class
Add Parameter in methodname (and others)Adjust the the formal parameters of methodname to conform to the given actual parameters. Includes removing, adding parameters, or creating a new method with the given ones.
Class errors:
Organize importsCS+Oremove unused or erroneous imports
Implement missing methodswhen a class does not yet implement methods required by an interface or an abstract base class
new String("Hallo"); // no variable assignment
Assign statement to new local variablecreate a new variable (usually called "string") and assign the new object.
Assign statement to new fieldcreate a new field (usually called "string")
Refactoring AS+TChange various "bad smells" in Software
RenameAS+Rrename a variable, class, method across all usages; also for package names
MoveAS+Vmove a method from one class to another, adjusting the calls (esp. for moving into member field classes, and for static methods). A delegate can be left.
Extract MethodAS+Mmake a method of the currently selected code fragment. Parameters and possibly return value are automatically determined; often other places of the same code fragment are also replaced.
Extract Local VariableAS+Lextract a local variable from the currently selected expression. Other uses of the expression in the same context are also replaced.
Inline VariableAS+IThe contrary to Extract local variable. The uses of a variable are inlined.
Extract ConstantExtracts a constant (final static) from the currently selected value, usually a "String"
Introduce ParameterIntroduces another parameter the current method, and all calls of it.
Source AS+SSource helpers
Toggle CommentCS+7Comment (out) the current lines
Override/Implement Methods
Generate Getters and Setters
Generate Constructor using Fields
Generate Constructors from Superclass
Surround withCS+Zfrom 3.2rc6(?) onwards, was part of "Source" before
Surround with try/catch

P

Invalid class exception

The following exception sometimes appears when working with serialization, especially in the case of EJB remote access (where Serializable classes, including Exceptions, are passed from server to client):

java.io.InvalidClassException: org.firebirdsql.jdbc.FBSQLException;
local class incompatible:
stream classdesc serialVersionUID = 3969094886006956637,
local class serialVersionUID = -3559440527871139169
This is always a warning that the library versions of this class differ between server and client.

Get the messages and/or the stack trace of an exception

While e.printStackTrace(); always writes onto stderr, there are also ways to get the full message of an exception, including all nested exceptions.

public static String getExceptionMessage(Throwable e) {
Throwable cause = e;
String sRet="";
do {
 sRet += "["+cause.getClass().getName() +"] ";
 sRet += cause.getMessage()+"\n";
 cause = cause.getCause();
} while (cause!=null);
return sRet;
}
to get the stack trace is even easier:
public static String getExceptionStackTrace(Throwable e) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(out);
e.printStackTrace(ps);
ps.flush();
return out.toString();
}
In some cases, it is necessary to treat certain exceptions specially. For example, the SQL exception that is raised in case of batch errors contains a special list for the various batch errors. The only way to get these errors is to check the type (of the nested exception), make an explicit cast, and list the batch errors manually.

Use Beans for data encapsulation

Use Beans for data encapsulation

Often, more than one value needs to be returned from a method. This might be especially the case with lists/collections, where each item is a tuple of various values. Solution: Use a simple java bean (that has nothing to do with Enterprise Java Beans, EJB) to encapsulate the values. A nested public static class can be used well for this. A bean is defined by Sun as a class that
  • has a default constructor (no parameters), and either
  • has only public fields, or
  • public getXXX and setXXX methods for all private/protected fields XXX.
By the naming convention, a "bean property" value can be either published as public String value; or public String getValue() {...} public String setValue(String value) {...} E.g., in the OPC database access, each data item contains a timestamp and a float value. In this case, setXXX methods are not necessary as the constructor does this work.
public class OpcDataConnection ...
public static class DataItem {
  private Date mDate;
  private float fValue;
  public Date getDate { return mDate; }
  public float getValue { return fValue; }
}
...
}
The same Beans are also used in many other cases in Java, e.g.
  • in jsp pages, such a bean can be directly accessed as property value dataItem.value, dataItem.date
  • such beans can be serialized and stored in an XMLEncoder

Log4j: Tipps and Tricks

Rolling log files w/o overwriting

When using the normal file appender, the log files grows indeterminately. When using the rolling file appender, the existing log file (of the current day) is overwritten on application restart. It should be possible to
  • use a file for each day the app is running
  • either append to the day's file, create a new file, or rename the day's file
before overwriting if the app is restarted.

Don't overwrite rolling file on startup

JBoss rolling file appender uses Append=false - this can be sensibly changed to not overwrite existing log files on startup Note: replace (, ), /) with the right XML parentheses.
(appender name="FILE" class="org.jboss.logging.appender.DailyRollingFileAppender"\)
(errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/)
 (param name="File" value="${jboss.server.log.dir}/server.log"/)
 (param name="Append" value="true"/)

 (!-- Rollover at midnight each day --)
 (param name="DatePattern" value="'.'yyyy-MM-dd"/)
[...]
It also works with the properties-based file:
log4j.appender.file.Append=true

Rename files before startup

When starting an app/server always with the same script, the log file can be moved out of the way before startup.

Rename files on startup

In the following code, the last log file is renamed to a date based pattern. Yet the pattern is based on the current date (the restart timestamp), not the original log file creation or its last entry. To use this, the logger must not be statically initialized in the main class, but after moving the file.
try {
String date = new SimpleDateFormat("yyyy.MM.dd-HH.mm").format(new Date());
// if log file already open, moving no longer possible ...
File file = new File(LOG4J_FILE_NAME+".log");
if (file.exists())
  file.renameTo(new File("LOG4J_FILE_NAME-"+date+".log"));
mLogger = Logger.getLogger(CurrentClass.class);
}
catch (IOException e) {...}
It might be possible to configure the name of the file the logger should use in the code, instead of the configuration file. This allows to set a filename manually (date pattern based) *before* the first log statement is printed and the log file thus opened. This might also require an explicit call to the ...Configurator. It will probably not work in combination with RollingFileAppender. Maybe there is no way around writing an appender (derived from RollingFileAppender) of our own?

DatedFileAppender

DatedFileAppender works in the same manner as the Tomcat FileLogger. Contrary to DailyRollingFileAppender shipping with log4j, log file names generated by DatedFileAppender always contain today's date. While this distinction seems minor, it means you can reliably copy, compress, remove or manipulate a day's log file shortly after midnight. With the DailyRollingFileAppender, a day's log file is not renamed until the first message is logged some time after midnight. http://minaret.biz/tips/datedFileAppender.html

Different log levels for stdout and file

Is there a possibility of using different log levels in log4j when logging onto stdout, and when logging into a file? The PropertiesConfigurator obviously does *not* support this, yet the xml configurator does. JBoss does this in its log4j.xml. From the log4j.dtd, no reference to such possibilities can be found. JBoss does the following in its xml configuration file:
(appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender")
(errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/)
(param name="Target" value="System.out"/)
(param name="Threshold" value="INFO"/)
[...]
This also works with the properties configuration file:
log4j.appender.stdout.Threshold=INFO

Jakarte Commons Primitives (de)

Jakarta Commons Primitives enthält eine Reihe von Collections - v.a. List, Array etc. - für die primitiven Datentypen von Java. Sicherlich schneller im Zugriff bei vielen Elementen als List und entsprechende, weil die Umwandlung Klasse <-> primitiver Type wegfällt. http://jakarta.apache.org/commons/primitives/ Aus Performance-Gründen sollte man die Objekt-Kapselungen der primitiven Datentype (also Integer, Float, Double) nur verwenden, wenn es nicht anders geht - und schon gar nicht in größeren Mengen (sprich Listen, array[] etc.).