Archive for the ‘Java’ Category

Free mobile: les erreurs du site d’inscription

January 25th, 2012

Le site de Free Mobile a connu beaucoup de problèmes le jour de l’ouverture de l’offre: impossibilité de s’inscrire, inscriptions non prises en compte, etc.

Ne tenant pas la charge, le site à été réécrit pendant la nuit, en effectuant au passage une transition de Java (Jsf) vers Php.

En partant de ce constat, le troll Java Vs PHP est facile, mais plusieurs erreurs de conception ont largement contribué à l’écroulement du site:

Avant l’ouverture:
Avant l’ouverture officielle des inscriptions, le site de Free Mobile affichait un message du type : “dans quelques instants vous pourrez consulter nos offres”

  • Première erreur: Rechargement automatique toutes les minutes.

    la page se rafraîchissait automatiquement toutes les minutes.
    En plus des rafraîchissements manuels effectués par les impatients, ce code à généré un surplus de connexions et surtout a agit comme une retenue d’eau : à l’ouverture du vrai site, l’ensemble des utilisateurs en attente y ont accédé dans la première minute.….

À l’ouverture
Le site utilisait un système de “slots” pour le processus d’inscription : seul un nombre limité d’utilisateurs pouvaient s’inscrire simultanément. Les autres devaient attendre.

  • Deuxième erreur: Rechargement automatique toutes les 5 secondes.

    Lorsqu’aucun slot était disponible, le site affichait une page d’attente qui se rechargeait automatiquement toutes les 5 secondes pendant plusieurs minutes.
    En réponse à une surcharge, le site a multiplié volontairement la charge au bas mot entre 12x et 60x.

  • Troisième erreur: Choix de JSF
    JSF est un framework par composants, orienté applications web (type intranet), qui a besoin de stocker en session, pour chaque utilisateur :
    • L’état de l’ensemble des composants de la page courante
    • Le même état pour les X dernières pages visitées pour permettre l’utilisation du bouton précédent

    … là où les frameworks orientés sites web publics ne stockent que l’identifiant de l’utilisateur, dans le cas où celui-ci est authentifié.

    Dans le cas de free mobile, toutes les inscriptions sont faites par des utilisateurs différents. Le volume de données à stocker est donc énorme et n’est pas adapté à la fonction du site.

    Il est possible dans JSF de reporter ces données coté utilisateur en les intégrant dans le code html, au prix d’une augmentation de la bande passante. Cette configuration n’était pas utilisée sur free mobile.

Après la refonte:
Le site fonctionne maintenant en PHP, mais on peut voir que les leçons ont été tirées des problèmes ci-dessus:

  • En cas de surcharge du site, la page d’erreur redirige immédiatement vers la page d’accueil. Il n’y a plus de rechargement automatique. La redirection est même suffisamment rapide pour empêcher les utilisateurs de recharger eux-même la page trop facilement. (Note: La page principale est statique.)
  • Le site est en php basique, sans utilisation de framework visible. On se doute qu’il n’y a quasiment pas de données en session, voir pas du tout

Conclusion

  • Les rechargement de page en javascript sont dangereux sur les sites à forte charge. Il faut porter une extrême attention à leur impact sur le dimensionnement. Il vaut mieux privilégier un rechargement manuel de la page par l’utilisateur
  • La session est un élément sensible des applications web. Pour un site a forte audience, il faut limiter drastiquement les données stockées, ce qui exclut naturellement un certain nombre de frameworks de type JSF.

    En cas de nécessité, il est possible de déporter les données sur des caches mémoire, tels que memcache, ehcache, cohérence.

  • Un rappel: l’architecture mise en place ne dépend pas du langage. Faire une application complexe (modèle composant, de multiples couches, plein de données en session) ou ultra-simple quelques lignes dans un fichier est un choix, qui est réalisable de façon sensiblement identique dans les différents langages.

J’en profite également pour placer le projet open source Stateless Filter qui permet de déporter de façon transparente les sessions d’applications Java coté client ou dans un cache mémoire.

Les retours sont bien sûr les bienvenus. Je mettrai à jour l’article pour quelques corrections si nécessaire…

Transparent javascript and css compression with Maven3 and Yuicompressor

December 23rd, 2011

There are a lot of ressources on how to use YUIcompressor on a Maven project, but several examples don’t work with Maven3, or don’t allow to replace javascript and css by their compressed version transparently.

The following example will compress files transparently when packaging the webapp in a WAR file, and keep original files for development.

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-war-plugin</artifactId>
   <version>2.1.1</version>            
   <configuration>
      <warSourceExcludes>**/*.css,**/*.js</warSourceExcludes>
   </configuration>
</plugin>


<plugin>
   <groupId>net.alchim31.maven</groupId>
   <artifactId>yuicompressor-maven-plugin</artifactId>
   <executions>
      <execution>
         <id>compressyui</id>
         <phase>prepare-package</phase>
         <goals>
            <goal>compress</goal>
         </goals>
      </execution>

   </executions>
   <configuration>
      <nosuffix>true</nosuffix>
   </configuration>
</plugin>

XmlField : new validation API

December 21st, 2011

XmlField 0.7 which was just released provides a new validation API, based on JSR 303, with some additions borrowed from Hibernate validation.

It is now very simple to ensure objects are valid, without complex XPath expressions or XPath duplication.

Add constraints to your interfaces :
@ResourceXPath("/database")
public interface IDatabase {
   @NotEmpty
   @FieldXPath("@name")
   String getName();

   @Size(min=1)
   @FieldXPath("tables/table")
   ITable[] getTables();
}

Validate :
IDatabase db = new XmlField().xmlToObject( xmlString, IDatabase.class );

Set<ConstraintViolation<Object>> violations = new XmlFieldValidator().validate( db );

Supported annotations :

  • @NotEmpty : value exists and is not blank
  • @Size : string length, array size
  • @Range : numbers between min and max
  • @Values : check for accepted values

Enjoy :-)

See also : Introducing XmlField : Java xml/object mapping framework

Introducing XmlField : Java xml/object mapping framework

November 28th, 2011

We have recently released XmlField, a new Java xml/object mapping framework.

XmlField logo

There are already a lot of tools for this, but none seemed to fit our requirements :

  • A (very) simple API : we wanted to write as few code/configuration as possible, and keep code meaningful.
  • The ability to process and update XML documents without altering additional, unsupported data. This means that the XML model can be updated without requiring to update and deploy existing applications in most cases. (for more information see the “Behavior” page on the projet’s site.
  • No need to have a 1:1 mapping between the object XML structure, ability to flatten an XML document into a single object

If you’re writing a standalone application and use XML for storing configuration, XmlField will not be a major improvement (you may still like its simple API).

But if you are working in a corporate environment, with multiple applications sharing data using web or REST services, you may already see the benefits of these points.

A typical use case could be a system where user related data is stored in a central repository as xml documents and where this data is exposed through web services and used by several applications (both for reading and writing).

A some point, a new application requires additional data, which is not currently part of the xml model. This usually requires to update the central repository, adding support for this data through a new version of the web services, then maintain 2 versions of these services or move all existing applications to the new model to get rid of the previous one.

With XmlField-based applications, you just have to create your new app which stores additionnal tags in xml doduments. No need to update the central repository nor other applications. They will continue to process and update Xml objects, ignoring the new data but keeping it safe.

On the technical side, XmlField uses annotated interfaces to map xml data to objects. An interface can be written this way :

@ResourceXPath("/modelRootTag")
public interface IModel {
@FieldXPath("version")
String getVersion();

@FieldXPath("flag")
boolean getFlag();

@FieldXPath("entries/entry")
IEntry getEntries();

void setVersion(String version);

void setFlag(boolean flag);

IEntry addToEntries();
}

Then XmlField can be used this way :
// Source Xml
String xml ="";

// Read doc
XmlField xf = new XmlField();
IModel model = xf.xmlToObject(xmlRessource, IModel.class);

// Play with XML
model.setVersion( "1.0" );
String firstEntryName = model.getEntries()[0].getName();

//Add entry
IEntry newEntry = model.addToEntries();
newEntry.setName( "entry4" );
newEntry.setValue( "value4" );

// Back to XML.
xml = xf.objectToXml( model);

For more detailed examples, I just added a quickstart tutorial and a step-by-step example to the project’s website.

Even if the version number is only 0.6 yet, XmlField is stable enough for most uses and is currently used in production by several projects in different companies. We plan to reach 1.0 after the addition of a new document repository module, providing a lightweight xml document store with search and data validation.

Feedback is welcome. Feel free to test, use and report bugs or patchs using the project bugtracker and mailing lists.

XmlField released under the Apache Licence V2.0

http://xmlfield.sourceforge.net

(Related keywords : xml, java, serialization, marshalling, mapping, binding)

Solve webapp random startup errors (connection time out) and slowness

February 16th, 2011

When developping Java web apps, you may sometime see random startup errors like this one :

java.lang.IllegalStateException: Unable to instantiate container.
at org.apache.tiles.web.startup.TilesListener.contextInitialized(TilesListener.java:60)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:549)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1282)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:518)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:499)
(...)

Most of the time your application works, but sometimes it just does not start.

This is because of the dtd resolution mecanism: if you use the reference of a dtd which is not in the webapp classpath, the container will try to get it from internet.

If the remote site is down (in this case http://tiles.apache.org), your app will no longer start.

Sadly, it’s easy to get in this situation.

  • Upgrade a library without updating xml headers
  • Copy/Paste a snippet from the elsewhere

… and the container will start to fetch dtds from the internet.

In my case, the previous error was caused by :

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>
(...)
</tiles-definitions>

instead of :

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">

<tiles-definitions>
(...)
</tiles-definitions>

With tiles 2.0.6 in the classpath.

Conclusion
Be sure to use the exact version of the dtd in your classpath. Don’t pickup examples from the internet without double-checking the dtd.
This will prevent longer startup times and potential random errors.

Note: this post dedicated to Olivier and Jimmy :-)