Publié le 26 Mai 2010

La performance d'une appli java est bien entendu lié à la qualité de code écrit mais pas seulement. En effet une partie importante des performances est liée à l'utilisation (et donc à la configuration) du garbage collector.

 

Ceci pour la simple raison que le garbage collector peut interrompre notre application à tout moment pour nettoyer la mémoire. Dans ce cas on perd la main et on n'a plus aucun controle sur le temps d'exécution de notre application.

 

Petite parenthèse sur Java Real Time: Java Real Time n'est pas plus rapide qu'une JVM classique mais il offre la garantie que les phases de garbage collection ne dépassera pas une durée données (ex: 20 ms). Ce qui permet d'avoir un controle plus fin du temps d'exécution d'une appli java.

En revanche ça ne signifie pas que l'appli sera plus rapide en moyenne. Simplement on garantie que l'appli ne sera jamais bloqué plus de 20 ms par le GC.

 

Ceci étant dit, retournons à notre GC classique. Pour optimiser une application java il faut donc paramètrer la jvm pour éviter au maximum les phases de full garbage qui nettoie toute la mémoire allouée et qui peuvent parfois durer plusieurs secondes.

 

Pour ce faire il est essentiel de comprendre comment fonctionne le GC :

 

La JVM gère 3 espaces mémoires différents dans lesquels sont stockés les objets java:

 - la young generation

 - la old generation

 - permanent storage

 

Commençons par le plus trivial le permanent storage. Cet espace mémoire est alloué directement au démarrage de la JVM. Il contient les objets java permanent qui seront présent pendant toute la durée d'exécution.

 

Ensuite la young generation : c'est là où sont créées les nouvelles instances des objets java. L'exécution du GC sur cette partie de la mémoire reste assez performante.

La young generation peut contenir des zones "survivor space" où les objets seront copiés progressivement avant de migrer vers la old generation.

 

La old generation contient des objets assez vieux qui ont survécu un certain temps dans la young generation. L'execution du GC sur cette partie de la mémoire est très couteuse et c'est ce type d'exécution qu'il faut chercher à éviter. il faut donc mettre que les objets qui ne doivent pas être effacés.

 

Tout l'art du tuning de la JVM va consister à allouer des espaces mémoires appropriés pour les différentes zones afin d'atteindre le comportement souhaité.

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 20 Mai 2010

Voici un tutoriel expliquant comment stocker un google User dans Google App Engine puis comment le récupérer ensuite.

 

Tout d'abord il faut savoir que google permet d'utiliser les API JDO (Java Data Object) et JPA (Java Persistance API).

 

Ici nous allons utiliser JDO comme dans l'exemple du "Getting started" de google qui décrit très bien comment mettre en place cette API.

 

Ici nous allons nous intéresser uniquement à la définition des données, leur stockage et leur récuprération.

 

Tout d'abord il faut définir la classe que nous voulons stocker en base. Ici nous allons utiliser une classe Book très simple pour stoker un livre.

 

package com.over-blog.patatos.gap;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.users.User;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;


@PersistenceCapable
public class Book{
   
    @PrimaryKey
    @Persistent
(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;
   
    @Persistent
    private User owner;
   
    @Persistent
    private String title;
   
    public Book(User owner, String title){
        this.owner = owner;
        this.title = title;
    }
   
    public Key getKey(){
        return key;
    }
   
    public User getOwner(){
        return owner;
    }
   
    public String getTitle(){
        return title;
    }
   
    public void setOwner(User owner){
        this.owner = owner;
    }
   
    public void setTitle(String title){
        this.title = title;
    }
   
}

 

Comme vous avez pu le remarquer JDO utilise les annotations pour générer le modèle de données à stocker en base.

 

Nous allons maintenant écrire une petite servlet qui permettra de stocker un livre dans BigTable (la base de persistance du google app engine). Attention BigTable n'est pas une base de données relationnelle mais ça n'est pas un problème dans notre cas.

 

package com.over-blog.patatos.gap;

import java.io.IOException;

import javax.jdo.PersistenceManager;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class SaveBookServlet extends HttpServlet {

   public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
       
        String site = req.getParameter("title").trim();
       
        Book book = new Book(user, title);
        PersistenceManager pm = PMF.get().getPersistenceManager();
       
        try{           
            //sauvegarde notre objet "book"
            pm.makePersistent(book);
        }
        finally{
            pm.close();
        }
       
        resp.sendRedirect("/");
       
    }
   
}

 

PMF signifie Persistence Manager Factory. Il s'agit d'une classe créée dans le tutoriel google sur la mise en place de JDO.

 

Voici son code:

 

package com.over-blog.patatos.gap;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {
    private static final PersistenceManagerFactory pmfInstance =
        JDOHelper.getPersistenceManagerFactory("transactions-optional");

    private PMF(){}

    public static PersistenceManagerFactory get(){
        return pmfInstance;
    }
}

Voilà tout est prêt pour enregistrer un livre dans le google app engine. pour cela il suffit de créer un formulaire HTML qui pointe vers la servlet SaveBookServlet qui doit être définie dans web.xml.

 

Maintenant que nous avons vu comment enregistrer un objet dans google app engine voyons comment le récupérer:

Nous allons ici utiliser JDOQL qui est un language semblable à SQL qui permet de faire des requêtes JDO.

 

Nous allons générer une jsp qui va récupérer la liste des livres d'un utilisateur et les afficher dans un tableau HTML.

Nous utilisons JSP dans un souci de simplicité le mécanisme serait le même au sein d'une servlet.

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="javax.jdo.PersistenceManager" %>
<%@ page import="com.google.appengine.api.users.User" %>
<%@ page import="com.google.appengine.api.users.UserService" %>
<%@ page import="com.google.appengine.api.users.UserServiceFactory" %>
<%@ page import="com.over-blog.patatos.gap.Book" %>
<%@ page import="com.over-blog.patatos.gap.PMF" %>
<%@ page import="java.util.List" %>

<html>
  <body>


<%
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();
    if (user != null) {
%>
        <p>Hello, <%= user.getNickname() %>! (You can
        <a href="<%= userService.createLogoutURL(request.getRequestURI()) %>">sign out</a>.)</p>
<%        
        PersistenceManager pm = PMFactory.get().getPersistenceManager();        
        
        String query =  "select from " + Book.class.getName() +
           " where owner == ownerParam" +
           " parameters com.google.appengine.api.users.User ownerParam" +
           " order by title";
        List<Book> books = (List<Book>)pm.newQuery(query).execute(user);

        if(books.isEmpty()){
%>
            <p>You have no books yet</p>
<%
        }
        else{
%>
            <p>You read the following books:</p>
            <table>
             <thead>
              <tr><th>
Title</th></tr>
             </thead>
             <tbody>

<%
            for(Book b : books){
%>
                <tr><td><%= b.getTitle() %></td></tr>
<%
            }
%>
             </tbody>
            </table>

<%
        }
%>
        <form action="/savebook" method="post">
           <div>title: <input type="text" name="title" /></div>
           <div><input type="submit" value="add book" /></div>
        </form>
        
<%
    }
    else {
%>
        <p>Hello!
        <a href="<%= userService.createLoginURL(request.getRequestURI()) %>">Sign in</a> to save your books.</p>
<%
    }
%>
  </body>
</html>

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 19 Mai 2010

Pour exécuter une fonction définie dans un package Oracle sous sqlplus, il suffit de l'appeler au travers d'un "select from dual" de la manière suivante:

 

SELECT MON_PACKAGE.MA_FONCTION(mes, parametres) FROM DUAL;

Voir les commentaires

Rédigé par Bliz

Publié dans #Oracle

Repost 0

Publié le 18 Mai 2010

Pour changer la lettre d'un lecteur windows (par exemple la lettre d'un lecteur DVD ou clé USB, etc) - c'est à dire les fameux C:, D:, etc.

 

  • Faire un clic-droit sur le "poste de travail"
  • Sélectionner "Gérer"
  • Dans la fenêtre "Gestion de l'ordinateur", sélectionner "Stockage / Gestion des disques" dans le menu de gauche
  • Faire un clic-droit sur le lecteur dont on veut changer la lettre
  • Choisir "Modifier la lettre de lecteur et les chemins d'accès"
  • Puis faire "Modifier" et sélectionner la lettre désirée puis valider.

 

gestion-ordinateur.JPG

Voir les commentaires

Rédigé par Bliz

Publié dans #Office

Repost 0

Publié le 17 Mai 2010

Aujourd'hui je vais revenir sur un problème que j'avais rencontré dans un article précédent sur l'installation de l'environnement de dév de Google App Engine.

 

J'avais noté que lors du démarrage du serveur jetty (qui est le conteneur de servlet utilisé pour faire tourner les google apps en mode développement) apparaissaient quelques erreurs.

 

En fait il s'agit d'une exception java.net.ConnectException car la classe com.google.appengine.tools.info.RemoteVersionFactory n'arrive pas à accèder au net (notamment l'adresse suivante:

http://appengine.google.com/api/updatecheck?runtime=java&release=1.3.3.1&timestamp=1272042847&api_versions=['1.0']

 

Voici la trace d'erreur complète ci-dessous :

 

10 mai 2010 15:05:04 com.google.appengine.tools.info.RemoteVersionFactory getVersion
INFO: Unable to access http://appengine.google.com/api/updatecheck?runtime=java&release=1.3.3.1&timestamp=1272042847&api_versions=['1.0']
java.net.ConnectException: Connection timed out: connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
    at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
    at java.net.Socket.connect(Socket.java:519)
    at java.net.Socket.connect(Socket.java:469)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:163)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:394)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:529)
    at sun.net.www.http.HttpClient.<init>(HttpClient.java:233)
    at sun.net.www.http.HttpClient.New(HttpClient.java:306)
    at sun.net.www.http.HttpClient.New(HttpClient.java:323)
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:837)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:778)
    at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:703)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1026)
    at java.net.URL.openStream(URL.java:1009)
    at com.google.appengine.tools.info.RemoteVersionFactory.getVersion(RemoteVersionFactory.java:70)
    at com.google.appengine.tools.info.UpdateCheck.checkForUpdates(UpdateCheck.java:94)
    at com.google.appengine.tools.info.UpdateCheck.doNagScreen(UpdateCheck.java:164)
    at com.google.appengine.tools.info.UpdateCheck.maybePrintNagScreen(UpdateCheck.java:132)
    at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:150)
    at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48)
    at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:113)
    at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89)

 

Comme je l'avais supposé à l'époque il s'agit du proxy qui n'est pas configuré et donc pas moyen de se connecter sans passer par ce proxy.

 

Il faut donc indiquer à Google App Engine les coordonnées du proxy. Sous éclipse cela se fait de la manière suivante:

 

Sélectionner le menu Run / Open Run Dialog / Arguments

 

et ajouter les arguments "-Dhttp.proxyHost=<adresse_proxy> -Dhttp.proxyPort=<port_proxy>" pour préciser le proxy dans VM arguments:

 

 

-Xmx512m -Dhttp.proxyHost=<adresse_proxy> -Dhttp.proxyPort=<port_proxy> -javaagent:D:\AOSI-EclipseD2I-v1.3.1\extensions\eclipse-clearcase\eclipse\plugins\com.google.appengine.eclipse.sdkbundle.1.3.3_1.3.3.v201004231111\appengine-java-sdk-1.3.3.1\lib\agent\appengine-agent.jar

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 12 Mai 2010

Aujourd'hui une petite astuce pour améliorer le temps d'exécution d'une requête SQL Oracle lorsqu'on travaille sur de gros volumes de données, du genre plusieurs millions d'enregistrements.

 

Dans ce cas un simple SELECT peut prendre plusieurs minutes pour s'exécuter avant de retourner un résultat.

 

Voici donc comment paralléliser la requête et gagner du temps d'exécution:

 

SELECT mon_champ /*+ PARALLEL(ma_table 5)*/ FROM ma_table WHERE ....

Voir les commentaires

Rédigé par Bliz

Publié dans #Oracle

Repost 0

Publié le 11 Mai 2010

Pour installer des mises à jour ou de nouveaux plugins ou extensions, il faut qu'Eclipse puisse accèder au net pour pouvoir les télécharger.

 

Hors si vous vous trouvez derrière un proxy (ce qui est très souvent le cas dans les entreprises) ce mécanisme d'upgrade sera inopérant, à moins de configurer votre proxy dans Eclipse.

 

Pour se faire il faut ouvrir le menu : "Window / Preferences"

 

Puis naviguer dans  "General / Network Connections" dans l'arborescence de menu à gauche.

 

Ensuite vous n'avez plus qu'à cocher "Manual Proxy Configuration" et entrer les coordonnées (adresse IP, port) de votre proxy.

 

N'oubliez pas de définir les exclusions pour votre réseau local (ou autre) si besoin dans le tableau du dessous.

 

Eclipse-Network-Connection

Voir les commentaires

Rédigé par Bliz

Publié dans #Eclipse

Repost 0

Publié le 10 Mai 2010

Lorsqu'on installe MySQL (que ce soit seul ou dans un bundle tel que LAMP ou easyPHP), la base est configurée par défaut avec un user 'root' sans mot de passe (ou plus exactement avec un mot de passe vide '').

 

D'un point de vue sécurité ce n'est pas vraiment souhaitable et c'est même un risque à éviter.

 

Pour se faire il faut se connecter en tant que root à MySQL ce qui est faisable soit en ligne de commande avec:

 

# mysql mysql -u root

 

Soit en utilisant une interface d'administration telle que PHPMyAdmin.

 

 

Les users et mots de passe étant stockés dans une table spécifique de la base : la table 'user'.
Il faut donc modifier l'enregistrement de l'utilisateur 'root' à l'aide de la commande SQL suivante:

 

UPDATE user SET password=PASSWORD('nouveau_mot_de_passe') WHERE user='root';

 

Ensuite pour appliquer ces changements il faut utiliser le SQL suivant:

 

FLUSH PRIVILEGES;

Voir les commentaires

Rédigé par Bliz

Publié dans #MySQL

Repost 0