Le blog d'Arcade Village

De l'applet vers l'application (Partie 4) : cookies

Nous arrivons à la dernière partie de cette série d'articles donnant des pistes pour transformer vos applets en applications.
Les navigateurs offraient aux applets la possibilité de sauver des données sous la forme de cookies. C'est ce que nous allons étudier aujourd'hui.
Netscape proposait de communiquer avec le navigateur par l'intermédiaire de la classe JSObject. Celle-ci permettait d'appeler des fonctions javascript ou d'accéder aux cookies.

Les jeux d'ArcadeVillage l'utilisaient pour conserver leurs meilleurs scores. J'avais créé un objet Cookie que je mets ici à titre indicatif :

import java.util.*;
import java.text.SimpleDateFormat;
import java.applet.Applet;
import netscape.javascript.JSObject;
import netscape.javascript.JSException;


/**
* Cookies
*
*
* The cookies class represent a persistent set of properties.

* The properties can be saved or loading by cookies on the page

* Each key is a String. The value is a string with a date associated

*
* @see Hashtable
* @see Properties
*
* @since JDK 1.1
*
*/

public class Cookies extends Hashtable
{

/**
*
* Default number of day to keep a cookie
*
*/
public int dd = 30;

protected class CookieValue
{
String value;
Calendar exp;
}
/**
*
* Creates an empty cookies list with no default values.
*
*/
public Cookies()
{
}

/**
*
* Creates an empty cookies list with a default number of day to keep the cookies.
* @param dd - the time in days to keep the cookie ( default is 30 ) .
*
*/

public Cookies( int dd )
{
super();
this.dd = dd;
}
/**
*
* Load the cookies list associated to the document where is the given applet.
* @param a - the applet.
*
*
*/

public synchronized void load( Applet a )
{
String key;
CookieValue cv;
//
// Now, we search all the cookies. Each cookies is separated by a ';'
//
int is = 0;
int i = 0;
try
{
JSObject win = JSObject.getWindow(a);
JSObject doc = (JSObject)win.getMember("document");
String s = ( String )doc.getMember("cookie" );
while ( is < s.length() )
{
// First we seach a =
cv = new CookieValue();
i = s.indexOf("=", is);
if ( i == -1 )
{
System.out.println("Error in cookie string :"+s);
return;
}
key = s.substring(is, i);
is = ++i;
// Now we search a ;
i = s.indexOf(";", is);
if ( i == -1 )
{
cv.value = s.substring(is);
is = s.length();
}
else
{
cv.value = s.substring(is,i);
is = i + 1; // Because the return string add a blank;
if ( s.charAt(is)==' ' ) is++;
}
put( key, cv );
}
}
catch( Exception e )
{
System.out.println("Load :"+e);
}
}
/**
*
* Returns an enumeration of all the keys in this property list, including the keys in the default property list.
* @return : an enumeration of all the keys in this property list, including the keys in the default property list.
*
* @see Enumeration
*
*/

public Enumeration propertyNames()
{
return this.keys();
}

/**
*
* Save the cookies list associated to the document where is the given applet.
* @param a - the applet.
*
*
*/
public synchronized void save( Applet a )
{
String s = "";
String sdate;
String k;
CookieValue cv;
SimpleDateFormat df = new SimpleDateFormat("EEE, d MMM yyyy hh:mm:ss", Locale.US);
//
// We take all the properties and create a cookie string
//
Enumeration e = this.keys();
while ( e.hasMoreElements() )
{
k = ( String )e.nextElement();
cv = ( CookieValue )get(k);
if ( s.length() != 0 ) s = s + ";";
sdate = cv.exp == null ? "" : "+'; expires="+df.format(cv.exp.getTime())+" UTC'";

s = s + "'"+k+"='+escape('"+cv.value+"')"+sdate;
}
try
{
JSObject win = JSObject.getWindow(a);
s = "document.cookie="+s+";";
win.eval(s);
}
catch( Exception ex )
{
System.out.println("Cookie : "+ex);
}


}

/**
*
* Searches for the property with the specified key in this property list. If the key is not found in this property list, the default property list, and its defaults, recursively, are then checked. The method returns null if the property is not found.
* @param key - the property key.
* @return the value in this property list with the specified key value.
*
*/

public String getProperty(String key)
{
CookieValue v = ( CookieValue )this.get(key);
return( v == null ? null : v.value );
}

/**
*
* Searches for the property with the specified key in this property list.

* If the key is not found in this property list, the default property list, and its defaults, recursively, are then checked.

* The method returns the default value argument if the property is not found.

* Parameters:
*
* @param key - the hashtable key.
* @param defaultvalue - a default value.
*
* @return the value in this property list with the specified key value.
*
*/

public String getProperty(String key,
String defaultValue)
{
String s = getProperty(key);
return( s == null ? defaultValue : s );
}

/**
*
* Put the property with the specified key in the property list.
* The expiration date of the property is the default expiration date
public void setProperty(String key, String val )
{
setProperty(key, val, dd );
}

/**
*
* Put the property with the specified key in the property list with the given
* expiration date
*
* @param key - the hashtable key.
* @param val - the value.
* @param nday - the number of day to keep the cookie.
*
*
*/
public void setProperty(String key, String val, int nday )
{
CookieValue v = new CookieValue();
v.value = val;
v.exp = Calendar.getInstance();
v.exp.add( Calendar.DAY_OF_MONTH, nday );
put( key, v );
}
}


Mon objet Cookies dérivait de Hashtable et permettait d'aasocier des valeurs avec une clé et de sauver ou charger ces valeurs par JSObject.

Le navigateur associait les cookies à une page internet.

Lorsque nous travaillons avec des applications, il n'y a plus de navigateur, c'est donc à nous de spécifier où stocker et retrouver les cookies.

La plupart des systèmes d'application offre un espace disque associé à l'utilisateur. Le chemin vers cet espace est donné par le code :
System.getProperty("user.home")

En remplacement de l'objet Hashtable, j'utilise, tout comme pour les paramètres, l'objet Properties qui offre la possibilité de sauvegarder ses valeurs sous la forme d'un fichier XML.

Le navigateur associait les cookies à une URL. J'ai donc imité son fonctionnement. Mon nouvel objet est créé en spécifiant un répertoire de stockage.
Chaque fichier est donc stocké dans un répertoire différent, sous-répertoire du répertoire utilisateur.

La fonction getPathName de mon objet donne le nom du fichier de sauvegarde.

private String getPathName()
{
String s = System.getProperty("user.home")+System.getProperty("file.separator")+"arcadevillage"+System.getProperty("file.separator")+this.dock;
s = this.majSeparator(s);
return s;
}

private String getFileName()
{
return this.getPathName()+System.getProperty("file.separator")+"acm.ini";
}


Les répertoires de sauvegarde son en plus fils d'un répertoire "arcadevillage". J'ai fait ce choix pour ne pas perturber d'éventuels autres programmes qui utiliseraient les mêmes noms de fichier. Ma ancienne classe Cookies est donc remplacée dans les applications par la classe AppletCookieManager.
Voici le code de cette nouvel classe.

package cccookie;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.Properties;


public class AppletCookieMgr
{
private URL docbase;
private String dock; // Le répertoire où seront sauvés les cookies
private Properties params = new Properties();

public AppletCookieMgr( URL idocbase )
{
this.docbase = idocbase;
this.dock = this.docbase.getPath();
this.dock = this.majSeparator(this.dock);
this.dock = this.dock.replace(System.getProperty("user.dir"), "");
}

public AppletCookieMgr( String sdock )
{
this.dock = sdock;
}

public void load()
{
FileInputStream f;
try
{
f = new FileInputStream(this.getFileName());
// load a properties file
params.load(f);
f.close();
}
catch (Exception ex)
{
params.clear(); // Pas de fichier, on vide
}
}

private String majSeparator( String s )
{
s = s.replace("/", System.getProperty("file.separator"));
s = s.replace("", System.getProperty("file.separator"));
return s;
}
private String getPathName()
{
String s = System.getProperty("user.home")+System.getProperty("file.separator")+
"arcadevillage"+System.getProperty("file.separator")+this.dock;
s = this.majSeparator(s);
return s;
}

private String getFileName()
{
return this.getPathName()+System.getProperty("file.separator")+"acm.ini";
}

public int getInteger( String name, int defvalue )
{
String s = getString( name );

return ( s == null ? defvalue : Integer.parseInt(s) );
}

public String getString( String name )
{
return params.getProperty(name, null);
}

public void setInteger( String name, int value )
{
setString(name, String.valueOf(value));
}

public void setString( String name, String value )
{
params.setProperty(name, value);
}

public void flush()
{
FileOutputStream f;
File rep=new File(getPathName());
if ( !rep.exists())
{ // Le répertoire doit être crée
if (!rep.mkdirs() )
{
System.out.println("Le répertoire "+getPathName()+" n'a pas été créé");
return;
}
}
try
{
f = new FileOutputStream(this.getFileName());
params.store(f, "cookie");
}
catch( Exception ex )
{
ex.printStackTrace();
}
}

}


Nous avons maintenants toutes les étapes permettant de transformer une applet en application sans trop modifier le code de celle-ci.
ArcadeVillage.com 1999 - 2024