2011-01-19 - standalone soap server en java

Ayant divers projets de plugins java sur une application existante (application “lourde”, sans tomcat ou autre futilité dans ce contexte bien précis), je me penche sur les différentes classes disponibles ici et là, afin de ne pas ré-inventer la roue une nouvelle fois.

jSoapServer

Je viens de “tomber” sur jSoapServer, un ensemble de classes aux fonctionnalités bien allêchantes...

Avant de commencer a coder quoi que ce soit, je vais rapidement tester la chose, via la petite démonstration disponible dans l'archive zip disponible sur le site.

Démo

Après de rapides modifications au script shell fourni (pour adaptation au shell que j'utilise), et rapide vérification de "ce qui va se passer", je lanec donc la démonstration.

La chose s'initialise rapidement, et bind deux ports tcp/8090 pour le webservice en lui-même, et tcp/9080 pour la console d'administration (telnet).

Durant la phase de développement, disposer d'un wsdl automatiquement synchronisé avec le code du webservice s'avère être un atoût non négligeable. jSoapServer dispose de cette fonctionnalité, il en va de même pour la démo.

Configuré sur les ports par défaut, l'accès au wsdl se fait sur http://localhost:8090/test. Parfait, voilà tout ce dont nous avons besoin pour faire un rapide essai depuis un client SOAP écrit dans un autre langage que le java.

Essai depuis un client perl

Pour faire simple (et changer un peu), essayons depuis un petit client perl reposant sur SOAP::Lite

 1 #!/usr/bin/perl
 2 #
 3 # client_test.pl :
 4 #
 5 use strict;
 6 use SOAP::Lite;
 7 
 8 my $wsdl = 'http://localhost:8090/test';
 9 
10 my $client = SOAP::Lite->service($wsdl);
11 $client->outputxml(1); # we now want to see full xml response :p
12 
13 print $client->testIntAdd(42, 1);

Une éxécution plus tard, notre micro-client perl nous affiche la réponse attendue, en xml, comme demandé :

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 3  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 4  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 5   <soapenv:Body>
 6    <ns1:testIntAddResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 7     xmlns:ns1="http://jSoapServer.org">
 8      <testIntAddReturn xsi:type="xsd:int">43</testIntAddReturn>
 9    </ns1:testIntAddResponse>
10   </soapenv:Body>
11 </soapenv:Envelope>

Sauf erreur de ma part ... 42 + 1 ... donne bien 43 :p

Ensuite...

La prochaine étape va consister en l'écriture d'un petit serveur soap autonome, from scratch, n'utilisant que jSoapServer, via inclusion des archives jar dans notre build.xml (ant).

Ensuite, s'il s'avère que la chose reste légère et souple, exposer différentes méthodes sur nos plugins java sera un jeu d'enfant, et facilitera la communication entre nos applications tierces, et nos plugins.


Posté par a.lm | Lien permanent | Classé sous: java, programming, soap, webservice

2011-01-16 - soap webservices et php - nusoap et mode wsdl

Après avoir fait joujou avec Zend_Soap_Server, j'ai cherché quelque chose de plus léger et me suis penché sur NuSOAP.
Facilitant le développement de webservices, grâce à son auto-génération de wsdl, différents problêmes n'ont pas tardé à pointer leur nez :

Une même version de nusoap ne fonctionne tout simplement pas d'une version de php à une autre ... y compris sur une même “minor” version ...
Faire fonctionner le serveur (basé sur nusoap donc) en mode wsdl est un peu pénible également et au final on se vois perdre pas mal de temps inutilement sur des problêmes qui n'existent pas lorsque l'on utilise directement l'implémentation php.

Voilà pourquoi - contrairement aux avis bien tranchés de certains - je me contenterais dorénavant d'utiliser l'implémentation php pour ce qui concerne soapServer (retour en arrière non négligeable dans le temps) ...

Voici donc un exemple simplissime de webservice soap en php, en mode wsdl :

Le serveur

On repose ici sur la version module apache de php (php 5.3.5 sous apache 2.2.16 sur la machine concernée).
(je me répête, ceci est une version minimaliste, sans gestion d'erreur ou presque...)

 1 <?php
 2 /**
 3  * @file ws.php
 4  * @brief minimalist sample soap webservice.
 5  * @details reachable at http://soap.localhost/ws.php
 6  */
 7 
 8 // defines and registers our custom autoloader:
 9 require_once('bootstrap.php');
10 
11 // path to static wsdl (may eventually be set to a full url) :
12 $wsdl = 'wsdl/subscription.wsdl';
13 
14 // only useful while tuning your wsdl file:
15 //ini_set("soap.wsdl_cache_enabled", 0);
16 
17 // sample, simple options:
18 $soap_options = array(
19     'soap_version'  => SOAP_1_2,
20     'encoding'      => 'UTF-8'
21 );
22 
23 // instantiate a server using php implementation, binded to our wsdl :
24 $srv = new soapServer($wsdl, $soap_options);
25 
26 // attach a single class containing methods exposed by this webservice:
27 $srv->setClass('My_Ws_Service_Subscription'); // our autoloader knows where to find this
28 
29 // handle request and send response to agent:
30 $srv->handle();
31 
32 ?>

Méthodes exposées

Pour faire simple, toutes les méthodes exposées par un même webservice sont issues d'une seule classe ; en voici un exemple:

 1 <?php
 2 /**
 3  * @file classes/My/Ws/Service/Subscription.class.php
 4  * @brief methods exposed by webservice from /ws.php
 5  */
 6 
 7 /**
 8  * @brief simple sample for ws.php soap webservice.
 9  * @details all public methods from this class are exposed by webservice.
10  * @note My_Ws_Service_Base may be used to expose 'shared' methods.
11  */
12 class My_Ws_Service_Subscription extends My_Ws_Service_Base {
13 
14     /**
15      * @brief retrieves some informations on given user subscription.
16      * @param integer $userInternalId our internal user identifier.
17      * @param integer $serviceId identifier for one of our public services.
18      * @return array subscription fields/informations.
19      */
20     public function getinfo($userInternalId, $serviceId) {
21         $uselessExample = array(
22             'registration_stamp'    => 3451191601110150,
23             'expiration_stamp'      => 3451191631110150,
24         );
25 
26         return ($uselessExample);
27     }
28 }
29 
30 ?>

Le wsdl correspondant

Maintenant que le code du “serveur” est en place, écrivons le fichier wsdl utilisé pour décrire le webservice ; ce fichier sera le seul élément nécéssaire aux consommateurs du webservice pour l'écriture de clients.

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <definitions xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
 3     xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 5     xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
 6     xmlns:tns="http://soap.localhost/soap/subscription" 
 7     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
 8     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
 9     xmlns="http://schemas.xmlsoap.org/wsdl/" 
10     targetNamespace="http://soap.localhost/">
11 
12 <types>
13  <xsd:schema targetNamespace="http://soap.localhost/">
14  <xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
15  <xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" />
16  </xsd:schema>
17 </types>
18 
19 <!-- our input / output messages : -->
20 <message name="getinfoRequest">
21  <part name="user_id" type="xsd:integer" />
22  <part name="service_id" type="xsd:integer" />
23 </message>
24 <message name="getinfoResponse">
25  <part name="registration_stamp" type="xsd:integer" />
26  <part name="expiration_stamp" type="xsd:integer" />
27 </message>
28 
29 <!-- our supported operations (methods) and their i/o parameters : -->
30 <portType name="subscriptionPortType">
31  <operation name="getinfo">
32   <input message="tns:getinfoRequest"/>
33   <output message="tns:getinfoResponse"/>
34  </operation>
35 </portType>
36 
37 <!-- describes our operations : -->
38 <binding name="subscriptionBinding" type="tns:subscriptionPortType">
39  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
40  <operation name="getinfo">
41   <soap:operation soapAction="http://soap.localhost/ws.php/getinfo" style="rpc"/>
42    <input><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
43    <output><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
44  </operation>
45 </binding>
46 
47 <!-- describe our webservice: -->
48 <service name="subscription">
49  <port name="subscriptionPort" binding="tns:subscriptionBinding">
50   <soap:address location="http://soap.localhost/ws.php"/>
51  </port>
52 </service>
53 
54 </definitions>

Partie clients

Maintenant que nous sommes supposés avoir un webservice, il est temps de l'appeller :

 1 <?php
 2 /**
 3  * @file test_client.php
 4  * @brief simple soapclient for our test webservice.
 5  * @note minimalist sample.
 6  */
 7 
 8 // either use local copy of wsdl file, or point it to its url:
 9 $wsdl = "http://soap.localhost/wsdl/subscription.wsdl";
10 
11 // create a new soap client using provided wsdl :
12 $client = new SoapClient($wsdl);
13 
14 // call 'getinfo' remote method with our two 'integer' parameters:
15 $response = $client->getinfo(23, 42);
16 
17 // let's see...
18 var_dump($response);
19 
20 ?>

Essayons également depuis un petit client perl:

 1 #!/usr/bin/perl
 2 
 3 use strict;
 4 use SOAP::Lite;
 5 
 6 my $wsdl = 'http://soap.localhost/wsdl/subscription.wsdl';
 7 
 8 my $client = SOAP::Lite->service($wsdl);
 9 
10 $client->outputxml(1); # remove me :p
11 
12 # optional HTTP basic auth:
13 sub SOAP::Transport::HTTP::Client::get_basic_credentials {
14         return 'soaplite' => 'authtest';
15 }
16 
17 print $client->getinfo(23, 42);

Posté par a.lm | Lien permanent | Classé sous: programming, php, soap, webservice

2011-01-13 - webservice soap en php avec generation automatique du wsdl

Si vous avez déjà écrit un webservice soap, vous savez à quel point la génération du wsdl peut être pénible et fastidieuse, d'autant plus si vous écrivez votre webservice en PHP.

Générer dynamiquement un wsdl correspondant réellement au code exposé peut s'avérer très pratique, notamment durant la phase de développement de vos applications. C'est ce que je vais décrire ici : générer automatiquement et dynamiquement le wsdl correspondant à un webservice.

Dépendances

Le framework Zend propose la fonctionnalité désirée via Zend_Soap_AutoDiscover.
Le code indiqué ici est écrit avec ZendFramework 1.11.2 sur php 5.3.3

Arborescence

Pour faire compliqué, je ne vais pas utiliser les scripts en ligne de commande de Zend, pour générer l'arborescence/squelette du projet, mais la créer manuellement.
(nous utiliserons ~/projects/webservice comme répertoire racine).

1 mkdir -p ~/projects/webservice
2 cd ~/projects/webservice
3 mkdir -p application/views/scripts/error
4 mkdir application/views/scripts/index
5 mkdir application/controllers
6 mkdir application/configs
7 mkdir public
8 mkdir -p library/Exposed
9 mkdir library/Zend

Voici à quoi doit ressembler votre arborescence :

 1 ./application
 2 ./application/views
 3 ./application/views/scripts
 4 ./application/views/scripts/error
 5 ./application/views/scripts/index
 6 ./application/controllers
 7 ./application/configs
 8 ./public
 9 ./library
10 ./library/Exposed
11 ./library/Zend

librairie Zend locale

Nous installons maintenant localement une copie du répertoire “library/Zend” sous library/Zend/ (méthode “moche”) :

1 mkdir /tmp/zf
2 cd /tmp/zf
3 tar zxvf /tmp/ZendFramework-1.11.2.tar.gz
4 mv ZendFramework-1.11.2/library/Zend/* ~/projects/webservice/Zend/

(le fichier Version.php de Zend doit être directement sous library/Zend/Version.php)

Ré-écriture d'url

Pour que Zend “retrouve ses petits”, nous créons public/.htaccess :

1 # public/.htaccess
2 RewriteEngine On
3 RewriteCond %{REQUEST_FILENAME} -s [OR]
4 RewriteCond %{REQUEST_FILENAME} -l [OR]
5 RewriteCond %{REQUEST_FILENAME} -d
6 RewriteRule ^.*$ - [NC,L]
7 RewriteRule ^.*$ index.php [NC,L]

Point d'entrée

Au tour de public/index.php :

 1 <?php
 2 /**
 3  * @file public/index.php
 4  */
 5 
 6 // Define path to application directory
 7 defined('APPLICATION_PATH')
 8     || define('APPLICATION_PATH', realpath(dirname(__FILE__) .
 9         '/../application'));
10 
11 // Define application environment
12 defined('APPLICATION_ENV')
13     || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ?
14         getenv('APPLICATION_ENV') : 'production'));
15 
16 // Ensure library/ is on include_path
17 set_include_path(implode(PATH_SEPARATOR, array(
18     realpath(APPLICATION_PATH . '/../library'),
19     get_include_path(),
20 )));
21 
22 /** Zend_Application */
23 require_once 'Zend/Application.php';
24 
25 // Create application, bootstrap, and run
26 $application = new Zend_Application(
27     APPLICATION_ENV,
28     APPLICATION_PATH . '/configs/application.ini'
29 );
30 
31 $application->bootstrap()
32     ->run();
33 
34 ?>

Page d'erreur pour debug

application/views/scripts/error/error.phtml :

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 5  <title>Zend Framework Default Application</title>
 6 </head>
 7 <body>
 8  <h1>An error occurred</h1>
 9  <h2><?php echo $this->message ?></h2>
10  <?php if (isset($this->exception)): ?>
11 
12  <h3>Exception information:</h3>
13  <p>
14   <b>Message:</b> <?php echo $this->exception->getMessage() ?>
15  </p>
16 
17  <h3>Stack trace:</h3>
18  <pre><?php echo $this->exception->getTraceAsString() ?></pre>
19 
20  <h3>Request Parameters:</h3>
21  <pre><?php echo var_export($this->request->getParams(), true) ?></pre>
22  <?php endif ?>
23 
24  </body>
25  </html>

Page par defaut

Pour tout de même afficher quelque chose lors de requêtes “mal placées” - application/views/scripts/index/index.phtml

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 3 <head>
 4  <meta http-equiv="content-type" content="text/html;charset=utf-8" />
 5  <title>Nothing here</title>
 6 </head>
 7 <body>
 8  <p>Nothing here</p>
 9 </body>
10 </html>

bootstrap zend

au tour du bootstrap : application/Bootstrap.php

1 <?php
2 
3 class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
4 {
5 
6 
7 }
8 
9 ?>

Configuration de notre application

Plutôt classique, hormis “rootUrl” et “autoloadernamespaces[]” : application/configs/application.ini

 1 [production]
 2 phpSettings.display_startup_errors = 0
 3 phpSettings.display_errors = 0
 4 includePaths.library = APPLICATION_PATH "/../library"
 5 bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
 6 bootstrap.class = "Bootstrap"
 7 ; enable autoloader for library/Zend/ and library/Exposed/ :
 8 autoloadernamespaces[] = "Zend"
 9 autoloadernamespaces[] = "Exposed"
10 resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
11 resources.frontController.params.displayExceptions = 0
12 ; rootUrl : uri containing '/public/' directory (for soap wsdl):
13 rootUrl = "/"
14 
15 [staging : production]
16 
17 [testing : production]
18 phpSettings.display_startup_errors = 1
19 phpSettings.display_errors = 1
20 
21 [development : production]
22 phpSettings.display_startup_errors = 1
23 phpSettings.display_errors = 1
24 resources.frontController.params.displayExceptions = 1

Classe exposée

Pour un webservice donné (un controller zend), l'ensemble des méthodes de la classe indiquée dans notre futur controller sera exposé par notre webservice : library/Exposed/Subscription.php

 1 <?php
 2 
 3 class Exposed_Subscription {
 4 
 5     /**
 6      * Sample description for this exposed method.
 7      *
 8      * @param integer $sampleNumber some integer.
 9      * @param string $sampleString some string.
10      * @return array
11      */
12     public function testMethod($sampleNumber, $sampleString) {
13         $ret = array(
14             'someReturnedField' => ($sampleNumber + 1),
15             'anotherValue' => "your msg: " .  $sampleString
16         );
17 
18         return ($ret);
19     }
20 }
21 
22 ?>

notre index controller

Presque vide ... application/controllers/IndexController.php :

 1 <?php
 2 /**
 3  * @file application/controllers/IndexController.php
 4  */
 5 
 6 class IndexController extends Zend_Controller_Action
 7 {
 8 
 9     public function init() {
10 
11     }
12 
13     public function indexAction() {
14 
15     }
16 
17 }
18 
19 ?>

Notre controller d'erreur

Controller par defaut : application/controllers/ErrorController.php

 1 <?php
 2 /**
 3  * @file application/controllers/ErrorController.php
 4  */
 5 
 6 class ErrorController extends Zend_Controller_Action {
 7 
 8     public function errorAction()
 9     {
10         $errors = $this->_getParam('error_handler');
11 
12         switch ($errors->type) {
13             case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
14             case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
15             case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
16                 // 404 error -- controller or action not found
17                 $this->getResponse()->setHttpResponseCode(404);
18                 $this->view->message = 'Page not found';
19             break;
20             default:
21                 // application error
22                 $this->getResponse()->setHttpResponseCode(500);
23                 $this->view->message = 'Application error';
24             break;
25         }
26 
27         // conditionally display exceptions
28         if ($this->getInvokeArg('displayExceptions') == true) {
29             $this->view->exception = $errors->exception;
30         }
31 
32         $this->view->request   = $errors->request;
33     }
34 
35 ?>

Le controller de notre webservice

Ce controller “Subscription” fournira le webservice accessible sous /subscription et son wsdl sous /subscription/wsdl : application/controllers/SubscriptionController.php :

 1 <?php
 2 /**
 3  * @file application/controllers/SubscriptionController.php
 4  */
 5 
 6 class SubscriptionController extends Zend_Controller_Action {
 7     protected $_exposedClassName = "Exposed_Subscription";
 8 
 9     protected $_wsdl;
10     protected $_endpoint;
11 
12     /**
13      * sets wsdl and endpoint according to configured 'rootUrl'.
14      *
15      * @see application/configs/application.ini
16      */
17     public function init() {
18         $bootstrap = $this->getInvokeArg('bootstrap');
19         $configArray = $bootstrap->getOptions();
20         $config = new Zend_Config($configArray);
21 
22         $scheme = $this->getRequest()->getScheme();
23         $host = $this->getRequest()->getHttpHost();
24         $rootUrl = $config->rootUrl ?  $config->rootUrl : "/";
25         $controllerName = $this->getRequest()->getControllerName();
26 
27         $this->_endpoint = $scheme .  '://' .  $host .  $rootUrl .  $controllerName;
28 
29         $this->_wsdl = $this->_endpoint .  '/wsdl';
30     }
31 
32     /**
33      * soap server action.
34      */
35     public function indexAction() {
36         $options = array(
37             'soap_version'  => SOAP_1_2,
38         );
39         $server = new Zend_Soap_Server($this->_wsdl, $options);
40 
41         // exposed class, containing exposed methods:
42         $server->setClass($this->_exposedClassName);
43 
44         $server->handle();
45         exit;
46     }
47 
48     /**
49      * action that renders WSDL automatically.
50      */
51     public function wsdlAction() {
52         $wsdlGenerator = new Zend_Soap_AutoDiscover();
53         $wsdlGenerator->setClass($this->_exposedClassName);
54         $wsdlGenerator->setUri($this->_endpoint);
55         $wsdlGenerator->handle();
56         exit;
57     }
58 
59 ?>

Configuration du virtualhost apache

Rien de particulier ici : le DocumentRoot pointe sur ~/projects/webservice/public
Nous indiquons également notre éventuel environnement de dev: SetEnv APPLICATION_ENV development

Essai rapide

A titre d'essai, pointez votre navigateur web vers votre virtualHost, sur l'uri /subscription/wsdl
Vous devez apercevoir le wsdl complet, avec les paramètres d'entrée et sortie corrects pour la fonction exposée.

Client initial

La partie utile maintenant : un client de test, nous permettant de vérifier le fonctionnement de notre webservice :

 1 <?php
 2 /**
 3  * @file sampleSoapClient.php
 4  */
 5 
 6 // ensure our Zend/ directory is available for includes:
 7 $libDir = dirname(__FILE__) . '/library';
 8 set_include_path(get_include_path() . PATH_SEPARATOR . $libDir);
 9 
10 require_once('Zend/Loader/Autoloader.php');
11 $zfLoader = Zend_Loader_Autoloader::getInstance();
12 
13 // wsdl location:
14 $wsdl = 'http://localhost/subscription/wsdl';
15 
16 // soap-related options:
17 $options = array(
18     'soap_version'  => SOAP_1_2,
19     );
20 ini_set("soap.wsdl_cache_enabled", "0");
21 
22 // calling 'test()' method from 'Subscription' webservice:
23 $client = new Zend_Soap_Client($wsdl, $options);
24 $response = $client->testMethod(42, "helloWorld");
25 
26 var_dump($response);
27 
28 ?>

Posté par a.lm | Lien permanent | Classé sous: programming, php, zendframework, soap, webservice

2011-01-03 - Android et Linux - installation d'applications

Ne pouvant pas télécharger d'application directement depuis mon mobile a l'heure actuelle, je me suis penché sur la question de l'installation d'applications localement, depuis un fichier apk téléchargé précédemment.

Reconnaitre le mobile

Avant d'envisager un quelconque transfert de fichier, il faut s'assurer que le mobile est bien reconnu (nous ne parlons pas ici de l'usb storage - l'installation d'application sur le mobile depuis la SD card n'étant normalement pas possible).

La “magie” réside ici dans udev, renseigné avec le vendorID correspondant à votre mobile (0bb4 pour mon HTC desire).

Création d'une règle udev :

1 SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666"

(obtenez votre propre vendorID grace a un lsusb des usbutils.

Un redémarrage de udev plus tard, et l'adb (Android Debug Bridge, contenu dans le répertoire “platform-tools” de votre SDK android) liste votre mobile depuis un ./adb devices.

Installation d'une application

Toujours depuis le répertoire platform-tools de votre SDK android, lancez :

1 ./adb install /path/to/your/application.apk

Note : ceci ne concerne pas les applications que vous développez vous-même sous Eclipse, ce dernier effectuant la procédure lors d'une éxécution ou debug.


Posté par a.lm | Lien permanent | Classé sous: telephonie, mobile, android, linux

2011-01-03 - Portabilite du numero - J+4

Vendredi 31 Décembre 2010 ; bien que n'ayant absolument aucun avis de passage, la page de suivi Chronopost indique que mon HTC desire aurait été acheminé jusqu'à mon immeuble, et serait donc retourné au dépôt Chronopost de Maisons-Alfort.

Après plusieurs coup de fil au numéro de téléphone indiqué par chronopost sur mon répondeur, après que l'on m'ait raccroché au nez passé 10 minutes d'attente, j'ai finalement pu joindre une conseillère Chronopost.

Il s'est averé que si je voulais mon mobile avant 2011, il fallait que je rende visite à mon colis :-)
Une petite heure de transports en commun plus tard, j'ai finalement pu obtenir le tant attendu mobile :)

Le colis contient bien tous les éléments, ainsi que le contrat papier que je me suis empressé de poster.
Le numéro temporaire qui m'est assigné s'active immédiatement, et permet la réception d'appels ; je dois attendre la réception de mon contrat par orange, et la date du 7 Janvier pour profiter pleinement de ma ligne (Délai le plus court choisi lors de l'initiation du transfert de numéro).


Posté par a.lm | Lien permanent | Classé sous: telephonie, mobile

2010-12-30 - Dev Android - Etape 1 - Installation environnement

Introduction

Curieux de voir ce qu'offre réellement Android en termes de possibilités de développement, et allant recevoir très prochainement mon HTC desire (sous android), je m'initie progressivement au développement d'applications mobiles sous Android.

Cette série d'articles - que j'espère étoffer régulièrement - va présenter mon expérience personnelle dans le domaine, à commencer par les tout premiers pas : la mise en place de son environnement de développement.

Prérequis

La voie préconisée par la documentation se basant sur l'utilisation de Eclipse, une JVM récente et son JDK sont évidemment nécessaires.

Installation de Eclipse

Mes machines personelles fonctionnant toutes sous différentes distributions GNU/Linux, aucune particularité propre à une autre plateforme ne sera décrite ici.

Afin de ne pas nécessiter de privilèges particuliers, l'environnement de développement sera mis en place sous un compte utilisateur sans privilèges particuliers.

Eclipse, ainsi que le SDK android seront donc installés sous le répertoire “share” sous mon homedir:

1 mkdir -p ~/share/eclipse

Nous téléchargeons la version courante de Eclipse pour le dev java depuis la page de téléchargements de eclipse.
(Pour ma part, je télécharge “eclipse-java-helios-SR1-linux-gtk-x86_64.tar.gz” [99.2 MB] )

L'archive ainsi téléchargée contient un répertoire “eclipse”, nous pouvons donc l'extraire directement sous ~/share :

1 cd ~/share
2 tar zxvf /path/to/download/eclipse-java-helios-SR1-linux-gtk-x86_64.tar.gz

Par commodité, je créé un alias me permettant de lancer eclipse où que je sois dans l'arborescence :

1 alias eclipse='cd ~/share/eclipse && ./eclipse'

Installation du SDK android

Téléchargé depuis cette page, nous extrayons le SDK sous ~/share/

1 cd ~/share
2 tar zxvf /path/to/download/android-sdk_r08-linux_86.tgz

Ceci créé un répertoire ~/share/android-sdk-linux_86

Installation du plugin eclipse ADT

  • Sous Eclipse, depuis Help / Install new Software...
  • Cliquer sur “Add” (ajoùt d'un site de téléchargement)
  • Dans ce dialogue “Add repository”, saisir “ADT plugin” comme nom, et https://dl-ssl.google.com/android/eclipse/ comme Location.
  • Validez en cliquant sur OK ; eclipse effectue une petite mise à jour.
  • Dans la partie centrale du dialogue, cocher la case en face de “Developper Tools” pour sélectionner les différents modules.
  • Cliquer sur Next
  • Cliquer sur next, accepter la license et cliquer sur finish.
  • Redémarrer eclipse lorsque demandé

Composants du SDK android

1 cd ~/share/android-sdk-linux_86/tools
2 ./android

Choisir Available Packages dans la liste de gauche,
puis sous “Android Repository”, cocher les versions sur lesquelles vous souhaitez développer (Android 2.1 pour mon HTC desire), ainsi que les éventuels exemples, mais aussi “Android SDK Platform-tools”

Une fois les composants sélectionnés, cliquer sur Install selected, accepter toutes les licences et Install.

Configuration du plugin eclipse ADT

Le SDK Android étant maintenant installé, nous pouvons configurer Eclipse pour l'utiliser :

  • sous Eclipse: Window / Preferences...
  • sélectionner Android dans la liste de gauche
  • sur la ligne “SDK location” cliquer sur “Browse”
  • choisir ~/share/android-sdk-linux_86
  • Cliquer sur apply : une target apparait, avec la plateforme choisie plus haut.

Création d'un device android

La dernière étape consiste en la création d'un ou plusieurs devices (par exemple l'emulateur).
Sous eclipse, choisir Window / Android SDK and AVD manager
Cliquer sur New, saisir un nom, indiquer une taille de carte SD a emuler, choisir la plateforme cible ("Target") et cliquer sur create AVD. Voila ... l'environnement de développement est maintenant prêt.


Posté par a.lm | Lien permanent | Classé sous: java, programming, telephonie, mobile, android

2010-12-29 - Portabilite du numero - J+2

Nous voilà Mercredi, 2 jours après avoir lancé le changement d'opérateur.

La page de suivi de commande a évolué aujourd'hui ; ma commande est en cours d'expédition, actuellement au hub chronopost de Chilly, il est fort probable que je reçoive mon HTC desire demain matin :)


Posté par a.lm | Lien permanent | Classé sous: telephonie, mobile

2010-12-28 - Portabilite du numero - jour J+1

voulant changer de mobile pour passer de mon vieux Nokia E61 aià un HTC desire, j'ai finalement opté pour un changement d'opérateur mobile, afin de bénéficier d'une "offre promotionnelle" proposant ce téléphone.

Ce lundi 27 décembre, peu avant 20 heures, je me suis donc lancé dans la procédure de changement d'opérateur, avec portabilité du numéro.

Cette phase initiale consiste en deux courtes étapes :

  • Obtention du RIO (relevé d'identité opérateur) auprès de l'ancien opérateur.
  • Souscription à l'offre du nouvel opérateur

Obtention du RIO

Ce numéro à 12 caractères s'obtient via un serveur vocal, sur simple appel depuis la ligne a migrer (appel au 933 depuis une ligne SFR).

Inscription chez le nouvel opérateur

Procédure très classique, hormis le fait que l'on souhaite conserver son ancien numéro (et donc saisir notre RIO).
Passé quelques minutes, après saisie de ses informations personnelles / facturation, la procédure est presque terminée ; il faudra seulement retourner le contrat au nouvel opérateur, lorsque ce dernier sera acheminé par voie postale.

Edit: ce Mardi 28 Décembre, en fin de soirée, ma commande vient de passer en statut "Validée" sur la page de suivi de mon nouvel opérateur Orange.


Posté par a.lm | Lien permanent | Classé sous: telephonie, mobile

2010-10-05 - gitolite - repositories git et ACLs

gitolite se présente comme le successeur de gitosis, il permet d'assigner simplement des ACL à vos différents repositories git.

Utilisant un compte unique sur le serveur centralisant les repositories git à administrer, gitolite utilise les clefs publiques ssh des développeurs pour autoriser ou non l'accès en lecture et/ou écriture à un ou plusieurs repositories.

La configuration des ACL, ainsi que l'ajoùt de nouvelles clefs publiques se fait intégralement via git.

Exemple d'installation sur une machine debian GNU/Linux :

Installation de gitolite

Un simple apt-get install :

1 root@server# apt-get install gitolite

Compte utilisateur dédié

Bien que debian créé un compte 'gitolite' je créé un compte supplémentaire "git" pour plus de commodités durant les accès distants aux repositories:

1 root@server# adduser git

Clé publique de l'administrateur

exporter la clef publique ssh de l'administrateur gitolite et la nommer "sitaram.pub"

1 gitadmin@station$ scp ~/.ssh/id_rsa.pub root@server:/tmp/sitaram.pub

Crétion de l'environnement gitolite

lancer gl-setup sur le serveur :

1 root@server# su - git
2 git@server# gl-setup /tmp/sitaram.pub

configuration distante

La configuration se fait uniquement via le repo gitolite-admin :

1 dev@station$ cd ; git clone git@server:gitolite-admin

placer les clefs publiques ssh des développeurs autorisés à accéder aux repositories dans keydir/

La configuration des groupes et les repositories auxquels ils ont accès en lecture/écriture se fait via l'edition de conf/gitolite.conf dans ce repository cloné.
Au moment du push sur le serveur, les nouveaux repositories sont créés, les nouvelles clefs ssh autorisées...

activation de gitweb par repository

L'activation se fait automatiquement pour chaque repository disposant d'une description :

 1  # locally cloned gitolite-admin repo:
 2  # gitolite-admin/conf/gitolite.conf
 3  #
 4 
 5  @agroup = auserinsomegroup
 6  @somegroupname = auser anotheruser @agroup
 7  @rogroup = athirduser
 8 
 9  repo    somereponame
10          RW+  =  @somegroupname
11          R    =  @anotherrogroup
12          somereponame "owner full name" = "project description"

Accès distant aux repositories

Les URLs d'accès aux repositories sont de la forme "git@server:reponame"

1 user@station$ git clone git@server:somerepo

push d'un repository existant:

1 user@station$ cd existingrepo
2 user@station$ git push --all git@server:reponame
3 user@station$ git push --tags git@server:reponame

Posté par a.lm | Lien permanent | Classé sous: acl, debian, git

2010-10-03 - Installation de nginx et php fastcgi

Venant de réinstaller une distribution linux avec gestion de paquets binaires sur mon petit laptop (Athlon 1400+), j'ai finalement décidé que apache n'y aura pas son emprise cette fois ci :)

Passé la phase d'installation, je dois avouer que je suis pour l'instant plutôt satisfait de la chose ... Plus besoin de "tricher" ou effectuer plusieurs tentatives pour avoir un véritable virtual host "fallback" (entête Host correspondant à une adresse IP, ou non spécifié), des directives simples exploitant la puissance des expressions régulières, bref ... ça fonctionne vite et bien :)

Voici donc la procédure suivie, pour installer nginx avec php5 en fastcgi, sur une debian fraîchement installée, passée en testing (notamment pour me contenter d'un apt-get install tint2, mais plus globalement pour l'éternel "problême" des versions des paquets debian).

Installation de nginx et php

Je me contente pour l'instant de quelques extensions php, j'ajouterais celles dont j'aurais besoin progressivement.

1 apt-get install nginx php5-cgi php5-mysql php5-sqlite psmisc

Configuration initiale de php5 en vue du passage en fastcgi

Dès l'installation terminée, on active cette option dans /etc/php5/cgi/php.ini :

1 # /etc/php5/cgi/php.ini
2 cgi.fix_pathinfo = 1

Script d'init php5 en fastcgi

Créez /etc/init.d/php-fastcgi :

 1 #!/bin/bash
 2 # /etc/init.d/php-fastcgi
 3 #
 4 BIND=127.0.0.1:9000
 5 USER=www-data
 6 PHP_FCGI_CHILDREN=5
 7 PHP_FCGI_MAX_REQUESTS=1000
 8 
 9 PHP_CGI=/usr/bin/php-cgi
10 PHP_CGI_NAME=`basename $PHP_CGI`
11 PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin
12 PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN
13 PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND"
14 RETVAL=0
15 
16 start() {
17     echo -n "Starting PHP FastCGI: "
18     start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
19     RETVAL=$?
20     echo "$PHP_CGI_NAME."
21 }
22 
23 stop() {
24     echo -n "Stopping PHP FastCGI: "
25     killall -q -w -u $USER $PHP_CGI
26     RETVAL=$?
27     echo "$PHP_CGI_NAME."
28 }
29 
30 case "$1" in
31     start)
32         start
33     ;;
34     stop)
35         stop
36     ;;
37     restart)
38         stop
39         start
40     ;;
41     *)
42         echo "Usage: php-fastcgi {start|stop|restart}"
43         exit 1
44     ;;
45 esac
46 exit $RETVAL

On lance php en fastcgi au démarrage :

1 update-rc.d php-fastcgi defaults

Support php dans un vhost

Dans un virtualhost nginx :

 1 # /etc/nginx/sites-available/localhost
 2 #
 3 
 4 # ...
 5 location ~ \.php$ {
 6     root           /var/www/localhost;
 7     fastcgi_pass   127.0.0.1:9000;
 8     fastcgi_index  index.php;
 9     fastcgi_param SCRIPT_FILENAME /var/www/localhost$fastcgi_script_name;
10     include fastcgi_params;
11 }
12 # ...

Test de la config

1 echo "<?php phpinfo(); ?>" > /var/www/localhost/info.php
2 /etc/init.d/php-fastcgi start
3 /etc/init.d/nginx start

un accès à http://localhost/info.php affiche bien les infos php, avec ServerAPI=CGI/FastCGI, et www-data en user.


Posté par a.lm | Lien permanent | Classé sous: nginx, php, linux