Archives pour la catégorie ‘Java’

Maven : vérifier les mises à jour disponibles

Vérifier les mises à jour des plugins Maven :

boris@debian:~$ mvn versions:display-plugin-updates

Vérifier les mises à jour des dépendances du projet :

boris@debian:~$ mvn versions:display-dependency-updates

Maven : construire une image Docker et y intégrer le JAR du projet

Le but est de construire l’image Docker d’un projet Java par Maven. L’image est générée par le plugin Maven docker-maven-plugin mais afin de ne pas casser le versioning, le nom du JAR original n’est pas modifié; une copie est réalisée avant intégration (un nom de fichier fixe est obligatoire).

Au niveau du projet Maven, un répertoire dédié est créé pour le Dockerfile et l’ensemble des fichiers de génération de l’image :

bhuisgen@local:~/Projects/java/demo$ find src/main/docker/
src/main/docker/
src/main/docker/Dockerfile
src/main/docker/root
src/main/docker/root/etc
src/main/docker/root/etc/services.d
src/main/docker/root/etc/services.d/app
src/main/docker/root/etc/services.d/app/finish
src/main/docker/root/etc/services.d/app/run

L’image repose sur une base Alpine Linux avec gestion des services par s6-overlay auquel est ajouté le strict nécessaire :

bhuisgen@local:~/Projects/java/demo$ cat src/main/docker/Dockerfile
FROM bhuisgen/alpine-base:latest
MAINTAINER Boris HUISGEN <bhuisgen@hbis.fr>

RUN apk add --update openjdk8-jre && \
    rm -rf /var/cache/apk/*

COPY root /

ENTRYPOINT ["/init"]
CMD []

A noter que la commande de copie du JAR n’est pas présente; le plugin l’ajoutera de lui-même. Le reste est donc à ajouter au fichier POM :

bhuisgen@local:~/Projects/java/demo$ vim pom.xml

[...]

    <build>
        <plugins>

[...]

            <!-- copy and rename the JAR to a fixed filename -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <copy
                                    file="${project.build.directory}/${project.artifactId}-${project.version}.jar"
                                    tofile="${project.build.directory}/app.jar" />
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- build the Docker image -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.4.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <imageTag>${project.version}</imageTag>
                    <imageTag>latest</imageTag>
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <directory>${project.build.directory}</directory>
                            <include>app.jar</include>
                            <targetPath>/</targetPath>
                        </resource>
                    </resources>
                </configuration>
            </plugin>

L’image sera générée lors de la phase package et un tag y sera appliqué pour conserver le numéro de version de l’application.

Java : log syslog avec log4j

package syslog;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.net.SyslogAppender;

public class test {
	private static final Logger log = Logger.getLogger(test.class);

	public static void main(String[] args) {
		Logger rootLogger = Logger.getRootLogger();
		
		rootLogger.setLevel(Level.DEBUG);

		PatternLayout layout = new PatternLayout("%t: %p: %m%n");
		SyslogAppender syslogAppender = new SyslogAppender(layout, "localhost",
				SyslogAppender.LOG_USER);
		
		Logger.getRootLogger().addAppender(syslogAppender);

		log.info("log message");
	}
}

Ne pas oublier d’activer l’écoute réseau du serveur syslog local :

# vim /etc/rsyslog.conf
# provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

Ant : génération d’un bundle OSGI avec bnd

Bnd : https://bndtools.ci.cloudbees.com/job/bnd.master/ws/biz.aQute.bnd/generated/

bhuisgen@muse:~/Projects/java/libirc$ cat build.xml
<target name="dist" depends="doc" description="create package">
   <!-- JAR package -->
   <mkdir dir="${dist.home}/bin/${ant.project.name}" />
   <copy todir="${dist.home}/bin/${ant.project.name}">
      <fileset dir="${build.home}" />
   </copy>
   <jar destfile="${dist.home}/${ant.project.name}-${build.version}-bin-${DSTAMP}.jar" basedir="${dist.home}/bin/" />

   <!-- OSGI bundle -->
   <replaceregexp file="myfile.bnd" match="Bundle-Version: (.*)" replace="Bundle-Version: ${build.version}" byline="true" />
   <taskdef resource="aQute/bnd/ant/taskdef.properties" classpath="${lib.home}/bnd-2.0.0.jar"/>
   <bnd classpath="${build.home}" files="myfile.bnd" output="${dist.home}/${ant.project.name}-${build.version}-bundle-${DSTAMP}.jar" />
</target>
bhuisgen@muse:~/Projects/java/libirc$ cat libirc.bnd
Bundle-Name: IRC Client Framework Bundle
Bundle-SymbolicName: fr.hbis.lib.irc
Bundle-Version: 0.2.0

Private-Package: fr.hbis.lib.irc.*

SWT : gérer le menu application sous MacOS X

SWT ne gère pas directement le menu application sous Mac OS X. Par défaut, toute application a donc un menu ressemblant à ceci :

Il est donc nécessaire de coder la modification du menu pour y refléter le nom réel de l’application et également mapper les actions des éléments A propos, Préférences et Quitter.

Auparavant, l’emploi de CocoaUIEnhancer était obligatoire car aucune API SWT n’existait pour accéder à ce menu. Depuis la version 3.7, les choses ont changé et une API interne est disponible. Voici un exemple d’utilisation de celle-ci :

Menu systemMenu = shell.getDisplay().getSystemMenu();
if (systemMenu == null)
	return; // not MacOS X

for (MenuItem menuItem : systemMenu.getItems())
{
	switch (menuItem.getID())
	{
		case SWT.ID_ABOUT:
		{
			menuItem.setText("About " + Constants.APPLICATION_NAME); // application name
			menuItem.addListener(SWT.Selection, new Listener()
			{
				@Override
				public void handleEvent(Event event)
				{
					helpAbout();
				}
			});
			break;
		}

		case SWT.ID_PREFERENCES:
		{
			menuItem.addListener(SWT.Selection, new Listener()
			{
				@Override
				public void handleEvent(Event event)
				{
					filePreferences();
				}
			});

			break;
		}

		case SWT.ID_QUIT:
		{
			menuItem.addListener(SWT.Selection, new Listener()
			{
				@Override
				public void handleEvent(Event event)
				{
					if (!fileExit())
						event.doit = false; // ignore exit if false
				}
			});

			break;
		}

		default:
		{
			break;
		}
	}
}

SWT : générer le JAR de la javadoc

La documentation de la librairie SWT n’est pas disponible directement sous la forme d’un package. Il faut donc la générer depuis les sources.

Une fois le JAR des sources récupéré sur cette page, la génération s’effectue de cette façon :

# cd swt-4.2-cocoa-macosx-x86_64
# unzip src.zip -d src
# javadoc -source 1.4 -d docs -sourcepath src -link http://java.sun.com/javase/6/docs/api/ -link . -subpackages org.eclipse.swt
# cd docs
# jar cf swt-4.2-doc.jar *

Reste ensuite à copier et ajouter le JAR à votre projet.

Par exemple sous Eclipse, il faut éditer les propriétés du projet, rubrique Java Build Path / Libraries et paramétrer l’élément Javadoc Location du JAR source :

Une fois tout ceci en place, la complétion de code doit être opérationnelle.

SWT : scrolling automatique avec un composant StyledText

L’astuce consiste à effectuer une sélection vide (invisible) du dernier caractère en appelant la méthode setSelection :

StyledText styledOutput;

// ...

styledOutput.append("texte à ajouter");

styledOutput.setSelection(styledOutput.getCharCount());

A noter qu’avec setSelectionRange, seul le positionnement du curseur est effectué pas le scolling.

Java : désactiver la validation d’un certificat SSL

Un moyen rapide et pas propre pour désactiver la validation d’un certificat SSL côté client :

SocketFactory socketFactory;
Socket socket;

TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
	public java.security.cert.X509Certificate[] getAcceptedIssuers()
	{
		return null;
	}

	public void checkClientTrusted(
			java.security.cert.X509Certificate[] certs,
			String authType)
	{
	}

	public void checkServerTrusted(
			java.security.cert.X509Certificate[] certs,
			String authType)
	{
	}
} };

try
{
	SSLContext sc = SSLContext.getInstance("TLS");
	sc.init(null, trustAllCerts, new java.security.SecureRandom());

	socketFactory = sc.getSocketFactory();
}
catch (GeneralSecurityException e)
{
	e.printStackTrace();
}

socket = socketFactory.createSocket(host, port);

Java EE : charger un fichier de propriétés depuis un WAR

	Properties properties = new Properties();

	try {
		properties.load(this.getClass().getClassLoader().
			getResourceAsStream("/config.properties));
	} catch (IOException e) {
		throw new RuntimeException(e.getMessage(), e);
	}

Le fichier de propriétés doit être stocké dans le CLASSPATH de l’application web. Dans le cas d’un WAR, il s’agit de WEB-INF/classes.

Java : caster un Object en Map

Alors le casse-tête du jour : comment convertir un Object en une Map ?

Solution avec dans mon cas une Map<Object,Object> – ce qui constitue toute la difficulté – :

Object ret;
Map<Object, Object> map;

ret = getData();
map = safeCastMap(ret, Object.class, Object.class);

Voici les fonctions de vérifications nécessaires  :

	@SuppressWarnings({ "unchecked" })
	public static <K, V> Map<K, V> safeCastMap(Object map, Class<K> keyType,
			Class<V> valueType) {
		checkMap(map);
		checkMapContents(keyType, valueType, (Map<?, ?>) map);
		return (Map<K, V>) map;
	}

	private static void checkMap(Object map) {
		checkType(Map.class, map);
	}

	private static <K, V> void checkMapContents(Class<K> keyType,
			Class<V> valueType, Map<?, ?> map) {
		for (Map.Entry<?, ?> entry : map.entrySet()) {
			checkType(keyType, entry.getKey());
			checkType(valueType, entry.getValue());
		}
	}

	private static <K> void checkType(Class<K> expectedType, Object obj) {
		if (!expectedType.isInstance(obj)) {
			throw new IllegalArgumentException("Expected " + expectedType
					+ " but was " + obj.getClass() + ": " + obj);
		}
	}
Haut de page