ShrinkWrap è il modo più semplice per creare archivi in Java, e offre maggior potenza al meccanismo di deploy di Arquillian. Questa guida permetterà di creare gli oggetti utilizzati nel deployment. Copriremo:
- Architettura e benefici di ShrinkWrap contro i tradizionali archivi basati su file
- Creazione passo passo di un nuovo archivio
- Differenti meccanismi per l’aggiunta dei contenuti
- Importazione di archivi da strutture di file già esistenti
Motivazioni architetturali
Fin dall’inizio, ShrinkWrap è nato dalla necessità di eseguire il deploy dei test su piattaforme enterprise in modo semplice. Tradizionalmente definiti come archivi flat e aderenti allo standard ZIP, hanno bisogno di una fase di creazione del pacchetto e di aggiunta delle risorse. E questa fase consuma tempo prezioso:
$ mvn clean install
... traccia di output terrificante ...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:13.492s
[INFO] ------------------------------------------------------------------------
Ma da sviluppatori quali siamo, passiamo al nostro ambiente di sviluppo.
Quindi ci chiediamo: “Possiamo dichiarare in Java un oggetto che rappresenti quest’archivio?”
Il risutato è una API Java analoga al tool “jar”, un file system virtuale con una sintassi intuitiva.
JavaArchive archive = ShrinkWrap.create(JavaArchive.class,"myarchive.jar")
.addClasses(MyClass.class, MyOtherClass.class)
.addResource("mystuff.properties");
Con quest’API lavoriamo internamente al nostro codice risparmiandoci il lavoro manuale di creazione del pacchetto di deploy.
Come altro risultato abbiamo un modo completamente integrato per eseguire i test sui nostri pacchetti Java.
Questo è ShrinkWrap.
Iniziamo
Il primo passo è prelevare i binari di ShrinkWrap. Il Core è composto di tre parti:
Name | Coordinate Maven |
---|---|
API | org.jboss.shrinkwrap:shrinkwrap-api |
SPI | org.jboss.shrinkwrap:shrinkwrap-spi |
Implementazione | org.jboss.shrinkwrap:shrinkwrap-impl-base |
Soltanto l’API deve essere disponibile al ClassPath di compilazione, mentre i moduli SPI e l’Implementazione sono entrambi richiesti a runtime. E’ sempre una buona regola separare le classi utilizzabili direttamente e quelle interne al progetto.
Con Maven, possiamo prendere le librerie in modo semplice, richiamando il Dependency Chain POM di SchrinkWrap, disponibile nel repository centrale:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- snip -->
<dependency> <groupId>org.jboss.shrinkwrap</groupId> <artifactId>shrinkwrap-depchain</artifactId> <version>${version.shrinkwrap}</version> <type>pom</type> </dependency>
<!-- snip --> </project>
Per i progetti che non usano Maven, ShrinkWrap offre comunque tutti i moduli disponibili per il download, in modo che chiunque si possa installare manualmente le dipendenze.
Prerequisiti
- JRE5+ Runtime
- Nessun’altra dipendenza aggiuntiva
ShrinkWrap può girare su una Java5 runtime o superiore, ma richiede almeno la JDK6 per la compilazione.
Documentazione delle API
I JavaDoc per tutte le versioni si trovano qui .
Codice Open Source
Potete fare un fork e aiutarci nello sviluppo collegandovi su Sviluppo .
Creazione dell’Archivio
Il punto di partenza per usare ShrinkWrap è la classe org.jboss.shrinkwrap.api.ShrinkWrap
. Da qui si può chiamare il metodo create
per creare un nuovo Archive
, il quale è una vista generica del file system virtuale che permette l’aggiunta di contenuti chiamati Asset
in uno spazio ArchivePath
. La seguente tabella mostra in modo semplice la nomenclatura dei vari termini di ShrinkWrap:
Termine Comune | Classe ShrinkWrap | Descrizione |
---|---|---|
Archivio | org.jboss.shrinkwrap.api.Archive |
Un insieme di risorse, essenzialmente chiamato filesystem virtuale |
File | org.jboss.shrinkwrap.api.Node |
Una entry dell’@Archive@; può rappresentare un contenuto o una directory |
Path | org.jboss.shrinkwrap.api.ArchivePath |
Spazio dell’ Archive sotto cui si trova il Node |
Asset | org.jboss.shrinkwrap.api.Asset |
Contenuto di tipo byte dentro il Node |
Inoltre, L’ Archive
ha diverse viste, e di solito non si richiama direttamente la classe Archive
. Infatti, ShrinkWrap supporta diverse estensioni di Archive
che offrono un maggior aiuto nella manipolazione del pacchetto.
Tipo di Archivio | Descrizione |
---|---|
org.jboss.shrinkwrap.api.GenericArchive |
Il tipo più semplice di una vista utente di un Archive ; supporta operazioni generiche |
org.jboss.shrinkwrap.api.spec.JavaArchive |
Formato JAR; permette l’aggiunta del Class es, Package , e le operazioni sul Manifest |
org.jboss.shrinkwrap.api.spec.EnterpriseArchive |
Formato Java EE EAR; supporta il Manifest e le relative operazioni previste dalle specifiche |
org.jboss.shrinkwrap.api.spec.WebArchive |
Formato Java EE WAR; supporta le operazioni comuni allo sviluppo delle applicazioni web |
org.jboss.shrinkwrap.api.spec.ResourceAdaptorArchive |
Formato Java EE RAR; supporta le operazioni comuni allo sviluppo dei resource adaptor |
Per creare un Archive
, semplicemente scegliete l’archivio desiderato e opzionalmente assegnate un nome al metodo statico ShrinkWrap:create
:
GenericArchive myArchive = ShrinkWrap.create(GenericArchive.class,"myArchive.jar");
Questo è tutto! Avete creato il tuo primo archivio ShrinkWrap!
Aggiungere i Contenuti
Naturalmente, un oggetto che rappresenta un archivio vuoto è assolutamente inutile. Proviamo ad aggiungere dei contenuti. Come notato prima, il contenuto è modellato dalla classe Asset
, quindi diamo subito uno sguardo alle implementazioni dell’ Asset
fornite da ShrinkWrap:
Asset | Rappresenta |
---|---|
org.jboss.shrinkwrap.api.asset.ArchiveAsset |
Archive annidato |
org.jboss.shrinkwrap.api.asset.ByteArrayAsset |
byte[] o un contenuto di tipo InputStream |
org.jboss.shrinkwrap.api.asset.ClassAsset |
Class Java |
org.jboss.shrinkwrap.api.asset.ClassLoaderAsset |
Una qualunque risorsa che può essere caricata da un ClassLoader |
org.jboss.shrinkwrap.api.asset.FileAsset |
Contenuto di tipo File |
org.jboss.shrinkwrap.api.asset.StringAsset |
Contenuto di tipo String |
org.jboss.shrinkwrap.api.asset.UrlAsset |
Contenuto raggiungibile da un dato URL |
org.jboss.shrinkwrap.api.asset.EmptyAsset |
Contenuto vuoto (0-byte) |
Inoltre, dato che l’@Asset@ è un’interfaccia, potete fornire la vostra propria implementazione per supportare un contenuto di tipo byte sotto forma di InputStream
. Come esempio, il codice in basso mostra come ottenere un DataSource
per l’Activation Framework sotto forma di Asset
:
final DataSource dataSource = null; // Presupponendo di averlo già
Asset asset = new Asset() {
@Override
public InputStream openStream() {
try {
return dataSource.getInputStream();
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
};
Il metodo Archive:add
permette di aggiungere l’ Asset
all’ ArchivePath
.
myArchive.add(myAsset,"path/to/content");
System.out.println(myArchive.toString(true));
Il valore true
passato al metodo toString
dell’ Archive
attiva la verbosità creando in output un "ls -l"
ricorsivo:
myArchive.jar:
/path/
/path/to/
/path/to/content
Anche le viste Archive
mostrate prima sono molto di aiuto, a seconda del tipo di contenuto che si utilizza. Per esempio, uno standard file JAR tipicamente contiene file .class
e altre risorse, cosicchè avete modo di aggiungerle tramite il JavaArchive
.
ShrinkWrap supporta un semplice meccanismo per cambiare a runtime il tipo di archivio, fornendo il metodo as
dell’interfaccia org.jboss.shrinkwrap.api.Assignable
; tutte le viste estendono l’interfaccia Assignable
. Così se vogliamo passare da un archivio esistente ad un @JavaArchive per inserire in modo più semplice le classi, possiamo semplicemente scrivere:
myArchive.as(JavaArchive.class).addClasses(String.class, Integer.class);
System.out.println(myArchive.toString(true));
archive.jar:
/java/
/java/lang/
/java/lang/String.class
/java/lang/Integer.class
Questo meccanismo è importante per mantenere l’uso di ShrinkWrap chiaro e intuitivo, offrendo una versatilità che è tipica dei linguaggi con la vera ereditarietà multipla.
Lavorare con i File
Poichè ShrinkWrap ha le sue radici nella Java EE ed è legato alla piattaforma di test di Arquillian, non è certamente l’unico uso che se ne può fare. Infatti, ShrinkWrap può lavorare anche con comuni file.
Ripartendo dall’esempio visto sopra, proviamo a usare ShrinkWrap per aggiungere i file .class
nel pacchetto corrente sotto forma di JAR in fomrato ZIP. Il codice per fare ciò è piuttosto semplice:
JavaArchive archive = ShrinkWrap.create(JavaArchive.class,
"myPackage.jar").addPackage(this.getClass().getPackage());
System.out.println(archive.toString(true));
archive.as(ZipExporter.class).exportTo(
new File("/home/alr/Desktop/myPackage.jar"), true);
javalang.jar:
/org/
/org/alr/
/org/alr/test/
/org/alr/test/TestClass.class
Vediamo cosa sta accadendo. Per prima cosa abbiamo creato un JavaArchive
e aggiunto tutti i contenuti nel Package
della Classe
. Poi abbiamo stampato l’output sulla console, giusto per vedere cosa c’è nel pacchetto. Infine, abbiamo usato nuovamente l’utilità Assignable
della vista JavaArchive
per passare ad una nuova vista: quella capace di esportare i contenuti in modalità ZIP. In questo caso abbiamo usato lo ZipExporter
che ci permette di esportare su di un File
, OutputStream
, o persino ricevere contenuti i contenuti come InputStream
in modo che possiamo trattare essi stessi come byte.
Ci sono 3 tipi di exporters in ShrinkWrap:
Exporter | Formato di Output |
---|---|
org.jboss.shrinkwrap.api.exporter.TarExporter |
TAR |
org.jboss.shrinkwrap.api.exporter.TarGzExporter |
TAR.GZ |
org.jboss.shrinkwrap.api.exporter.ZipExporter |
ZIP |
Naturalmente, possiamo anche ottenere un archivio ShrinkWrap da un file flat in modo simile utilizzando i seguenti importer:
Importer | Formato di Output |
---|---|
org.jboss.shrinkwrap.api.importer.TarImporter |
TAR |
org.jboss.shrinkwrap.api.importer.TarGzImporter |
TAR.GZ |
org.jboss.shrinkwrap.api.importer.ZipImporter |
ZIP |
Tanto per completare il precedente esempio ecco un esempio di codice per eseguire un import :
JavaArchive roundtrip = ShrinkWrap
.create(ZipImporter.class, "myPackageRoundtrip.jar")
.importFrom(new File("/home/alr/Desktop/myPackage.jar"))
.as(JavaArchive.class);
Nota come passiamo lo ZipImporter
nel metodo ShrinkWrap.create
, visto che anch’esso è di tipo Assignable
! Notate una certa somiglianza?
Questo conclude la nostra introduzione per gestire i contenuti con ShrinkWrap. Speriamo che troverete le API molto intuitive e consistenti, e benvenuti alla nostra community.
Share the Knowledge
Find this guide useful?
There’s a lot more about Arquillian to cover. If you’re ready to learn more, check out the other available guides.
Feedback
Find a bug in the guide? Something missing? You can fix it by forking this website, making the correction and sending a pull request. If you’re just plain stuck, feel free to ask a question in the user discussion forum.
Recent Changelog
- Sep 21, 2017: Fix(scripts) timeout for waiting for timestamp available on pages is by Matous Jobanek