<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1251111456079579036</id><updated>2012-01-13T14:17:15.315+01:00</updated><category term='graphics'/><category term='gimp graphics photo'/><category term='technology'/><category term='performance'/><category term='wsdl'/><category term='testng'/><category term='java odbc'/><category term='ejb'/><category term='java'/><category term='java security'/><category term='muse'/><category term='richfaces'/><title type='text'>QE Café</title><subtitle type='html'>Café Corner on (Java) Software Quality Engineering</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-1176608650873860361</id><published>2012-01-07T18:39:00.004+01:00</published><updated>2012-01-07T18:52:51.255+01:00</updated><title type='text'>Byteman plays with Drools</title><content type='html'>&lt;p&gt;Due to my recent suspicion that there is a bug in &lt;a href="http://www.jboss.org/drools"&gt;Drools&lt;/a&gt; I needed to monitor its guts in detail. To be more specific, I needed to see what is in the working memory after execution of all rules.&lt;/p&gt;
&lt;p&gt;Debbuger was not a good option since there were hundruds of invocations of the problematic part and I needed to get overview of quite a large amount of data. If I inly could store all the data for each invocation in a file and then grep through it.&lt;/p&gt;
&lt;p&gt;But wait! Of course I can. &lt;a href="http://www.jboss.org/byteman"&gt;Byteman&lt;/a&gt; will help me!
The identified point in source code was execution of &lt;em&gt;fireAllRules()&lt;/em&gt; in &lt;em&gt;org.drools.common.AbstractWorkingMemory&lt;/em&gt;. Ideally, just before return from the method. So here is the corresponding rule:&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
RULE Debug fireAllRules
HELPER org.drools.planner.examples.tournaments.helper.BytemanHelper
CLASS ^org.drools.common.AbstractWorkingMemory
METHOD fireAllRules
AT EXIT
IF TRUE
DO
  printWorkingMemory($0.getKnowledgeRuntime());
ENDRULE
&lt;/pre&gt;
&lt;p&gt;Just a few notes to it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;^&lt;/em&gt; means to apply to child classes as well&lt;/li&gt;
&lt;li&gt;&lt;em&gt;$0&lt;/em&gt; refers to &lt;em&gt;this&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
As you can see there is a custom helper class to print the working memory content since Byteman rules are little bit limited in the supported Java syntax.
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
import org.drools.impl.StatefulKnowledgeSessionImpl;
import org.jboss.byteman.rule.Rule;
import org.jboss.byteman.rule.helper.Helper;

public class BytemanHelper extends Helper {
   protected BytemanHelper(Rule rule) {
      super(rule);
   }
   
   public void printWorkingMemory(Object obj) {
      StatefulKnowledgeSessionImpl session = (StatefulKnowledgeSessionImpl) obj;
      debug("vvvvvvvvvvvvvvvvvvvvvvvvvvv");
      debug(session.toString());
      for (Object o: session.getObjects()) {
         debug(o.toString());
      }
      debug("^^^^^^^^^^^^^^^^^^^^^^^^^^^");
   }
}
&lt;/pre&gt;
&lt;p&gt;And now I was able to get some nice output of individual working memories! So the resulting bug is &lt;a href="http://issues.jboss.org/browse/JBRULES-3337"&gt;JBRULES-3337&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-1176608650873860361?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/1176608650873860361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2012/01/byteman-plays-with-drools.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/1176608650873860361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/1176608650873860361'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2012/01/byteman-plays-with-drools.html' title='Byteman plays with Drools'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-7863084997212625877</id><published>2011-12-04T11:57:00.010+01:00</published><updated>2011-12-08T23:42:33.410+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gimp graphics photo'/><title type='text'>My Gimp Magic</title><content type='html'>I'm a Linux user (distribution-agnostic) so I have to &lt;a href="http://www.google.com/search?q=Operating+Systems+and+Airlines"&gt;bolt my seat down in the airplane&lt;/a&gt; but once done, it is really comfortable. The same thing applies to Gimp. Today I spent some time with it on a fresh installation and found out all the good plugins I ever used. The important point here is that there are only three of them to do what I really need. And, of course, all of this can be done manually in a clean Gimp installation but it might take ages.

&lt;h3&gt;Contrast Blending aka HDR Photography&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/High_dynamic_range_imaging"&gt;High dynamic range imaging&lt;/a&gt; is a set of techniques that allow displaying images with big differences between dark and light parts on a limited device. A limited device is a usual computer screen or a printed image. None of these media can fully display the range that a human eye is able to see. So we need to make a compromise in the scene.&lt;/p&gt;
&lt;p&gt;
There is &lt;a href="http://tir.astro.utoledo.edu/jdsmith/code/exposure_blend.php"&gt;a great Gimp plugin and tutorial&lt;/a&gt; for HDR blenging. The basic principle is to take three pictures with different exposure values (dark, normal and bright) and mix them together. A good algorithm can do that pretty easily for you. A sample picture can be seen below. In the left upper corner, there is the dark exposure. In the upper right corner, there is the normal exposure, the bright exposure is placed at lower left, and, eventually, the result image is at lower right. Note that you can see the background, while there is the candle wick still visible below the light.&lt;/p&gt;
&lt;img src="http://www.marvec.org/blog/hdr-blend.jpg" class="aligncenter" alt="HDR Photo" /&gt;

&lt;h3&gt;Layer Effects&lt;/h3&gt;
&lt;p&gt;In Photoshop, layer effects are built-in. These effects can do some easy manipulation with the image and is one the most criticised lacks of Gimp. Fortunately, there is &lt;a href="http://registry.gimp.org/node/186"&gt;a plugin&lt;/a&gt; that can be easily installed and works pretty much the same way.&lt;/p&gt;
&lt;img src="http://www.marvec.org/blog/layer-effects.jpg" class="aligncenter" alt="Layer Effects Demo" /&gt;

&lt;h3&gt;Shadows and Highlights&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://registry.gimp.org/node/116"&gt;This plugin&lt;/a&gt; allows you to manipulate dark and light parts of the scene. It can automatically extract these parts into new layers and by using the layer opacity you can configure the light in shadows and darken the bright parts.&lt;/p&gt;
&lt;p&gt;This is not such a miracle, but it is very useful in &lt;a href="http://en.wikipedia.org/wiki/IR_photography"&gt;infrared (IR) photography&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;IR Photography&lt;/h3&gt;
&lt;p&gt;The biggest issue with IR photography is that usual DSLR cameras have a fixed built-in IR filter before the image chip. This is to avoid unwanted light. But for IR photos we want it! The solution (except for camera disassembly or buying Sigma SD14 with removable filter) is to increase exposure period. It can take several minutes to get enough light with an IR filter on your lens.&lt;/p&gt;
&lt;p&gt;Now, when we have a photo, how to process the &lt;em&gt;red scene&lt;/em&gt; we obtained? There is a great &lt;a href="http://www.shotaddict.com/tips/article_How+To+Post+Process+Your+Infrared+Digital+Photos.html"&gt;Photoshop IR tutorial&lt;/a&gt;. But I wanted to do that in Gimp. There is &lt;a href="http://digital-photography-school.com/forum/post-processing-printing/78874-infrared-photography-post-processing.html#post674036"&gt;a tutorial in a forum&lt;/a&gt; that resembles the Photoshop procedure. To summarize that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Realize what is in individual color channels - red is brightness, green is sharpness, blue is noise.&lt;/li&gt;
&lt;li&gt;In Gimp go to Colors, Levels and try Automatic or set a reference white point (which is something that produces most IR light - a green leaf on a sun for instance). You can also setup individual channels as you like.&lt;/li&gt;
&lt;li&gt;In Gimp select Colors, Components, Channel mixer and switch the red and the blue channels. This is done by setting 100% for blue and 0% for red with the red input channel and vice versa for the blue input channel.&lt;/li&gt;
&lt;li&gt;Now is the best time for the &lt;em&gt;Shadows and Highlights&lt;/em&gt; plugin.&lt;/li&gt;
&lt;li&gt;Finally, you can try Colors, Hue/Saturation and add a little bit of Hue (+15 - +24) and possibly add some Saturation as well.&lt;/li&gt;
&lt;li&gt;Bonus step is to open Colors, Curves or Colors, Levels and fine tune the image colors.&lt;/li&gt;
&lt;/ol&gt;
&lt;img src="http://www.marvec.org/blog/ir-photo.jpg" class="aligncenter" alt="IR Photo" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-7863084997212625877?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/7863084997212625877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2011/12/my-gimp-magic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/7863084997212625877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/7863084997212625877'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2011/12/my-gimp-magic.html' title='My Gimp Magic'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-71147883060650666</id><published>2011-05-17T16:15:00.005+02:00</published><updated>2011-07-12T17:21:56.739+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java odbc'/><title type='text'>Accessing ODBC from Java</title><content type='html'>&lt;p&gt;Connecting to an ODBC database from Java can be a real nightmare. Most &lt;a href="http://www.google.com/search?q=odbc+from+java"&gt;solutions suggest&lt;/a&gt; using a JDBC-ODBC bridge. So what are real possibilities here? Native JDBC-ODBC bridge by Sun/Oracle &lt;em&gt;sun.jdbc.odbc.JdbcOdbcDriver&lt;/em&gt;. Well, there are some limitations like the number of concurrent connections and poor performance. I was not able to find any free (ideally open source) JDBC-ODBC bridge. There are multiple vendors but only one seems to have a de facto standard - Easysoft. They provide trial version of their bridge so you can try the solution before you buy it. Here we realized some troubles in Java Virtual Machine consuming too much memory. I do not want to blame the bridge. It was on a separate machine but we are not able to debug it and see how it works. So not being opensource killed Easysoft's chance to get a new customer.&lt;/p&gt;
&lt;p&gt;After all I decided to write a small Java client that would be able to access an ODBC database. We needed just some basic querying capabilities anyway. But this is a little tricky, there is no ODBC communication protocol specification. Eventually, I decided to use unixODBC library using JNI. And here is beginning of the story.&lt;/p&gt;
&lt;p&gt;
First I designed a client for accessing the database. I had some previous ODBC API knowledge so I designed the client in order to write minimum code in C.&lt;/p&gt;
&lt;p&gt;
A design note: I failed passing database handles (type void*) between C and Java, so I created an array to store real handles in the C library and pass just an index to the array. This requires tha Java part to remember which handles have been used. There definitely exist a more sophisticated solution but I wanted to query an ODBC database at first. Also note that all data are returned as &lt;em&gt;String&lt;/em&gt;s for simplicity. There is also a shor &lt;em&gt;main()&lt;/em&gt; method to test the client.&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
package org.marvec.odbc;

public class OdbcClient {
   
   private static SortedSet&lt;Integer&gt; usedHandles = new TreeSet&lt;Integer&gt;();
   private int handle;
   
   public native void connect(String connection) throws IOException;
   public native void execute(String statement) throws IOException;
   public native int getNumCols();
   public native ColumnMetadata getColMetadata(int col);
   public native boolean fetch();
   public native String getColData(int col) throws IOException;
   public native void freeStatement();
   private native void close();
      
   public OdbcClient() throws IOException {
      int i = 0;
      while (usedHandles.contains(i) &amp;&amp; i &lt;= 1024) {
         i++;
      }
      if (i == 1024) {
         throw new IOException("All handles are currently in use. Try to free some handles by disconnecting from ODBC.");
      }
      usedHandles.add(i);
      handle = i;
   }

   public void disconnect() {
      close();
      usedHandles.remove(handle);
   }

   public static class ColumnMetadata {
       public String name;
       public int type;
       public long length;
       public int digits;
       this.nullable = nullable;

       public String toString() {
          return name + ": " + type + "(" + length + ")" + "[" + digits + "]" + (nullable ? "*" : "");
       }
   }

   public static void main(String... args) throws Exception {
       System.loadLibrary(args[0]);
       OdbcClient c = new OdbcClient();
       c.connect("DRIVER={PostgreSQL64};DATABASE=myodbcdb;SERVER=localhost;PORT=35432;Uid=admin;Pwd=admin;");
       c.execute("select * from persons where person_id &lt; 1000");
       System.out.println("Columns: " + c.getNumCols());
       for (int i = 1, j = c.getNumCols(); i &lt;= j; i++) {
           ColumnMetadata meta = c.getColMetadata(i);
           System.out.println("Column " + i + ": " + meta);
       }
       while (c.fetch()) {
           for (int i = 1, j = c.getNumCols(); i &lt;= j; i++) {
               System.out.print(c.getColData(i) + (i == j ? "\n" : ", "));
           }
       }
       c.freeStatement();
       c.disconnect();
   }
}
&lt;/pre&gt;
&lt;p&gt;
After compilation, I neede javah utility to obtain a C header file (.h).
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
javah -jni org.marvec.odbc.OdbcClient
&lt;/pre&gt;
&lt;p&gt;
Now the hard C part begins. I'm not a C guru and my compiler reports many warnings about my code. However, it compiles and works. First I copied &lt;em&gt;org_marvec_odbc_OdbcClient.h&lt;/em&gt; to &lt;em&gt;org_marvec_odbc_OdbcClient.c&lt;/em&gt; and added the shared handle storage to the header file as well as necessary includes. As you can see, we need to remember three different handles for each connection.
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
#include &lt;sql.h&gt;
#include &lt;sqlext.h&gt;
...
SQLHENV env[1024];
SQLHDBC dbc[1024];
SQLHSTMT stmt[1024];
&lt;/pre&gt;
&lt;p&gt;You might find me wasting some memory but you know, in Java world, there is always enough memory... I will show you only some parts of the solution, link to a complete package is at the end of this post. The most difficult function is getting column metadata that requires creating a new Java object from C.&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
JNIEXPORT jobject JNICALL Java_org_marvec_odbc_OdbcClient_getColMetadata(JNIEnv *jnienv, jobject obj, jint col) {
    int h = getStaticHandle(jnienv, obj);
    SQLSMALLINT nameLength, dataType, decimalDigits, nullable;
    SQLULEN colSize;
    jstring jstr;
    char name[512];
    
    SQLDescribeCol(stmt[h], (SQLUSMALLINT) col, name, sizeof(name), &amp;nameLength, &amp;dataType, &amp;colSize, &amp;decimalDigits, &amp;nullable);

    jstr = (*jnienv)-&gt;NewStringUTF(jnienv, name);

    jclass clazz;
    jmethodID cid;
    jobject meta;

    clazz = (*jnienv)-&gt;FindClass(jnienv, "org/marvec/odbc/OdbcClient$ColumnMetadata");
    cid = (*jnienv)-&gt;GetMethodID(jnienv, clazz, "&lt;init&gt;", "(Ljava/lang/String;IJIZ)V");
    meta = (*jnienv)-&gt;NewObject(jnienv, clazz, cid, jstr, dataType, colSize, decimalDigits, (jboolean) (nullable == SQL_NULLABLE));

    return meta;
}
&lt;/pre&gt;
&lt;p&gt;In some problematic methods I also check for errors using another utility library I mostly copied from &lt;a href="http://java.net/projects/jinput/"&gt;Jinput project&lt;/a&gt; (see function &lt;em&gt;throwIOException()&lt;/em&gt; for example).&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
JNIEXPORT void JNICALL Java_org_marvec_odbc_OdbcClient_connect(JNIEnv *jnienv, jobject obj, jstring conn) {
    SQLRETURN ret;
    jbyte *str;
    int h = getStaticHandle(jnienv, obj);
    char error[10240];

    jclass cls = (*jnienv)-&gt;GetObjectClass(jnienv, obj);

    str = (*jnienv)-&gt;GetStringUTFChars(jnienv, conn, NULL);

    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &amp;(env[h]));
    SQLSetEnvAttr(env[h], SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
    SQLAllocHandle(SQL_HANDLE_DBC, env[h], &amp;(dbc[h]));
    ret = SQLDriverConnect(dbc[h], NULL, str, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);

    if (!SQL_SUCCEEDED(ret)) {
        extractError(dbc[h], SQL_HANDLE_DBC, error, sizeof(error));
        throwIOException(jnienv, "SQLDriverConnect failed with return value %d:\n%s", ret, error);
    }

    (*jnienv)-&gt;ReleaseStringUTFChars(jnienv, conn, str);
}
&lt;/pre&gt;
&lt;p&gt;
Now there are some dependencies in the C project. You must have installed the following libraries in your system:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;unixODBC&lt;/li&gt;
&lt;li&gt;unixODBC-dev&lt;/li&gt;
&lt;li&gt;some ODBC driver for your target database like odbc-postgresql&lt;/li&gt;
&lt;li&gt;libltdl&lt;/li&gt;
&lt;li&gt;and some common C libraries that are likely to be already present on your computer: pthread, dl&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Now you must configure ODBC to provide you the driver (see the first part of the connection string &lt;em&gt;DRIVER=&lt;/em&gt;). This is done in /etc/odbcinst.ini and we can configure both 32- and 64-bit versions:
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
[PostgreSQL]
Description     = PostgreSQL driver for Linux &amp; Win32
Driver          = /usr/lib/odbc/psqlodbca.so
Setup           = /usr/lib/odbc/libodbcpsqlS.so

[PostgreSQL64]
Description     = PostgreSQL driver for Linux &amp; Win32
Driver          = /usr/lib64/odbc/psqlodbca.so
Setup           = /usr/lib64/odbc/libodbcpsqlS.so
&lt;/pre&gt;
&lt;p&gt;
To compile the C library I created a small &lt;em&gt;Makefile&lt;/em&gt;:
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
CC=gcc
CFLAGS=-shared -fPIC -w -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
PROJECT=org_marvec_odbc_OdbcClient

all: $(PROJECT).so

$(PROJECT).so: $(PROJECT).c
        $(CC) $(CFLAGS) util.c $(PROJECT).c -o $(PROJECT).so -lodbc -lpthread -lltdl -ldl
        ln -sf $(PROJECT).so libjavaODBC.so

clean:
        rm $(PROJECT).so libjavaODBC.so
&lt;/pre&gt;
&lt;p&gt;
Note the creation of a symbolic link. Java loads libraries on library path with standard name &lt;em&gt;lib[name fo the library].so&lt;/em&gt; and only the library name is what you pass as an argument to &lt;em&gt;System.loadLibrary()&lt;/em&gt;.
&lt;/p&gt;
&lt;p&gt;
Now to run the client just call:
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
java -Djava.library.path=. org.marvec.odbc.OdbcClient javaODBC
&lt;/pre&gt;
&lt;p&gt;
Feel free to download the &lt;a href="git://github.com/marvec/java-odbc.git"&gt;complete source code at github&lt;/a&gt;. The code is provided as is, I do not take any responsibility for any damage it might cause to anybody or anything (including hardware, software, people, animals, etc). For instructions see &lt;a href="http://community.jboss.org/wiki/ODBCClientInJava"&gt;JBoss Community document&lt;/a&gt;.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-71147883060650666?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/71147883060650666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2011/05/accessing-odbc-from-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/71147883060650666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/71147883060650666'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2011/05/accessing-odbc-from-java.html' title='Accessing ODBC from Java'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-7532308631834020815</id><published>2010-06-26T11:52:00.004+02:00</published><updated>2010-06-26T12:22:17.775+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java security'/><title type='text'>Invalid signature file digest for Manifest main attributes</title><content type='html'>&lt;p&gt;
Because of some obvious reasons, security is a must when it comes to computers nowadays. I am not much into security but I had to deal with it anyway. Last couple of days I worked with signed JAR files, when my Java compiler suddenly said: "Invalid signature file digest for Manifest main attributes".
&lt;/p&gt;
&lt;p&gt;
It was because some JAR files were not signed correctly since I needed to remove signatures and my automated tool for signatures removal was broken. Fine, but which files are in a bad condition? I was not able to make my compiler tell me. My class path was like 10kB of text and the day was almost over...
&lt;/p&gt;
&lt;p&gt;
Signatures and certificates in a JAR file are in the &lt;tt&gt;META-INF&lt;/tt&gt; directory. These are files with &lt;tt&gt;.SF&lt;/tt&gt;, &lt;tt&gt;.DSA&lt;/tt&gt;, and &lt;tt&gt;.RSA&lt;/tt&gt; extensions. All one need to do to "unsign" a JAR file is to delete those files. Note that, some information are in &lt;tt&gt;MANIFEST.MF&lt;/tt&gt; as well but it is not necessary to remove them until you want to sign the JAR file again. 
&lt;/p&gt;
&lt;p&gt;
It is pretty straight forward so what can be wrong? It was my bad, I assumed that all JAR files in my application use the same certificate file. I did not delete all &lt;tt&gt;.RSA&lt;/tt&gt; files but just something like &lt;tt&gt;PRODUCT.RSA&lt;/tt&gt;.
&lt;/p&gt;
&lt;p&gt;
But it took me a while to realize what is wrong. And here is a command that can help you to recognize a broken JAR file:
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
find -name *.jar -exec echo {} \; -exec jarsigner -verify {} \;
&lt;/pre&gt;
&lt;p&gt;
It is definitely a pity that Java compiler (Sun JDK 1.6) does not print out the problematic file name.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-7532308631834020815?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/7532308631834020815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2010/06/invalid-signature-file-digest-for.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/7532308631834020815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/7532308631834020815'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2010/06/invalid-signature-file-digest-for.html' title='Invalid signature file digest for Manifest main attributes'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-7083911034915680529</id><published>2010-04-02T18:41:00.002+02:00</published><updated>2010-04-02T19:12:27.567+02:00</updated><title type='text'>"Always avoid working with tools that have a helve"</title><content type='html'>&lt;p&gt;My daddy told me, son, always try to avoid working with tools that have a helve. I succeeded, I would say. I do not have to work with such tools. At least not at a daily basis. I work as a software engineer. I work mainly with intellectual property. But sometimes I feel like I am working just because of those tools.&lt;/p&gt;
&lt;p&gt;Just imagine your only job was to make a better hammer. I believed that a hammer proved to be optimal over the years. It is a mean of achieving a more complicated result. But all those software engineers working on operating systems or application middleware try to enhance tools for computer users or application developers all day long.&lt;/p&gt;
&lt;p&gt;The software engineers use another tools to make tools for you. Those another tools like compiler must have been developed by another engineers. But this is not what I wanted to talk about...&lt;/p&gt;
&lt;p&gt;The software engineers tend to think too much about their tools. It is good to know your tool, of course. But it should not be recognizable which tool you used. Usually, you cannot recognize a 9mm chisel trace on a sculpture. You should not design according to the tools you plan to use.&lt;/p&gt;
&lt;p&gt;I keep asking myself how difficult is to master a programming language. Is it that easy? Is it just a syntax sugar you need to know? Let's take Java as an example. There are too many pitfalls you must know to understand complicated code clearly - thread local variables, dynamic proxy, anonymous inner classes. You can make sure that you do not know the language perfectly, just google &lt;a href="http://www.google.cz/search?q=sample+scjp+questions"&gt;sample questions for the Sun Certified Java Programmer exam&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I started programming in Java around 2001. I was able to develop my applications easily without studying many guides. I did not know almost nothing but the language grammar. Now, almost 10 years later, I feel like I know intuitively 95% of the language (some percents were gained very very hard).&lt;/p&gt;
&lt;p&gt;And what now? After all, Java is just a tool. Like a software engineer's hammer. It is definitely less than 1% of my knowledge needed to do my job correctly. So big on one side and so small on the other side. What is the right side?&lt;/p&gt;
&lt;p&gt;My biggest dilemma is whether I should ask for language specific details when having an interview with a possible new employee at my company. Or should I ask more sophisticated questions? "What are basic properties of each transaction?" or "What is an application server?". And what about assembler? Everything that works need assembler!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-7083911034915680529?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/7083911034915680529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2010/04/always-avoid-working-with-tools-that.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/7083911034915680529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/7083911034915680529'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2010/04/always-avoid-working-with-tools-that.html' title='&quot;Always avoid working with tools that have a helve&quot;'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-5669812397099314638</id><published>2010-03-18T13:30:00.007+01:00</published><updated>2010-03-18T14:31:47.214+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><title type='text'>Fancy technologies</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dt7U9USNbqk/S6IrM7yyiQI/AAAAAAAAAHQ/xtwZXBW7EEk/s1600-h/fancy_glasses.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 200px;" src="http://2.bp.blogspot.com/_dt7U9USNbqk/S6IrM7yyiQI/AAAAAAAAAHQ/xtwZXBW7EEk/s200/fancy_glasses.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5449966000280865026" /&gt;&lt;/a&gt;
&lt;p&gt;
What makes technologies look good for the first sight? Is it a great demo showing an easy-to-implement solution? What makes you to choose a given technology? A nice graphics, open source, wide community?
&lt;/p&gt;&lt;p&gt;
Well, I have major interest in Java related technologies so my opinion may be skewed by that. Recently, I felt for some technology (let's call it &lt;em&gt;Technology X&lt;/em&gt;) and I chose it for my project. It has the following attributes that I appreciated (not in any particular order):
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;open source&lt;/li&gt;
&lt;li&gt;active community&lt;/li&gt;
&lt;li&gt;fancy demos&lt;/li&gt;
&lt;li&gt;great ratio of source lines/work done&lt;/li&gt;
&lt;li&gt;supporting tools&lt;/li&gt;
&lt;li&gt;usable documentation&lt;/li&gt;
&lt;li&gt;some books by known authors exist&lt;/li&gt;
&lt;li&gt;fresh post "bleeding edge" technology&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Especially the last attribute was a problem. I usually wait several months before upgrading my Linux distribution to hear from the community about major problems. I waited for a year after relatively wide adoption of Technology X. Obviously it was not enough and my decision proved to be a big mistake. 
&lt;/p&gt;&lt;p&gt;
What might look fancy at the beginning could become a real nightmare. My problem was that Technology X was well prepared for many standard usage scenarios keeping the above list of attributes valid. When I started looking at some specific problems I got into a trouble. And what makes your project exceptional? A specific behavior that nobody else has, in my opinion.
&lt;/p&gt;&lt;p&gt;
To make the long story short, I ended up dwelling in the Technology X's source code to realize that there are well-known bugs and design flaws that were blockers to my project.
&lt;/p&gt;&lt;p&gt;
What makes me think of this story was another blog post of a new superb glorious &lt;em&gt;Technology Y&lt;/em&gt; that can become a panacea to your projects. As a proof of all the positive features authors demonstrated a &lt;em&gt;Getting started&lt;/em&gt; example of &lt;em&gt;nothing too fancy, but enough to give you an idea of...&lt;/em&gt;
&lt;/p&gt;&lt;p&gt;
But realistically, it is possible that later the authors abandon the project and no other blog will be published. It is not likely to see a blog post describing what is not possible with Technology Y. So please, before you write a &lt;em&gt;Getting started&lt;/em&gt; blog/article, always make sure that you have tried advanced features of that technology as well.
&lt;/p&gt;&lt;p&gt;
Eventually, I used &lt;em&gt;Technology Z&lt;/em&gt; for my project. It was a complete restart of the development phase. This time I was more cautious. I realized that with the right technology I can start doing some real work early in the technology studying phase. The documentation is precise, yet relatively short. Technology Z has a great support in my favorite IDE. I have control of what and how is done - the technology is flexible in allowing me to choose an appropriate level of granularity in different parts of my project depending on my goals.
&lt;/p&gt;&lt;p&gt;
I couldn't believe it. Technology Z offers me the same functionality as Technology X. I do not have to write any significantly bigger amount of code or configuration files. I can implement new features in my project in approximately 20% of the original time needed with Technology X. Long live &lt;strong&gt;Technology Z&lt;/strong&gt;.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-5669812397099314638?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/5669812397099314638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2010/03/fancy-technologies.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/5669812397099314638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/5669812397099314638'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2010/03/fancy-technologies.html' title='Fancy technologies'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dt7U9USNbqk/S6IrM7yyiQI/AAAAAAAAAHQ/xtwZXBW7EEk/s72-c/fancy_glasses.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-8843011430600246598</id><published>2009-11-28T23:18:00.003+01:00</published><updated>2009-11-28T23:34:22.480+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='graphics'/><title type='text'>Image Analysis</title><content type='html'>&lt;p&gt;Today, I needed to compute an average value of a function. The problem was that the function was a chart in a .gif image.&lt;/p&gt;
&lt;p&gt;I run across a great application called &lt;a href="http://rsbweb.nih.gov/ij/"&gt;ImageJ&lt;/a&gt;. It has a pluggable interface, many powerful functions, it is open-source and written in Java. The platform independent distribution has only 3MB.&lt;/p&gt;
&lt;p&gt;I opened my image in the application, cropped the unnecessary parts, and used the magic wand to selected the area under the function line. Then I just clicked on measure and got the area of 69035 pixels (btw. this is the value of the integral). I divided the number by the width of the image and got 226. Now I subtracted 226 from the image height and looked at the y-axis for the average value - 8.7...&lt;/p&gt;
&lt;p&gt;
Disclaimer: &lt;em&gt;ImageJ is being developed at the National Institutes of Health by an employee of the Federal Government in the course of his official duties. Pursuant to Title 17, Section 105 of the United States Code, this software is not subject to copyright protection and is in the public domain.&lt;/em&gt; So long and thanks for ImageJ!
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-8843011430600246598?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/8843011430600246598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2009/11/image-analysis.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/8843011430600246598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/8843011430600246598'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2009/11/image-analysis.html' title='Image Analysis'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-29827949502060346</id><published>2009-09-07T15:14:00.016+02:00</published><updated>2009-11-28T23:34:55.066+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Performance testing: Load generator</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dt7U9USNbqk/SqUdLt8o3dI/AAAAAAAAAFY/3O7LVqShZYw/s1600-h/loaded-truck2.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 265px; height: 400px;" src="http://2.bp.blogspot.com/_dt7U9USNbqk/SqUdLt8o3dI/AAAAAAAAAFY/3O7LVqShZYw/s400/loaded-truck2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5378737417113624018" /&gt;&lt;/a&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Performance testing is a wide term, so let me be more specific please: &lt;em&gt;performance testing of a message oriented middleware from the client's point of view&lt;/em&gt;. A message oriented middleware can be an Enterprise Service Bus for instance. We tried several implementations - &lt;a href="http://jboss.org/jbossesb/"&gt;JBoss ESB&lt;/a&gt;, &lt;a href="http://wso2.org/projects/esb/java"&gt;WSO2 ESB&lt;/a&gt;, and &lt;a href="http://www.mulesoft.com/mule-esb-open-source-esb"&gt;Mule ESB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
What does the "testing from the client's point of view" mean? It means that we don't care about internal processes of the ESB. We just care how long it takes to process our request. It reminds of integration testing in the classical V-Model.
&lt;/p&gt;

&lt;h2&gt;Problem Definition&lt;/h2&gt;
&lt;p&gt;
We were working in a team on the problem and after trying several load generators, we found out that there is none that is generic enough. We wanted to send various types of messages (e.g. JMS, SOAP, files...) in different ways (send all messages at once, find the maximum sustainable speed, run a long-term test...). Apache JMeter approaches the ideal but is still missing some features. Moreover, we experienced high results jitter over time. So we decided to write our own lightweight, easy-to-use load generator. Here are some basic requirements:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stable results.&lt;/li&gt;
&lt;li&gt;There must be a constant message inflow while received messages are being processed.&lt;/li&gt;
&lt;li&gt;Messages must be generated by many concurrent clients.&lt;/li&gt;
&lt;li&gt;Clients must run on remote machines not to influence results.&lt;/li&gt;
&lt;li&gt;Speed should be measured on the client side for us not to affect the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Solution&lt;/h2&gt;
&lt;h3&gt;Message Sender&lt;/h3&gt;
&lt;p&gt;
First, there are different types of messages. So let's have an interface of a component that just sends a particular message.
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
public interface MessageSender {
  public void setProperty(String prop, String value);
  public void init(String address) throws Exception;
  public void close();
  public Serializable send(Serializable message, 
    Map properties) throws Exception;
  public MessageSender clone();
}
&lt;/pre&gt;
&lt;p&gt;
The component should be able to get configured with standard property/value pairs, initialize a connection to a given address, send a serializable message (e.g. a String), and close the connection. Moreover, it can clone itself for us not to have to configure each instance.
&lt;/p&gt;
&lt;p&gt;
There are two important decision points. First, do you want MessageSender to be reusable - to be able to send more than one message? When you are careful enough, you should be able to achieve this. At least, we did not experience any problems with that.
&lt;/p&gt;
&lt;p&gt;
Second, do you want your senders to be thread safe? This is a completely different situation, which is really hard to achieve and keep high performance. An example is sending of JMS messages. JMS session is not thread safe but it takes relatively long time to initialize. You might want to extend the interface and create a &lt;em&gt;ThreadSafeMessageSender&lt;/em&gt;.
&lt;/p&gt;
&lt;p&gt;
An example of an HTTPSender is shown below.
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
public class HTTPSender implements MessageSender {
  private URL url;
  private String method = "POST";

  public void setProperty(String prop, String value) {
    if ("method".equals(prop)) {
      method = value;
    }
  }

  public void init(String address) throws Exception {
    url = new URL(address);
  }

  public void close() {
  }

  public Serializable send(Serializable message, Map properties) throws Exception {
    HttpURLConnection rc = (HttpURLConnection) url.openConnection();
    
    // ... standard HttpUrlConnection usage ...

    return response;
  }

  @Override
  public MessageSender clone() {
    ...
  }
}
&lt;/pre&gt;
&lt;h3&gt;Message Generator&lt;/h3&gt;
&lt;p&gt;
Next, there must be a message generator that uses message senders to generate messages in a given way.
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
public abstract class MessageGenerator {
  protected MessageSender sender;
  protected int threads = 1;

  public void setProperty(String property, String value) {
    if ("threads".equals(property)) {
      threads = Integer.valueOf(value);
    }
  }

  public void init(String address, MessageSender sender) throws Exception {
    this.sender = sender;
    this.sender.init(address);
  }

  public void close() {
    sender.close();
  }

  public abstract void generate(Serializable message, int count) throws Exception;
}
&lt;/pre&gt;
&lt;p&gt;
As you can see, an already configured instance of &lt;em&gt;MessageSender&lt;/em&gt; must be passed to the &lt;em&gt;MessageGenerator&lt;/em&gt; in the &lt;em&gt;init()&lt;/em&gt; method. It is not a constructor because some configuration of the generator might be performed first in its descendants. This abstract generator supposes that the message sender is thread safe, because it uses just a single instance to pass all the messages through. Descendants might want to clone this instance in case it were not thread safe.
&lt;/p&gt;
&lt;p&gt;
We used several new features of Java 6 to create a message generator that just sends all the messages to the server in a given number of threads. Let's first examine a sender task that is created per each thread. It uses shared AtomicInteger to keep track of actually sent messages.
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
public class SenderTask implements Runnable {
  private MessageSender sender; // shared sender
  private Serializable message; // message to send
  private AtomicInteger counter; // shared message counter
  private int count; //  number of messages for this thread

  public SenderTask(AtomicInteger counter, MessageSender sender, 
      String address, Serializable message, int count) 
      throws Exception {
    this.count = count;
    this.sender = sender;
    this.message = message;
    this.counter = counter;

    // expect sender's uninitialized clone
    this.sender.init(address);
  }

  @Override
  public void run() {
    try {
      for (int i = 0; i &amp;lt; count; i++) {
        sender.send(message, null);
        counter.incrementAndGet();
      }
    } catch (Exception e) {
      log.error(e);
    } finally {
      sender.close();
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;
In the next listing, there is an implementation of the &lt;em&gt;generate()&lt;/em&gt; method. No speed measurement code is included but the main goal here was to show the &lt;em&gt;ExecutorService&lt;/em&gt;'s usage.
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
@Override
public void generate(Serializable message, int count) 
    throws Exception {
  List&amp;lt;SenderTask&amp;gt; taskList = 
    new ArrayList&amp;lt;SenderTask&amp;gt;(threads);

  // Let tasks to initialize senders
  for (int i = 0; i &amp;lt; threads; i++) {
    taskList.add(new SenderTask(counter, sender.clone(), 
      address, message, perThreadMessageCount);
  }

  // Submit all tasks for completion
  ExecutorService es = Executors.newFixedThreadPool(threads);
  for (int i = 0; i &amp;lt; threads; i++) {
    es.submit(taskList.get(i));
  }

  // Wait for termination
  es.shutdown();
  boolean terminated = false;
  while (!terminated) {
    // output current state
    // take some sleep
    // updated 'terminated' variable
  }
}
&lt;/pre&gt;
&lt;p&gt;
As you can see, clones of the original sender are created for us not to have to take care of the thread safeness. Individual &lt;em&gt;SenderTask&lt;/em&gt; instances are created in advance for all sender clones to get initialized. Then the instances are put in an &lt;em&gt;ExecutorService&lt;/em&gt; and executed. While we are waiting for all threads to finish, we can periodically output current and overall throughput for instance.
&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;
This concept already demonstrated its value in real world scenarios. We were able to write various message senders and generators easily and quickly. Even though it may look simple, there are some factors you must take into consideration.
&lt;/p&gt;
&lt;p&gt;
First is the warm up period of the server. You could either run the test several times and ignore a couple of first runs, or extend the generator to throw in some more messages and do not count them.
&lt;/p&gt;
&lt;p&gt;
Second, always make sure that the client is able to generate messages several times faster than the server is able to process. Otherwise, you measure the client's performance, which is something you do not want probably.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-29827949502060346?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/29827949502060346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2009/09/performance-testing-load-generator.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/29827949502060346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/29827949502060346'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2009/09/performance-testing-load-generator.html' title='Performance testing: Load generator'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dt7U9USNbqk/SqUdLt8o3dI/AAAAAAAAAFY/3O7LVqShZYw/s72-c/loaded-truck2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-5421232990605644414</id><published>2009-09-07T12:03:00.013+02:00</published><updated>2009-09-07T16:39:27.354+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wsdl'/><title type='text'>WSDL 2.0: Quick reference</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dt7U9USNbqk/SqUF1_GiRGI/AAAAAAAAAFQ/gKhZIlwvhbM/s1600-h/wsdl_structure.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 274px; height: 320px;" src="http://1.bp.blogspot.com/_dt7U9USNbqk/SqUF1_GiRGI/AAAAAAAAAFQ/gKhZIlwvhbM/s320/wsdl_structure.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5378711754993976418" /&gt;&lt;/a&gt;
&lt;p&gt;
I wrote this blog entry mainly for me - to beat WSDL structure in my mind in a clean and nice way. Hopefully, it will help some others as well.
&lt;/p&gt;
&lt;p&gt;
I would like to introduce changes between WSDL 1.1 and 2.0, and to go through the individual parts of the new WSDL version. This blog entry is based on several other on-line &lt;a href="#resources"&gt;resources&lt;/a&gt; as well as books.
&lt;/p&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;
WSDL stands for Web Services Description Language. It is a document written in XML. The document describes a Web service, specifies the location of the service, and the operations (or methods) the service exposes.
&lt;/p&gt;
&lt;p&gt;
WSDL 2.0 was first developed as WSDL 1.2 but was renamed because of its substantial differences. Some major changes are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding further semantics to the description language.&lt;/li&gt;
&lt;li&gt;Removal of message constructs. These are specified using the XML schema type system in the types element.&lt;/li&gt;
&lt;li&gt;No support for operator overloading.&lt;/li&gt;
&lt;li&gt;PortTypes renamed to interfaces. Support for interface inheritance is achieved by using the extends attribute in the interface element.&lt;/li&gt;
&lt;li&gt;Ports renamed to endpoints.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;h2&gt;Conceptual Model&lt;/h2&gt;
&lt;p&gt;
The description consists of two parts. In the abstract part, WSDL describes a web service in:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Messages it sends and receives using a type system (typically W3C XML Schema).&lt;/li&gt;
&lt;li&gt;Message exchange patterns that define the sequence and cardinality of messages.&lt;/li&gt;
&lt;li&gt;Operations that associates message exchange patterns with one or more messages.&lt;/li&gt;
&lt;li&gt;Interfaces group these operations in a transport and wire independent manner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
In the concrete part of the description:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bindings specify the transport and wire format for interfaces.&lt;/li&gt;
&lt;li&gt;A service endpoint associates network address with a binding.&lt;/li&gt;
&lt;li&gt;A service groups the endpoints that implement a common interface.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Structure&lt;/h2&gt;
&lt;p&gt;Following is a basic WSDL structure&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;
&amp;lt;definitions targetNamespace="xs:anyURI"&amp;gt;
&amp;lt;documentation /&amp;gt; ?
[&amp;lt;import /&amp;gt; | &amp;lt;include /&amp;gt; ] *
&amp;lt;types /&amp;gt; ?
[&amp;lt;interface /&amp;gt; | &amp;lt;binding /&amp;gt; | &amp;lt;service /&amp;gt; ] *
&amp;lt;/definitions&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Definitions&lt;/h3&gt;
&lt;p&gt;
The definitions element serves as a container.
&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;
&amp;lt;definitions name="StockQuote"
  targetNamespace="http://example.com/stockquote/definitions"
  xmlns:tns="http://example.com/stockquote/definitions"
  xmlns:xsd1="http://example.com/stockquote/schemas"
  xmlns:soap="http://www.w3.org/2003/11/wsdl/soap12"
  xmlns="http://www.w3.org/2003/11/wsdl"&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Include&lt;/h3&gt;
&lt;p&gt;
The include element helps to modularize the web service descriptions. Included documents must have the same target namespace.
&lt;/p&gt;

&lt;h3&gt;Import&lt;/h3&gt;
&lt;p&gt;
The concept behind the import element is very similar to that of include element, except that the imported WSDL can be in different target namespaces.
&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;
&amp;lt;import namespace="http://example.com/stockquote/schemas"
  location="http://example.com/stockquote/stockquoteV20.xsd"/&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Types&lt;/h3&gt;
&lt;p&gt;
The types element defines the data types used by the exchanged messages. WSDL uses W3C XML Schema as its preferred schema language.
&lt;/p&gt;
&lt;p&gt;
The following example refers to an imported XSD.
&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;
&amp;lt;types&amp;gt;
  &amp;lt;schema 
    targetNamespace="http://example.com/stockquote/definitions"&amp;gt;
    &amp;lt;element name="GetLastTradePriceInput" 
      type="xsd1:TradePriceRequest"/&amp;gt;
    &amp;lt;element name="GetLastTradePriceOutput" 
      type="xsd1:TradePrice"/&amp;gt;
  &amp;lt;/schema&amp;gt;
&amp;lt;/types&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Interface&lt;/h3&gt;
&lt;p&gt;
An interface element encloses a named set of abstract operations and the abstract messages. It can extend one or more other interfaces. Interfaces are referred to by QName in other components.
&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;
&amp;lt;interface name="StockQuoteInterface"&amp;gt;
  &amp;lt;operation name="GetLastTradePrice" pattern="http://www.w3.org/2003/11/wsdl/in-out"&amp;gt;
    &amp;lt;input message="tns:GetLastTradePriceInput"/&amp;gt;
    &amp;lt;output message="tns:GetLastTradePriceOutput"/&amp;gt;
  &amp;lt;/operation&amp;gt;
&amp;lt;/interface&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Binding&lt;/h3&gt;
&lt;p&gt;
The binding element defines the underlying transport and wire format for messages. Each binding references to an interface.
&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;
&amp;lt;binding name="StockQuoteSoapBinding" 
  interface="defs:StockQuoteInterface"&amp;gt;
  &amp;lt;soap:binding protocol="http://www.w3.org/2003/11/wsdl/http"/&amp;gt;
  &amp;lt;operation name="GetLastTradePrice"&amp;gt;
    &amp;lt;soap:operation 
      soapAction="http://example.com/GetLastTradePrice"/&amp;gt;
    &amp;lt;input&amp;gt;
      &amp;lt;soap:body/&amp;gt;
    &amp;lt;/input&amp;gt;
    &amp;lt;output&amp;gt;
      &amp;lt;soap:body/&amp;gt;
    &amp;lt;/output&amp;gt;
  &amp;lt;/operation&amp;gt;
&amp;lt;/binding&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Service&lt;/h3&gt;
&lt;p&gt;
A service element describes a set of endpoints which refer to a single network address for a binding. All other protocol specific information is contained in the binding.
&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;
&amp;lt;service name="StockQuoteService"&amp;gt;
  &amp;lt;documentation&amp;gt;My stock quote service&amp;lt;/documentation&amp;gt;
  &amp;lt;endpoint name="StockQuoteEndPoint" 
    binding="tns:StockQuoteSoapBinding"&amp;gt;
    &amp;lt;soap:address location="http://example.com/stockquote"/&amp;gt;
  &amp;lt;/endpoint&amp;gt;
&amp;lt;/service&amp;gt;
&lt;/pre&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;
Despite of the fact that the WSDL format might seem over-engineered to you (because it probably is), you should now be aware of its content and the meaning of individual elements.
&lt;/p&gt;

&lt;h2&gt;&lt;a name="resources"&gt;References&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
[1] Article on WSDL at &lt;a href="http://www.xml.com/pub/a/ws/2004/05/19/wsdl2.html?page=1"&gt;www.xml.com&lt;/a&gt;&lt;br /&gt;
[2] W3C School &lt;a href="http://www.w3schools.com/wsdl/default.asp"&gt;WSDL Tutorial&lt;/a&gt;&lt;br /&gt;
[3] Web Service Platform Architecture &lt;a href="http://www.informit.com/store/product.aspx?isbn=0131488740"&gt; on InformIT.com&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-5421232990605644414?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/5421232990605644414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2009/09/wsdl-20-quick-reference.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/5421232990605644414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/5421232990605644414'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2009/09/wsdl-20-quick-reference.html' title='WSDL 2.0: Quick reference'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_dt7U9USNbqk/SqUF1_GiRGI/AAAAAAAAAFQ/gKhZIlwvhbM/s72-c/wsdl_structure.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-5191971153652620938</id><published>2009-05-13T11:19:00.006+02:00</published><updated>2009-05-13T12:35:44.552+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='ejb'/><title type='text'>EJB3: Conscious Session Bean</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dt7U9USNbqk/Sgqahrx8xdI/AAAAAAAAADQ/OB3JCZrcvHE/s1600-h/beans.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://3.bp.blogspot.com/_dt7U9USNbqk/Sgqahrx8xdI/AAAAAAAAADQ/OB3JCZrcvHE/s200/beans.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5335246612052362706" /&gt;&lt;/a&gt;
&lt;p&gt;
Last week, I wanted to demonstrate &lt;tt&gt;@TransactionAttribute&lt;/tt&gt; in a session bean using JBoss AS 5.1.0 GA and EJB3. Everything seemed pretty simple...
&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
@Stateless
public class OmnipotentBean implements Omnipotent {
    @TransactionAttribute(REQUIRED)
    public String transactionRequired() throws SystemException {
        try {
            transactionNever();
            System.err.println("No exception occured - ERROR");
        } catch (EJBException e) {
            System.out.println("Expected exception - OK");
        }
    }

   @TransactionAttribute(NEVER)
    public String transactionNever() throws SystemException {
        ...
    }
}
&lt;/pre&gt;
&lt;p&gt;
As you can see, I wanted to show that calling a method with a transaction attribute set to &lt;tt&gt;NEVER&lt;/tt&gt; from a method that already runs in a transaction throws an exception. But
the exception was not thrown. How come?
&lt;/p&gt;
&lt;p&gt;
Let's start from the client. What kind of object do we get from JNDI when we looked up &lt;em&gt;OmnipotentBean/remote&lt;/em&gt;? It was neither &lt;tt&gt;OmnipotentBean&lt;/tt&gt; or its interface.
It was a dynamically generated class based on &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/Proxy.html"&gt;java.lang.reflect.Proxy&lt;/a&gt;, which handles all method calls and
passes them to the server. You can call its method because it implements &lt;tt&gt;Omnipotent&lt;/tt&gt; interface. Moreover, the call passes through a set of interceptors, which can perform additional work and setup the environment, inlcuding security and transactional interceptors.
&lt;/p&gt;
&lt;p&gt;
The same applies at the server side. What is &lt;tt&gt;this&lt;/tt&gt; inside &lt;tt&gt;transactionRequired()&lt;/tt&gt; method? It is just a &lt;tt&gt;OmnipotentBean&lt;/tt&gt; class instance, thus a simple POJO. We must lookup
the EJB through JNDI to get a proxy object for transactional attributes to start working.
&lt;/p&gt;
&lt;p&gt;
Another uncomfortable thing is that we cannot use dependency injection in our session bean to inject its proxy. Not having the bean initialized at the time of its initialization when dependencies are being injected, this is the cause.
&lt;/p&gt;
&lt;p&gt;
So, are all the problems just JBoss AS's whims? What does the specification say?
&lt;a href="http://jcp.org/aboutJava/communityprocess/final/jsr220/index.html"&gt;EJB3 - JSR-220&lt;/a&gt; (file EJB Core, page 343):
&lt;/p&gt;
&lt;p class="quote"&gt;
The following subsections define the responsibilities of the container for managing the invocation of an
enterprise bean business method &lt;em&gt;when the method is invoked via the enterprise bean’s business interface
(and/or home or component interface)&lt;/em&gt;, or web service endpoint. The container’s responsibilities depend
on the value of the transaction attribute.
&lt;/p&gt;
&lt;p&gt;
Everything is all right. EJB container (i.e., the application server) must manage the invocations of bean's methods only when they are called via the business interface, which is the proxy object.
&lt;/p&gt;
&lt;p&gt;
Maybe this is not suprising to you and you are right. It is very logical. Just bear in mind that a session bean must be conscious of its own business interface when invoking methods of its own.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-5191971153652620938?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/5191971153652620938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2009/05/ejb3-conscious-session-bean.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/5191971153652620938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/5191971153652620938'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2009/05/ejb3-conscious-session-bean.html' title='EJB3: Conscious Session Bean'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dt7U9USNbqk/Sgqahrx8xdI/AAAAAAAAADQ/OB3JCZrcvHE/s72-c/beans.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-6378508337757953514</id><published>2009-04-18T19:22:00.004+02:00</published><updated>2009-04-18T21:03:46.950+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='richfaces'/><title type='text'>RichFaces and Background Gradient</title><content type='html'>&lt;p&gt;I do not know whose idea it was. Maybe it is there just to demonstrate some advanced RichFaces' abilities but I (in all the humbleness) hate it. I am talking about the background gradient which is by default present at table headers and toolbars. The background is a dynamically generated image and its presence in a web page is caused by XML snippets like the following one (part of &lt;code&gt;richfaces-ui.jar:/org/richfaces/skin.xcss&lt;/code&gt;).&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;
&amp;lt;u:style name="background-image"&amp;gt;
  &amp;lt;f:resource xmlns:f="http:/jsf.exadel.com/template" f:key="org.richfaces.renderkit.html.GradientA"/&amp;gt;
&amp;lt;/u:style&amp;gt;
&lt;/pre&gt;
&lt;p&gt;A friend of mine would call such a beatiful thing a &lt;em&gt;funfair&lt;/em&gt; or a &lt;em&gt;fly-by&lt;/em&gt;. Apart from the &lt;strong&gt;hardcoded&lt;/strong&gt; gradient background I miss only one thing in RichFaces.&lt;/p&gt;
&lt;div align="center" style="text-decoration: blink"&gt;&lt;marquee direction="right" loop="20"&gt;&lt;blink&gt;
A scrolling text that blinks in Firefox and Opera.
&lt;/blink&gt;&lt;/marquee&gt;&lt;/div&gt;
&lt;p&gt;It took me couple of hours to get over the problem, yet I'm not satisfied with either solution I found.&lt;/p&gt;
&lt;h2&gt;Solution no. 1: Override the default behavior&lt;/h2&gt;
&lt;p&gt;
Your CSS style can be loaded later and override the background you are not satisfied with. This is even &lt;a href="http://www.jboss.org/community/docs/DOC-11860"&gt;"oficially" recommended&lt;/a&gt;. The linked page speaks about &lt;code&gt;rich:dataTable&lt;/code&gt; so I am adding my part for &lt;code&gt;rich:Toolbar&lt;/code&gt;.
&lt;/p&gt;
&lt;pre name="code" class="css"&gt;
.rich-toolbar, .rich-toolbar-item {
    background-image:none;
    background-color:transparent;
}     
&lt;/pre&gt;
&lt;p&gt;
You can of course set more convenient background color. The big issue here is that you still have the gradient style configured and loaded by your browser, and the background image generated at the server.
&lt;/p&gt;

&lt;h2&gt;Solution no. 2: Update richfaces-ui.jar&lt;/h2&gt;
&lt;p&gt;
You can grep through all &lt;code&gt;.xcss&lt;/code&gt; files inside &lt;code&gt;richfaces-ui.jar&lt;/code&gt; and remove the gradient from whatever place you want. You get tinier CSS and less work on the server side. But you have to repeate the procedure every time you want to upgrade RichFaces version. And you also must be careful about your &lt;code&gt;richfaces-ui-without-gradient.jar&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
I like neither of the solutions. For my project I went with no. 1 and I hope that there will be a new gradient style to configure in my &lt;code&gt;skin.properties&lt;/code&gt;: &lt;code&gt;gradientStyle=&lt;strong&gt;NONE&lt;/strong&gt;&lt;/code&gt;.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-6378508337757953514?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/6378508337757953514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2009/04/richfaces-and-background-gradient.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/6378508337757953514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/6378508337757953514'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2009/04/richfaces-and-background-gradient.html' title='RichFaces and Background Gradient'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-749872136999650174</id><published>2009-04-09T13:10:00.018+02:00</published><updated>2009-04-09T15:00:12.160+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='testng'/><title type='text'>TestNG and Group Filters</title><content type='html'>&lt;p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dt7U9USNbqk/Sd3f9DKyNWI/AAAAAAAAACQ/idwPO4KHBns/s1600-h/testnggroups.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 200px;" src="http://2.bp.blogspot.com/_dt7U9USNbqk/Sd3f9DKyNWI/AAAAAAAAACQ/idwPO4KHBns/s320/testnggroups.png" alt="" id="BLOGGER_PHOTO_ID_5322656574537348450" border="0" /&gt;&lt;/a&gt;
Recently I solved an interesting problem with test groups in TestNG. To describe the problem, let me describe a sample test class with three methods, which are included into two groups.
&lt;/p&gt;&lt;p&gt;
&lt;pre name="code" class="java"&gt;public class SampleTest {
  @Test(groups = { "groupA" })
  public void testMethod1() {
    System.out.println("1 in A");
  }

  @Test(groups = { "groupA", "groupB" })
  public void testMethod2() {
    System.out.println("2 in A, B");
  }

  @Test(groups = { "groupB" })
  public void testMethod3() {
    System.out.println("3 in B");
  }
}&lt;/pre&gt;
&lt;/p&gt;&lt;p&gt;
Usually, TestNG is called using an Ant task like the following one.
&lt;/p&gt;&lt;p&gt;
&lt;pre name="code" class="xml"&gt;&amp;lt;testng excludedGroups="..." groups="..." ... /&amp;gt;&lt;/pre&gt;
&lt;/p&gt;&lt;p&gt;
What methods can be executed with various &lt;em&gt;groups&lt;/em&gt; and &lt;em&gt;excludedGroups&lt;/em&gt; setting presents this table:
&lt;table class="qecafe"&gt;
&lt;tr&gt;&lt;th class="first"&gt;Methods&lt;/th&gt;&lt;th&gt;groups&lt;/th&gt;&lt;th&gt;excludedGroups&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="right"&gt;1&lt;/td&gt;&lt;td&gt;groupA&lt;/td&gt;&lt;td&gt;groupB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="right"&gt;1, 2&lt;/td&gt;&lt;td&gt;groupA&lt;/td&gt;&lt;td&gt;--&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="right"&gt;2, 3&lt;/td&gt;&lt;td&gt;groupB&lt;/td&gt;&lt;td&gt;--&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="right"&gt;3&lt;/td&gt;&lt;td&gt;groupB&lt;/td&gt;&lt;td&gt;groupA&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="right"&gt;1, 2, 3&lt;/td&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;--&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/p&gt;&lt;p&gt;
This is pretty logical. But wait, there is a combination missing from that table. What about just the method 2, which is in &lt;em&gt;groupA&lt;/em&gt; and &lt;em&gt;groupB&lt;/em&gt;? To be honest, I did not find an easy way to achieve this. But there is a workaround. First, you must use an external configuration file for TestNG.
&lt;/p&gt;&lt;p&gt;
&lt;pre name="code" class="xml"&gt;&amp;lt;testng classpathref="..."&amp;gt;
  &amp;lt;xmlfileset dir="." includes="testng.xml"/&amp;gt;
&amp;lt;/testng&amp;gt;&lt;/pre&gt;
&lt;/p&gt;&lt;p&gt;
In this file, you can use Beanshell to enable/disable individual methods.
&lt;/p&gt;&lt;p&gt;
&lt;pre name="code" class="xml"&gt;&amp;lt;suite name="TestSuite"&amp;gt;
  &amp;lt;test name="SampleTest"&amp;gt;
    &amp;lt;method-selectors&amp;gt;
      &amp;lt;method-selector&amp;gt;
        &amp;lt;script language="beanshell"&amp;gt;&amp;lt;![CDATA[
          groups.containsKey("groupA") &amp;amp;&amp;amp; groups.containsKey("groupB")
        ]]&amp;gt;&amp;lt;/script&amp;gt;
      &amp;lt;/method-selector&amp;gt;
    &amp;lt;/method-selectors&amp;gt;
    &amp;lt;classes&amp;gt;
      &amp;lt;class name="com.blogspot.qecafe.tests.SampleTest" /&amp;gt;
    &amp;lt;/classes&amp;gt;
  &amp;lt;/test&amp;gt;
&amp;lt;/suite&amp;gt;
&lt;/pre&gt;
&lt;/p&gt;&lt;p&gt;
The magic line in Beanshell will cause only methods in both groups to be executed.
&lt;/p&gt;&lt;p&gt;
There is yet another item missing - 1, 3 combination. You can run it in a similar way just like 2.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-749872136999650174?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/749872136999650174/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2009/04/testng-and-group-filters.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/749872136999650174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/749872136999650174'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2009/04/testng-and-group-filters.html' title='TestNG and Group Filters'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dt7U9USNbqk/Sd3f9DKyNWI/AAAAAAAAACQ/idwPO4KHBns/s72-c/testnggroups.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-1572723701032846753</id><published>2009-04-07T10:06:00.008+02:00</published><updated>2009-04-09T13:52:57.398+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='muse'/><title type='text'>Temptations of Software Engineers</title><content type='html'>&lt;p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dt7U9USNbqk/SdsLpthC4QI/AAAAAAAAACI/B8VugLwXPCo/s1600-h/swiss-army-collector.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 226px;" src="http://2.bp.blogspot.com/_dt7U9USNbqk/SdsLpthC4QI/AAAAAAAAACI/B8VugLwXPCo/s320/swiss-army-collector.jpg" alt="" id="BLOGGER_PHOTO_ID_5321860195889111298" border="0" /&gt;&lt;/a&gt;
Have you ever been tempted to use a technology just because of the technology itself? Was the technology such a fancy thing that you could not resist? Please do not do that! A result of your work would be barely usable in the real life. Do you know the superior Swiss knife with all the stuff inside? I am in doubt you could ever carve a little wooden ship for your son with it.
&lt;br clear='all' /&gt;
Let me tell you a true story of a software engineer and an application he developed.
&lt;/p&gt;&lt;p&gt;
Once upon a time, there was a guy who decided to learn Java and all its bright features, which brought the light on every programmer's possible problem. He chose a set of features that were most interesting to him including serialization, and multi threading. To be not all alone and to verify his code, he decided to take a community as a hostage. Let's inspect a couple of his mistakes.
&lt;/p&gt;&lt;p&gt;
First, serialization is good for remote method invocation, for sending objects over network, and even for storing small project configurations into a file. It should not be used as a primary data storage, since there are relational databases for such a purpose. If you wanted to be thread safe in a serialize-everything environment, you must keep all the objects in the memory and (de)serialize them only on an application start/shutdown. It is slow, complicated and inefficient way.
&lt;/p&gt;&lt;p&gt;
Second, multi threading is a powerful thing but it is like the fire - it can be very dangerous. Threads are not independent processes. You should be careful about them, especially if they are running third party code. Apart of that issue, the biggest problem was that &lt;code&gt;Thread.stop()&lt;/code&gt; does not stop a waiting thread on all JVM implementations. It is not good idea to stick to an implementation detail. Later, &lt;code&gt;Thread&lt;/code&gt;'s methods &lt;code&gt;stop()&lt;/code&gt;, &lt;code&gt;suspend()&lt;/code&gt;, and &lt;code&gt;resume()&lt;/code&gt; have become &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html"&gt;deprecated&lt;/a&gt; because it showed up that they are unsafe.
&lt;/p&gt;&lt;p&gt;
I could have continue here with similar cases but that should be enough to show what I meant by &lt;span style="font-style: italic;"&gt;temptations&lt;/span&gt;. If the project were now buried deep in the binary scarp, everything was fine. Unfortunately, the community around it become large and the project is massively used nowadays. And the users must fight with those design issues hidden deep inside of it.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-1572723701032846753?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/1572723701032846753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2009/04/temptations-of-software-engineers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/1572723701032846753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/1572723701032846753'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2009/04/temptations-of-software-engineers.html' title='Temptations of Software Engineers'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dt7U9USNbqk/SdsLpthC4QI/AAAAAAAAACI/B8VugLwXPCo/s72-c/swiss-army-collector.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1251111456079579036.post-4001185741358613292</id><published>2009-04-01T16:27:00.006+02:00</published><updated>2009-04-09T13:52:16.841+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='muse'/><title type='text'>Guts of Programming Languages</title><content type='html'>&lt;p&gt;
What makes it difficult to master a new programming language when you already know one or two? Is it a fancy syntax? Is it an API? I do not think so.
&lt;/p&gt;&lt;p&gt;
A syntactic sugar is not the real matter of the programming art. It should be only a hammer for your nails. Usually, a new syntax is not so much different. I mean how often do you meet a brand new paradigm? There is imperative, functional, logic and whatever programming, but you have probably chosen your way already.
&lt;/p&gt;&lt;p&gt;
Modern IDEs can help you with the API of the new language. Again, API should not be an obstacle. But there is still a thing that you must be aware of...
&lt;/p&gt;&lt;p&gt;
I do not know of any real programming language that isolates a programmer from its inside behavior (by a real programming language I mean a language that is commonly used for developing long running applications). You always need to be aware of a memory model, of a garbage collection mechanism, of a just in time compilation, of a target system architecture, of registers size, of a class inner representation, of a variable size in bytes...
&lt;/p&gt;&lt;p&gt;
There are too many "of". I wonder when there is a language that allows developers to concentrate completely on the main problem. A friend of mine suggested that PHP  &lt;span style="font-style: italic;"&gt;is&lt;/span&gt; such a language but I do not agree with that. It is a language which leaves a field of corpses behind itself and must finish processing sooner than anybody reveals this fact.
&lt;/p&gt;&lt;p&gt;
I have a favorite programming language, which isolates me at most. It is in the functional languages family, and it is called &lt;span style="font-weight: bold;"&gt;Haskell&lt;/span&gt;. You can even write a GUI application in Haskell, but an application server would be a death match.
&lt;/p&gt;&lt;p&gt;
So good luck in those hard times and do your best for you not to forget any single language implementation detail...
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1251111456079579036-4001185741358613292?l=qe-cafe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qe-cafe.blogspot.com/feeds/4001185741358613292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qe-cafe.blogspot.com/2009/04/guts-of-programming-languages.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/4001185741358613292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1251111456079579036/posts/default/4001185741358613292'/><link rel='alternate' type='text/html' href='http://qe-cafe.blogspot.com/2009/04/guts-of-programming-languages.html' title='Guts of Programming Languages'/><author><name>marvec</name><uri>http://www.blogger.com/profile/01257832382088091783</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dt7U9USNbqk/Sd8vh0fwyGI/AAAAAAAAACY/Xz7j0aRNtBQ/S220/marvec.jpg'/></author><thr:total>1</thr:total></entry></feed>
