Le blog d'Olivier

Aller au contenu | Aller au menu | Aller à la recherche

mardi 12 mai 2009

Multiples docbases avec tomcat

Je travaille avec des applicatifs java possédant deux arborescences distinctes :

  • le répertoire de la webapp contenant le cœur de l'applicatif : web.xml, context spring, jsp, images, css, ...
  • un répertoire avec des jsp générées par un CMS

La solution précédente mettait en œuvre des symlink entre ces deux répertoires pour qu'un Tomcat puisse servir l'ensemble des jsp. N'aimant pas beaucoup cette solution (nombreux symblink, problème sous windows, dans quel sens faire le symlink ?, ...) , je me suis mis à la recherche d'une solution plus élégante.

Avec Tomcat, on peut spécifier seulement un seul docBase par context, c'est un peu limitatif. Apache permet de faire des AliasMatch, Alias, ...

Voici un fichier classique de configuration Tomcat : conf/server.xml

<Host name="myhost" appBase="NO_WEBAPPS">
<Context path="" allowLinking="true" docBase="/path/to/my/webapp" override="true" reloadable="false">
</Context>
</Host>

L'idée est de créer une extension à Tomcat, la technique consiste à ajouter des docbases supplémentaires.

Dans l'idéal, le fichier conf/server.xml serait de la forme :

<Host name="myhost" appBase="NO_WEBAPPS">
<Context path="" allowLinking="true" docBase="/path/to/my/webapp" override="true" reloadable="false">
   <Resources className="com.xxx.xxx.MultipleDirContext" virtualDocBase="/path/to/another/docbase" />
</Context>
</Host>

Cette configuration permet d'ajouter un ou des docbases supplémentaires en plus de celui défini. En fait, contrairement à ce que je pouvais penser au départ, cette idée est assez facile en mettre en place. Il suffit de créer une classe MultipleDirContext héritant d'une classe tomcat FileDirContext.

/**
 * Add some DocBase in tomcat. VirtualDocBase separator is ';'.
 */
public class MultipleDirContext extends FileDirContext {
   private String seperator = ";";
   private String virtualDocBase;
   private LinkedHashSet<FileDirContextAdapter> virtualContexts = new LinkedHashSet<FileDirContextAdapter>();

   public MultipleDirContext() {
       super();
   }

   public MultipleDirContext(Hashtable env) {
       super(env);
   }

   public void setVirtualDocBase(String virtualDocBase) {
       this.virtualDocBase = virtualDocBase;
       StringTokenizer parser = new StringTokenizer(virtualDocBase, ",");
       while (parser.hasMoreTokens()) {
           FileDirContextAdapter currentContext = new FileDirContextAdapter();
           currentContext.setDocBase(parser.nextToken());
           virtualContexts.add(currentContext);
       }
   }

   public String getVirtualDocBase() {
       return virtualDocBase;
   }
   public String getSeperator() {
       return seperator;
   }
   public void setSeperator(String seperator) {
       this.seperator = seperator;
   }

   protected File file(String arg0) {
       File file = super.file(arg0);

       if (file == null) {
           for (FileDirContextAdapter virtualContext : virtualContexts) {
               file = virtualContext.file(arg0);
               if (file != null) {
                   return file;
               }
           }
       }
       return file;
   }

   public void setDocBase(String arg0) {
       super.setDocBase(arg0);
   }

   public void release() {
       super.release();
       for (FileDirContextAdapter virtualContext : virtualContexts) {
           virtualContext.release();
       }
   }

   public void allocate() {
       super.allocate();
       for (FileDirContextAdapter virtualContext : virtualContexts) {
           virtualContext.setCached(this.isCached());
           virtualContext.setCacheTTL(this.getCacheTTL());
           virtualContext.setCacheMaxSize(this.getCacheMaxSize());
           virtualContext.setCaseSensitive(this.isCaseSensitive());
           virtualContext.setAllowLinking(this.getAllowLinking());
           virtualContext.allocate();
       }
   }
}
public class FileDirContextAdapter extends FileDirContext {
   public FileDirContextAdapter() {
   }

   public FileDirContextAdapter(Hashtable env) {
       super(env);

   }
   protected File file(String arg0) {
       return super.file(arg0);
   }
}

Avec cette extension, si la ressource n'est pas trouvée dans le docbase par défaut, on itère sur les docbases supplémentaires. Une fois le MultipleDirContext.jar créé, le placer dans apache-tomcat-6.0.14/lib. Cette technique dévrait fonctionner avec tomcat 5.5.x, mais je n'ai pas testé, je travaille que sur tomcat 6 :)

Cette technique est utilisée en production depuis plus d'un an, sans overhead, sur ces sites publiques à fort trafic.

Qu'en pensez vous ?

mercredi 17 décembre 2008

How to create Oracle function (trunc, decode, ...) in H2 ?

I use Oracle in production environment, but I use an embedded H2 database in unit tests. H2 does not support Oracle functions like TRUNC or DECODE.

So, you can write yourself these functions ... in Java :)

// Oracle trunc like
public class H2Trunc {
    public final static Date trunc(Timestamp timeStamp) {
        return new Date(timeStamp.getTime());
    }
}
// Oracle decode like
public class H2Decode {
    public final static String decode(String expression, String param1, String value1, String param2, String value2, String param3,
            String value3, String param4, String value4, String param5, String value5, String param6, String value6, String param7,
            String value7, String param8, String value8, String defaultValue) {

        if (StringUtils.equals(expression, param1)) {
            return value1;
        }
        if (StringUtils.equals(expression, param2)) {
            return value2;
        }
        if (StringUtils.equals(expression, param3)) {
            return value3;
        }
        if (StringUtils.equals(expression, param4)) {
            return value4;
        }
        if (StringUtils.equals(expression, param5)) {
            return value5;
        }
        if (StringUtils.equals(expression, param6)) {
            return value6;
        }
        if (StringUtils.equals(expression, param7)) {
            return value7;
        }
        if (StringUtils.equals(expression, param8)) {
            return value8;
        }
        return defaultValue;
    }
}

In H2, create these functions with sql:

CREATE ALIAS IF NOT EXISTS DECODE FOR \"com.my.package.H2Decode.decode\"; CREATE ALIAS IF NOT EXISTS TRUNC FOR \"com.my.package.H2Trunc.trunc\"

lundi 20 octobre 2008

Maven in colour / Maven en couleur

ENG : If you want to see maven in colour, you can just add an litle awk in a script :)

FR : Vous voulez voir maven en couleur, il suffit d'ajouter un petit awk dans un script :)

Lire la suite...

jeudi 25 septembre 2008

Wake Up

Ce matin était organisé à la Cantine l'événement Wake Up, Cette première session fut riche en échange et en discussions.

Il me tarde d'être à la prochaine.

mardi 5 août 2008

GWT 1.5 RC2

GWT 1.5 RC2 vient tout juste de sortir. C'est téléchargeable ici : http://code.google.com/p/google-web-toolkit/downloads/list

- page 2 de 14 -