|
|
||
Andreas Schaefer's BlogProgramming ArchivesConvenience kills the CatPosted by schaefa on November 09, 2005 at 10:55 AM | Permalink | Comments (4)This week I created a test suite for a project I am currently working on and a coworker wanted to run the same tests but no matter what we did defining the junit task in the Ant build script failed. The script just reported: taskdef A class needed by class org.apache.tools.ant.taskdefs.optional.junit.JUnitTask even tough we added junit.jar in the classpath in the junit's taskdef.. After a search on the web I figure out that a long time ago I put junit.jar into the Ant's lib directory and now forgot to tell my coworker about it. The reason for that is that the classes for the Ant's junit task is in the archive ant-junit.jar and that is placed by default in the Ant's lib directory. So the class loader of ant will have the junit task put is not able to find the junit classes because Ant does not bundle the junit.jar archive together. Now even when I put the junit.jar in the taskdef's classpath the Ant's class loader is not able to find the junit classes because junit.jar is only available to a child class loader. There are only two ways to fix that:
In my opinion both solution are bad because it requires human interaction and the user is maybe not aware of the problems that go along with each solution. Solution 1 does look in the version of jUnit that can be used even when another Ant script wants to use a newer version. Solution 2 maybe breaks other scripts that expect that both archives are in Ant's lib directory and does not add both archives to the taskdef's classpath. The best solution in my opinion would be that all optional tasks that need another library are not placed into the Ant's lib directory so that they are not loaded by the Ant's class loader. Ant's distribution could have them in a separate directory available for scripts to use. Now in the jUnit's taskdef one could add the ant-junit.jar from the Ant distro along with the desired junit.jar. This way there is not human interaction needed and the scripts can choose the library they want to use rather than relying on the user to select the right one to be put in Ant's lib directory. Of course scripts that do rely on the fact that these archives are placed in Ant's lib directory would need to be adjusted but that would be a one time task rather than spending hours later to figure out why the junit tasks fails in certain environments or after someone upgraded to a newer version of Ant. Once again convenience has proven once more, at least to me, that on the long haul it uses up more time solving the problems it causes than what it actually saves in the first place. I think that it is much better to fail fast rather then letting a problem lurk under the surface and then it bites you from behind at the probably most inconvenient time. Have fun - Andy How to do Conditional Compilation with JavaPosted by schaefa on January 20, 2005 at 04:50 PM | Permalink | Comments (18)These instructions are a way to do conditional compilation with Java like the C/C++ #ifdef. In Java there is no preprocessor and so we need to work around this missing feature. This work around is using Ant's copy and filter feature to create the source with the different code in it. In this example I wanted to accomplish the following:
1. Add into your Java classes a start tag (like //[ifdef]) and an end tag (like //[enddef]) around the code in question. To include code for version 1: //[ifdef] import java.sql.ParameterMetaData; //[enddef]or
//[ifdef]
public byte[] getBytes(String parameterName)
throws SQLException {
...
}
//[enddef]
The // at the beginning of the tag ensures that this is still valid Java source code.To exclude code:
/* //[endef]
public byte[] getBytes(String parameterName) {
...
}
//[ifdef] */
2. To swap the used code for version 2 the start and end tag just have to be set to /* respectively */. In this case the included code is excluded and the excluded code in included. 3. Add a copy-n-filter task in your Ant build script. There the source coded will be copied away and the filter tags are replace with the actual value. For version 1 the start / end tag will vanish and for version 2 they will be substituted with /* and */. Attention: the source code is copied into two different root directory one for version 1 and the other for version 2. Because Ant tries to avoid copies if the file does not have changed this can lead to having the wrong version of code in your target directory. This is an Ant script snippet:
<copy todir="${src.dir}/${version}">
<fileset dir="${src.dir}/java">
<include name="**/*.java"/>
</fileset>
<filterset begintoken="//[" endtoken="]">
<filter token="ifdef" value="${ifdef.token}"/>
<filter token="enddef" value="${enddef.token}"/>
</filterset>
</copy>
4. Set the start / end tag token. Note that the start / end tag token are set at the end to their default value only when not already set.
<condition property="ifdef.token" value="/*">
<equals arg1="${compile.to.version.1}" arg2="false"/>
</condition>
<condition property="enddef.token" value="*/">
<equals arg1="${compile.to.version.1}" arg2="false"/>
</condition>
<!-- If not set already make sure that they are defined but empty -->
<property name="ifdef.token" value=""/>
<property name="enddef.token" value=""/>
If the Ant script is started without compile.to.version.1 set to false it will compile the code to version 1. If the parameter is set to false it will compile to version 2. This can be accomplished this way:
ant -Dcompile.to.version.1=false build 5. Make sure that you compile from the right directory:
<javac ...
>
<src path="${src.dir}/${version}"/>
</javac>
I hope this will help you in the future – Andy JCA 1.5: Choices are not Always a Good ThingPosted by schaefa on September 09, 2004 at 04:44 PM | Permalink | Comments (0)In JCA 1.5 Inbound Connection (IC) is added allowing developers to invoke Message Driven Beans (MBD) with other types of messages than JMS like emails, files etc. When a MDB is deployed using an IC the application server is calling endpointActivation() on the Resource Adapter (RA). This is the point when a RA can start sending messages to the MDB. The application server is providing a Message Endpoint Factory (MEF) to the RA so that it can create Message Endpoints (ME) acting as a proxy of the MDB to be invoked. This proxy implements the interface of the MDB and so works like a local interface of a Stateless Session Bean (SLSB). Because the MDB works more or less like a SLSB MDB instances are pooled and used only for the duration of an invocation on the interface. So an invocation of a MDB could be delayed if there is no MDB instance available in the pool. The JCA specification leave the application server the choice to either throw an exception when no instance is available when the ME is created or to block the invocation on the ME. But this leaves the RA developer in limbo and is quit a headache also due the inability of the specification to provide enough information to separate an empty pool for another, maybe permanent, failure. When a RA creates an Endpoint on the MEF it can throw an UnavailableException if something goes wrong but it has no information if this is a permanent or temporary failure that is vendor neutral. So, for example SunOne, is throwing immediately an UnavailableException when the MDB pool is depleted. Personally, I think this is not a good thing because a depleted pool is a natural state of a pool and not an exception. Other application server block the invocation on the ME until a MDB instance becomes available preventing the RA to react on a depleted pool. I would like to see some changes on the MEF/ME specification:
Maven: 'I love you' afterallPosted by schaefa on June 15, 2004 at 02:51 PM | Permalink | Comments (6)Correction: At the bottom of my weblog I complained that I cannot redistribute JAXB with my project forcing others to download and install JWSP. Ryan Shoemaker from JavaSoft told me that this is not correct and an updated FAQ entry about this is made available. I am glad to hear this and hope that JAXB can be found on the Maven repository soon. I hope that this confusion helped to clarify this important issue and I want to thank Ryan for his valuable feedback. The first time I saw Maven I did not like it at all. It seemed to be a huge, complex and unfinished project. But somehow I could convince myself to try it out in my very own JDoppio project. So I checked out the Maven website documentation and wrote the initial project descriptor. Now I just had to write the code, jUnit tests and was ready to run the project. So instead of writing an Ant script taking me roughly around one hour I wrote the project descriptor in ten minutes without loosing any features. Then I decided to split up the project into multiple sub projects and found some existing projects using Maven's multi-project tool like Turbine. This took a little bit longer to understand the multi-project but to write the sub projects was quick and easy as before. After that I needed to import sub projects into other sub projects which was easy using the local repository and the dependencies in the project descriptor. Using JAXB made it mandatory to add my own archives to the local repository. Finally using properties in the project descriptor allowed me to add certain archives to a class path or to copy them into the test environment to run the JDoppio server standalone. So every requirements by my project could be resolved by Maven very elegant without making it complex. The biggest challenge to me was to find help on problems I wanted to solve with Maven. The first stop was their website but it only works for simple questions. But then I discovered that looking into Maven plug ins and their project descriptors and Jelly scripts provided me with a wealth of information and every time I look into a different plug in I find new ways to solve a problem. It also helps to look into other open-source projects using Maven and their project and extension (maven.xml) descriptors to see how they solved a problem. The only problem I found so far was some buggy plug ins which I either did not care about or got the newest version from CVS to solve an issue. Otherwise I am convinced that using Maven is a real time saver and if you flexible it can be used in most projects I can think off. Have fun Andy P.S.: Can someone explain to me why Sun does not allow JAXB to be distributed freely and I have to bug all other developers interested in my project to download and install Java Web Services Developer Package to just get this archives? As if only web service developer would be the only ones interested in JAXB. Sometimes I am really wondering why Sun cannot stop making our lives miserable even thought they are using open-source software in their distribution as well. So Scott, please could you prevent JAXB from becoming the next Java on Linux issue where it took Sun years until they went along with the developer community. Debuggers: a modern 'Dr. Jekyll and Mr. Hyde'Posted by schaefa on December 02, 2003 at 02:16 PM | Permalink | Comments (5)I have to admit that I only use a debugger if someone wants to show me a problem he discovered within his debugger. Other than that I never used a debugger since I started to code in Java even thought I used debuggers before in C and C++. But when I started with Java there were no debuggers and so I have to rely on debugging statements and stack traces. When the first useful debuggers became available I had to switch between multiple OSs that, of course, one or more of them were not supported, yet. Finally, today, where many excellent debuggers are available but I really do not need them anymore and even think they do more harm than good. Dr. Jekyll or the debugger as useful tool can easily turn into a Mr. Hyde or a time sink if misused or overused. Beside that for certain problems a debugger is a great tool it prevents many developers from focusing on the real problem that their code is plain buggy and that they have no clue where to look for. Stepping through a program only works well when the developer can remember where he came from and where he is heading to. But most of the time people lose that and when they found the problem they do not know how they got there in the first place and so the have to step through multiple times until they understand what caused the problem and how to fix it. A much better way is to look at your code, log output and, if you have, your test cases to localize your problem area and then focus on this area. For me this does mostly lead to a solution and I do not need a debugger anymore. With an AOP framework and a decompiler I can also debug third party library without a debugger. You might think that I do not have to debug much and hardly have to deal with unknown code. As a J2EE application server developer I have to deal with many third party libraries, deployed application that are written in the company but also by customers and therefore I spend half of my time debugging code to find the problems and to fix it or to suggest a solution. A debugger is like a telescope looking at the night sky and you have to find the North Star. With the naked eye you will find it pretty easily even when you have to remember that the rear leg of the Big Bear directs to it. The telescope needs to be directed pretty closely to the target otherwise you will miss it and waste a lot of time. Actually that would not be so bad but it prevents you also from learning the big picture of the night sky and to navigate easily through all the stars and nebulas. In addition a debugger can only work when program is not working as expected and therefore does not help in any way to prevent a bug. A debugger does not or barely work with race conditions (multi threading), class loading issues, network problems or any other runtime issues. Here some tips how programs can be debugged without a debugger:
| ||
|
|