D’un programme Java à une application personnelle

Récemment, j’ai écrit plusieurs billets liés à un projet personnel, que je développe sur mon temps libre.

Une partie de ce projet consistait à développer une application. J’ai choisi Java pour l’implémenter, en sachant que ça devait tourner sous Windows 7 et que je serais probablement le seul utilisateur (généralement exigeant) de cette application. C’est une application graphique. Au début, j’avais attaqué en SWING. Puis finalement, je suis repassé sur du SWT / JFace (SWING était une contrainte technique liée à un besoin précis – ce besoin a par la suite disparu).

Est bien sûr arrivé le moment de passer du développement à la pré-production (tests en conditions réelles).
Dans un premier temps, je ne me suis pas pris la tête. J’ai écrit un script BAT qui lance le JAR de mon application. Si tout s’est bien passé, j’avais cependant deux retours négatifs avec ces tests.

  1. Mon application n’apparaissait pas dans la barre des tâches de Windows. Mon BAT (enfin, la ligne de commande), oui. Mais pas mon shell.
  2. Lancer une ligne de commande, c’est bien pour les trucs sans IHM, mais c’est un peu naze pour une application personnelle.

Le premier problème était graphique.
J’ouvrais simplement un TitleAreaDialog (une sous-classe en fait) à partir d’un nouveau shell. Quel que soit le style du shell ou le parent que je lui mettais, il n’y avait pas moyen que mon programme apparaisse dans la barre des tâches. J’ai finalement réglé le problème en étendant ApplicationWindow et en lui mettant un parent null.

public class PostHelperApplication extends ApplicationWindow {

	public PostHelperApplication( SortedSet<VideoFile> videoFiles ) {
		super( null );
		...
	}

	...
}

Premier problème réglé.

Le deuxième problème consistait quant à lui à embarquer mes JAR dans un .exe.
J’ai utilisé pour ça Launch4j, qui est très facile à utiliser. J’ai donc un dossier avec un .exe à la racine, et un sous-dossier lib qui contient mes JAR (exportés avec Eclipse – runnable jar). J’ai gardé les choses simples. Pas de Maven. J’ai simplement fourni un fichier .ico pour que mon application ait une jolie icône quand je parcours son dossier.

Là est apparu un nouveau problème.
L’icône proposée dans la barre des tâches Windows était plutôt insipide. J’ai donc dégoté un jeu d’icônes (gratuites) et je les ai associés à mon shell SWT. Ces images sont ensuite reprises par Windows pour être affichées dans la barre des tâches.

public class PostHelperApplication extends ApplicationWindow {

	private Image appli16, appli32, appli48;

	public PostHelperApplication( SortedSet<VideoFile> videoFiles ) {
		super( null );

		// ...

		// Application icons (for Windows bar)
		try {
			ImageData imgData = new ImageData( "./icons/appli_16x16.png" );
			this.appli16 = new Image( Display.getDefault(), imgData );

			imgData = new ImageData( "./icons/appli_32x32.png" );
			this.appli32 = new Image( Display.getDefault(), imgData );

			imgData = new ImageData( "./icons/appli_48x48.png" );
			this.appli48 = new Image( Display.getDefault(), imgData );

		} catch( Exception e ) {
			logger.fine( e.getMessage());
			if( logger.isLoggable( Level.FINEST ))
				logger.finest( BrowsingUtils.getFormattedStackTrace( e ));
		}
	}

	@Override
	public boolean close() {

		boolean result = super.close();

		if( this.appli16 != null && ! this.appli16.isDisposed())
			this.appli16.dispose();

		if( this.appli32 != null && ! this.appli32.isDisposed())
			this.appli32.dispose();

		if( this.appli48 != null && ! this.appli48.isDisposed())
			this.appli48.dispose();

		return result;
	}

	@Override
	protected Control createContents( Composite parent ) {

		getShell().setImages( new Image[] { this.appli16, this.appli32, this.appli48 });

		// ...
	}
}

Et voilà le résultat.
Quand mon application apparaît dans la barre des tâches, elle a une jolie icône, choisie par mes soins.


Voilà qui commence à avoir de l’allure.

FileNotFoundException avec une URL valide

Décidément, j’ai plein de choses à dire en ce moment.
D’ailleurs, j’ai encore 2-3 entrées sous le coude, que je vais me garder pour la semaine prochaine…

Voilà donc le scénario :

  • Vous essayez de récupérer le contenu d’une page Web dans une application Java.
  • L’URL que vous voulez appeler est valide, elle fonctionne dans votre navigateur Web.
  • Malheureusement, votre code lance une exception FileNotFoundException.
  • Vous avez aussi tenté d’utiliser URLEncoder, sans succès.

En fait, votre code doit à peu près ressembler à ça :

public static void main( String[] args ) {

	try {
		String base = "http://mon/url";

		InputStream in = new URL( base ).openConnection().getInputStream();
		BufferedReader rd = new BufferedReader( new InputStreamReader( in ));
		StringBuffer sb = new StringBuffer();
		String line;
		while(( line = rd.readLine()) != null )
			sb.append( line );

		rd.close();
		in.close();
		System.out.println( sb.toString());

	} catch( MalformedURLException e ) {
		e.printStackTrace();

	} catch( IOException e ) {
		e.printStackTrace();
	}
}

J’ai eu le problème, devinez quoi, en essayant de récupérer une page d’un blog WordPress.
Sur l’index, ça marche très bien. Et sur d’autres pages, pas du tout. Je précise que j’ai activé la réécriture d’URL sur mon serveur, et les permaliens sur le blog.

Bref…
Une des explications possibles que j’ai trouvées sur le net pourrait être un problème de User Agent.
Pourquoi pas…

Toujours est-il que voilà une solution.
Elle consiste à utiliser la librairie HTTP Client d’Apache.
Avec le code suivant, les URL qui vous plantaient avec le code plus haut, passent maintenant très bien.

public static void main( String[] args ) {

	try {
		String base = "http://mon/url";

		HttpClient httpClient = new DefaultHttpClient();
		HttpGet pageGet = new HttpGet( new URI( base ));
		HttpResponse response = httpClient.execute( pageGet );
		InputStream in = response.getEntity().getContent();

		BufferedReader rd = new BufferedReader( new InputStreamReader( in ));
		StringBuffer sb = new StringBuffer();
		String line;
		while(( line = rd.readLine()) != null )
			sb.append( line );

		rd.close();
		in.close();
		System.out.println( sb.toString());

	} catch( MalformedURLException e ) {
		e.printStackTrace();

	} catch( IOException e ) {
		e.printStackTrace();

	} catch( URISyntaxException e ) {
		e.printStackTrace();
	}
}