Skip to main content

Annotation et Pattern

Pattern d'injection

Nous allons regarder le pattern d'injection.

Soit une interface Store permettant de sauvegarder des données dans un fichier

public interface Store {

	public void initStore(String str);
	public void storeData(String filename, byte [] data);
	
}

 

Premiere implémentation.

La première implémentation utilise la librairie Apache common pour sauvegarder des données dans un fichier

import org.apache.commons.io.IOUtils;

public class PlainStore implements Store {

	public void initStore(String str) {
		// TODO Auto-generated method stub
		
	}

	public void storeData(String filename, byte[] data) {
		try{
			FileOutputStream stream=new FileOutputStream(filename);
		
		IOUtils.write(data, stream);
		stream.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

}

Deuxième Implementation

La deuxième implémentation utilise de la cryptographie pour enregistrer les données

package be.etnic.guice;

import java.io.FileOutputStream;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.io.IOUtils;

public class AESStoreProcessor implements Store{

	private SecretKey key;

	public void initStore(String str) {
		 try{
					SecureRandom sr = SecureRandom.getInstanceStrong();
	    byte[] salt = new byte[16];
	    sr.nextBytes(salt);

	    PBEKeySpec spec = new PBEKeySpec(str.toCharArray(), salt, 65536, 128);
	    SecretKey tmp = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
	    		.generateSecret(spec);
	    this.key = new SecretKeySpec(tmp.getEncoded(), "AES");

		 }
			catch (Exception e)
			{
				throw new RuntimeException(e);
			}
	}

	public void storeData(String filename, byte[] data) {
		  try{
				Cipher aes = Cipher.getInstance("AES");
	    aes.init(Cipher.ENCRYPT_MODE, key);
	  	FileOutputStream stream=new FileOutputStream(filename);
		
		IOUtils.write(aes.doFinal(data)
	    , stream);
		stream.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

}

 

Module de haut niveau.

Nous mettons a disposition une classe permettant d'avoir des store

public class StoreProcessor {

	Store store;
	
	public StoreProcessor(Store store)
	{
		this.store=store;
	}
	public void storeData(String filename,String initParameter,byte [] data)
	{
		store.initStore(initParameter);
		store.storeData(filename, data);
	}
}

Le hic est qu'il faut passer un store en parametre du store processor.

On peut utiliser ici un pattern d'injection


public class StoreModule extends AbstractModule {
	  @Override 
	  protected void configure() {

	     /*
	      * This tells Guice that whenever it sees a dependency on a TransactionLog,
	      * it should satisfy the dependency using a DatabaseTransactionLog.
	      */
	    bind(Store.class).to(PlainStore.class);
	  }

}

Et placer l'injection sur le constructeur de StoreProcessor

public class StoreProcessor {
	Store store;
	
	@Inject
	public StoreProcessor(Store store)
	{
		this.store=store;
	}
	public void storeData(String filename,String initParameter,byte [] data)
	{
		store.initStore(initParameter);
		store.storeData(filename, data);
	}
}

Dans la fonction main est ainsi faites

public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        StoreProcessor storeProcessor=new StoreProcessor(new AESStoreProcessor());
        storeProcessor.storeData("test.txt", "pilou", "hello world".getBytes());
        Injector injector = Guice.createInjector(new StoreModule());
        GuiceStoreProcessor storeProcessor2=injector.getInstance(GuiceStoreProcessor.class);
        storeProcessor2.storeData("test2.txt", "pilou", "hello world".getBytes());

    }
}