dimanche 14 février 2010

Création d'un site web pour la gestion de la liste des contacts d'un utilisateur

Le but est ici de développer un site web pour permettre à un utilisateur de gérer sa liste de contacts. Le site web devra donc permettre à un utilisateur de s'identifier à l'aide d'un pseudonyme et d'un mot de passe. S'il ne possède pas d'identifiant, le site lui permettra d'en créer un et il sera directement enregistré dans la base de données.
Une fois enregistré, l'utilisateur pourra gérer sa liste de contacts. Il pourra ainsi la consulter, et ajouter ou supprimer un contact à cette liste.
Pour l'accès aux données, nous utilisons des EJB (ceux déjà utilisés pour la conception du webservice).
Nous avons donc, d'une part un conteneur d'EJB qui permet de mapper un accès à la base de données, et d'autre part un conteneur WEB où nous utilisons JSF pour la partie interface client, et un javaBean pour tout ce qui est gestion de données.

Nous aurons donc des classes java beanManaged avec lesquelles nous pourront utiliser les attributs de la manière suivante :

public class beanManaged {


private String contactName;
private String contactMdp;
...
}

Ces attributs nous permettrons de récupérer les valeurs saisies dans les inputsText de la page en JSP de la manière suivante :

<h:form>
<h:outputText value="user : "></h:outputText>

<h:inputText id="inputTxtUser1" value="#{beanManaged.contactName}"&lt&gt/h:inputText&lt
<h:outputText value="Mot de passe : "></h:outputText>

<h:inputText id="inputTxtMdp1" value="#{beanManaged.contactMdp}"></h:inputText

></h:form>

Le beanManaged contient aussi toutes les fonctions permettant la recherche et la validation de données en faisant appel aux EJB (avec une interface FaçadeRemote). Nous avons donc par exemple des fonctions permettant l'enregistrement d'un utilisateur, la suppression d'un contact, l'ajout d'un contact etc.

dimanche 7 février 2010

Couche de persistance des données

Pour accéder à la base de données de l'application, nous avons utiliser les fonctionnalités de persistance proposées par l'API Java.
Pour cela, les assistants de netbeans facilitent grandement la mise en place. Néanmoins pour revenir sur les éléments nécessaires, on a besoin:
- D'un pool de connection.
- D'un nom jndi associé au pool.
- D'un persitence unit.
Ceci peut être crée à la main dans la console d'admin de glassfish ou pratiquement automatiquement en suivant ce processus:
  1. Créer un package db par exemple
  2. Clique droit > New > Entity classes from database...
  3. A ce moment là si le DataSource n'est pas crée, Netbeans propose un assistant pour le crée.
  4. Une fois les classes sélectionnées, Un assistant propose de créer un persitence unit en se basant sur le nom jndi du pool de connection précédemment crée.
  5. Une fois les entity créées, créer un autre package ejb par exemple.
  6. Clique droit sur ce package > New > Beans Sessions for Entity Classes...
Et voila, en quelques cliques nous avons de beaux EJB beans sessions permettant d'accéder à la base de données. Très pratique ces assistants de Netbeans quand même !!

Transformer des coordonnées GPS en une distance

Les données enregistrées dans la base de données sont une longitude et une latitude données en degrés.
Évidemment la comparaison des coordonnées GPS ne fournit pas des distances en kilomètres !!
Ainsi, déterminer la proximité d'un amis par rapport à une coordonnée GPS n'est pas un calcul trivial. Nous avons utiliser un calcul que nous avons trouvé sur un forum après recherches sur google et qui se révèle être; après quelques tests; plutôt proche de la réalité.
Voici le calcul utilisé:
d = R * (pi/2 - asin ( sin x1 * sin x2 + cos ( y1 - y2 ) * cos x1 * cos x2 ));
avec
d distance entre les 2 points
R rayon de la Terre
x1 lattitude en radians du 1er point
x1 lattitude en radians du 2eme point
y1 longitude en radians du 1er point
y1 longitude en radians du 2eme point

On voit qu'il faut encore transformer les données puisque le calcul utilise les radians alors que nous fournissons des degrés. Encore une fois une recherche rapide sur google fournit ces informations:

radians = degres * PI / 180
Implémenter ceci en java est relativement simple:

/**
*
* @author Yann Loiseau
*/
public class GPS {
public static float degres2radians(float degres){
return (float) (degres * Math.PI / 180);
}

static float getKilometers(float lattitude1, float lattitude2, float longitude1, float longitude2) {
return (float) (6378 * (Math.PI / 2 - Math.asin(Math.sin(GPS.degres2radians(lattitude1)) * Math.sin(GPS.degres2radians(lattitude2)) + Math.cos(GPS.degres2radians(longitude1) - GPS.degres2radians(longitude2)) * Math.cos(GPS.degres2radians(lattitude1)) * Math.cos(GPS.degres2radians(lattitude2)))));
} //d = R * (pi/2 - asin ( sin x1 * sin x2 + cos ( y1 - y2 ) * cos x1 * cos x2 ));
}





Web Application: partie métier du serveur basée sur un Web Service

Pour permettre à l'application client de mettre à jour ses coordonnées GPS et récupérer la liste des amis qui sont proches, nous avons fait le choix de créer un Web Service qui assurera cette fonction. Notre Web Service possède une seule opération pour l'instant:
@WebMethod(operationName = "UpdateCoordonnees")
public ArrayList UpdateCoordonnees(@WebParam(name = "Nom") String Nom, @WebParam(name = "Longitude") float Longitude,
@WebParam(name = "Latitude") float Latitude)

Plus simplement: notre opération prend 3 paramètres en entrée: le nom du contact qui l'interroge et ses coordonnées GPS: latitude et longitude.
Elle retourne un tableau de type contact simple qui est une classe contenant quatre attributs:

public class ContactSimple {
private String Nom;
private String Numero;
private float Longitude;
private float Latitude;
}


Netbeans s'occupe lui même de créer la structure XML.

C'est une fonctionnalité de Netbeans que j'ai trouvé assez pratique pour la création d'un Web Service. Il s'occupe évidemment de crée le wsdl mais également le fichier de description XML (.xsd) décrivant la structure des données utilisées pour les paramètres d'entrée et de sortie de l'opération.


Le Web Service utilise la couche de persistance des données pour enregistrer ou récupérer des données de la base.

Coté base de données

L'organisation du stockage des données s'est fait de manière très simple: en utilisant phpmyadmin. En effet le projet est expérimental et la solution la plus simple s'est imposée comme la meilleure!
Structure de la table:



Les points à noter sont:
Champ Date dans la table CoordonneesGPS est de type timestamp qui permet qu'il soit rempli automatiquement à l'insert.

Les relations entre Contact, Liste, ContactListePivot sont ainsi car un contact appartient à une liste de quelqu'un d'autre et en même possède une liste. Celà se traduit par une clé étrangère dans la table Liste pour modéliser le propriétaire de la liste et la création d'une table pivot contenant les clés étrangères de la liste et du contact pour modéliser l'appartenance.

Application coté serveur

Coté serveur, nous nous sommes basé sur une architecture distribuée utilisant le serveur d'application Glassfish. Plusieurs composants distincts forment cette architecture. Netbeans IDE 6.8 a constitué le support de développement.
Pour commencer il faut créer un projet de type Entreprise Application sous Netbeans. Pour le serveur nous avons pris Glassfish v3 dans un premier temps même si il a fallut switcher avec la v2.1 régulièrement car il y a eu quelques bugs incompréhensibles au moment du déploiement de l'application (erreurs du type The Module has not been deployed) que nous avons résolu en redémarrant le serveur ou en changeant carrément de version. Pour la version de Java EE: la 5 pour des soucis de compatibilité entre Glassfish v2.1 et v3.
Donc une fois l'entreprise application créée, on se retrouve avec deux modules: une Web App et un projet EJB. On s'est servi de la Web App pour la partie métier notamment en créant un Web Service pour ces traitements. Le projet EJB nous a servi pour l'accès aux données à l'aide des mécanismes de persistance.

Dans les prochains billets je traiterais en détail de ces deux composantes de l'architecture.

samedi 6 février 2010

Consommer un webservice dans une application mobile

Pour utiliser un web service dans une application mobile en c#, le principe est le même que dans une application c# classique.

Tout d'abord, il faut ajouter la référence du service au projet mobile (clic droit -> ajouter une référence Web) , on entre alors l'adresse du web service, on le nomme et on valide.

On peut à tout moment connaitre le contenu du web service en faisant un clic droit -> Afficher dans l'explorateur d'objets. Cela permet de connaitre les méthodes proposée, et les types utilisés.

Pour utiliser un web service, il faut l'instancier :
WebService.NomDuService ws = new WebService.NomDuService();
On peut alors faire des appels aux méthodes présents :
ws.maMethodeWeb();
De même, on peut utiliser un type présent dans un web service :
WebService.MonType montype;
Cela peut s'avérer utile lorsque le web service demande des paramètres particuliers ou lorsqu'il retourne une valeur d'un type non simple.

vendredi 5 février 2010

Proposer de passer un appel

Lorsqu'un utilisateur de notre application envoie sa position, il souhaite connaitre les noms et les numéros des personnes proches de lui. Pour lui éviter de devoir retaper le numéro, nous proposons d'appeler directement.

Pour cela, il suffit d'utiliser un code très simple mais pas forcément évident à trouver sur Internet :
Microsoft.WindowsMobile.Telephony.Phone myPhone = new Microsoft.WindowsMobile.Telephony.Phone();
myPhone.Talk("0123456789", true);

Il ne faut pas oublier d'inclure
Microsoft.WindowsMobile.Telephony;

Récupérer une carte depuis google maps

Pour permettre à l'utilisateur d'avoir un plan dans l'application, nous avons utilisé Google Maps. En effet, Google met à sa disposition des outils afin de récupérer une carte d'un endroit souhaité.

Pour nous aider, nous nous sommes fortement inspirés du tutoriel proposé par Pierre Cauchois.

Nous avons donc créé deux paramètres dans notre fichier de ressources : un pour l'url de l'application google maps, et un deuxième pour la clé nécessaire à la connexion à cette application.

Pour l'url, nous avons mis le paramètre GoogleMapsBaseUrl avec la valeur suivante : http://maps.google.com/staticmap? (avec le point d'interrogation)

Pour la clé, nous sommes allés sur ce site, et en bas, nous avons rempli l'url par http://localhost .
Google nous a retourné une clé que nous avons ajouté comme valeur d'un paramètre que nous avons nommé GoogleMapsApiKey.

Puis, pour faire la requête auprès de google, nous avons utilisé le code suivant :
Bitmap myMap = null;
#region Construction des arguments de l'URL
StringBuilder args = new StringBuilder();
args.Append("center=" + lat + "," + lng);
args.Append("&zoom=12");
args.Append("&size=" + 480 + "x" + 380);
args.Append("&format=png");
args.Append("&maptype=mobile");
args.Append("&markers=" + lat + "," + lng + "," + "blue");
args.Append("&key=" + Properties.Resources.GoogleMapsApiKey);
args.Append("&sensor=false");
#endregion
try
{
WebRequest myRequest = WebRequest.Create(Properties.Resources.GoogleMapsBaseUrl + args.ToString());
WebResponse myResponse = myRequest.GetResponse();
myMap = new Bitmap(myResponse.GetResponseStream());
myResponse.Close();
}
catch (WebException ex)
{
MessageBox.Show(ex.Message);
}


Ce code nous permet de passer les coordonnées à google qui nous retourne la carte correspondante. Nous pouvons alors utiliser cette carte pour l'afficher à l'utilisateur.

Problèmes et réorganisation

Nous avions prévu de travailler avec Azure pour ce projet mais nos comptes n'étant plus actifs depuis le 1er février 2010, cela pose quelques petits problèmes...
Nous sommes donc passés sur des web services en java sur un serveur glassfish pour pouvoir continuer le projet.

La partie mobile a également eu quelques ralentissements dus à des problèmes sur les téléphones reçus. Certains problèmes sont toujours présents mais nous allons tout de même continuer notre application avec les moyens possibles pour arriver à un résultat le plus proche du but premier.