Follow Us on Twitter

Oracle ADF-applicaties bouwen met Jenkins en Maven

Maart 2013 - Het is even wennen als je als Java-ontwikkelaar voor het eerst in aanraking komt met Oracle ontwikkelsoftware en JDeveloper. Veel Java-ontwikkelaars werken voornamelijk met Eclipse en platformen als Maven, Spring en Hibernate.

Oracle’s JDeveloper maakt het met al zijn wizards en knoppen mogelijk om snel en eenvoudig te ontwikkelen en te deployen. Dit is makkelijk, zolang je als ontwikkelaar alleen werkt. Wanneer je in één groot ontwikkelteam werkt aan één product, is er behoefte aan één centraal punt waar de gezamenlijke sources gebouwd worden. Een van de andere zaken die je als Java/Eclipse-ontwikkelaar daarin mist is het specificeren van dependencies met de juiste versie en het ophalen en deployen daarvan via een centrale respository. Het kunnen deployen van ADF libraries, die over verschillende projecten worden gebruikt, is niet eenvoudig bij het ontwikkelen in JDeveloper. Hiervoor moet een ontwikkelaar, de zelf gemaakte ADF libraries in het project samen met de source code inchecken. De andere ontwikkelaars moeten tijdens het ontwikkelen regelmatig hun project via de centrale source code management updaten. Met behulp van Maven kan bij elke bouw poging gecontroleerd worden of de meest actuele libraries gebruikt worden.

Het gebruiken van een Continuous Integration (CI) Server met Oracle Fusion Middleware is door mijn collega Dirk al besproken in "Continuous Integration met Oracle Fusion Middleware". Met behulp van een JDeveloper-installatie op de Hudson server kunnen OFM projecten worden gebouwd en getest. In dit Whitebook ga ik ADF applicaties hieraan toevoegen. De ADF applicaties worden opgebouwd met behulp van Maven en Nexus. In deze opzet is geen JDeveloper-installatie meer nodig op de CI-server om te compileren.

Dit Whitebook is geschreven in de vorm van een stappenplan om een Oracle ADF project om te zetten naar een Maven project, om deze vervolgens te kunnen deployen via een CI-Server.

Omgeving

Het is belangrijk voor dit Whitebook dat de omgeving goed is opgebouwd en dat de juiste versies zijn geïnstalleerd met eigen smaak en kennis. In dit hoofdstuk wordt stap voor stap beschreven hoe de omgeving verder ingericht moet worden voor het gebruik van ADF.

Omgevingsreferenties

Voor dit Whitebook zijn de volgende software ontwikkeltools gebruikt:

  • Maven 3.0.4
  • JDeveloper 11.1.2.3
  • SVN 1.7
  • Jenkins 1.466.2
  • Nexus 2.2
  • Sonar 3.3
  • Java JDK 1.6

Oracle Libraries

Maven heeft de ADF libraries nodig om deze als dependency op te nemen in de pom. Deze libraries moeten daarom eerst benaderbaar zijn voor Maven. Helaas heeft Oracle nergens op Internet een standaard Maven repository beschikbaar voor ADF. Om dit gebrek af te vangen gebruiken we het open source project "Maven-ADF" om de libraries te kopiëren van een JDeveloper-installatie naar de Nexus repository.

Het project Maven-ADF is een project van Leif Nelson. Dit project genereert scripts aan de hand van een aantal properties. Met deze scripts worden de Oracle Libraries in de Nexus repository geplaatst.

Voordat het Maven-ADF uitgevoerd kan worden moeten op dezelfde omgeving JDeveloper, Maven en SVN geïnstalleerd zijn. Voer nu de volgende stappen uit om Maven-ADF te installeren.

Ophalen van de sources gebeurt via SVN. Voer het volgende commando uit:

  svn co http://maven-adf.googlecode.com/svn/trunk maven-adf

Na het ophalen verander je in het bestand "sample.properties" de volgende properties:

Version         11.1.2.3.0
Jdevhome        /opt/oracle/middleware/jdeveloper
Repourl         http://[server]:[port]/nexus/content/repositories/thirdparty
Repoid          Nexus
Groupbase       com.oracle.jdeveloper
Pompath         target/scripts/poms
scriptpath      target/scripts
usemanifestclasspaths true

TIP: Zorg ervoor dat de settings.xml een gebruiker heeft met voldoende deploymentrechten met het profielId Nexus.

Voer nu het volgende commando's uit om de installatiescripts klaar te maken en uit te voeren:

mvn clean package exec:java –Dexec.args="-config sample.properties"
cd target/scripts
./deploy-adf-jars.sh
./deploy-adf-poms.sh

Hiermee worden de libraries en pom’s in Nexus geplaatst. Na het uitvoeren van deze twee scripts is je ontwikkelomgeving klaar om de libraries centraal van je Nexus omgeving op te halen.

Oracle ADF Applicatie

ADF Libraries

Een van de bijzonderheden van Oracle ADF is de ADF Library. Deze library lijkt op een standaard Java library, maar is toch net iets anders. Zo kan een ADF Library naast de gebruikelijke gecompileerde sources ook fragments, js, images en pages bevatten. In de map "adfLibrary" wordt het bestand "adflibREADME.txt" en een map META-INF met de volgende inhoud toegevoegd:

  • adflibWEBINDEX.txt
  • adfm.xml
  • faces-config.xml
  • oracle.adf.common.services.ResourceService.sva
  • [name].taglib.xml
  • [name].tld

De eerste vier bestanden zijn gegenereerd door JDeveloper en staan in de classes map. Het bestand faces-config.xml moet, nadat deze gegenereerd is, nog verder worden verrijkt met component verwijzingen. Deze verwijzingen vormen een relatie tussen de jspx componenten en de door JDeveloper gegenereerde componenten die zich bevinden in de map classes/.jsps/Component.java.

TIP: Om goed in te spelen op de verschillen tussen de door JDeveloper gegenereerde deployment en een door Maven gegenereerde deployment is het noodzakelijk om vooraf een EAR te maken via JDeveloper. Deze EAR kan worden gebruikt als vergelijkingsmateriaal voor de uiteindelijke Maven deployment.

ADF generated code

Het compileren van Oracle ADF applicaties met behulp van CI-Server (Jenkins) is niet zo eenvoudig als het lijkt. Oracle JDeveloper genereert code aan de hand van bepaalde acties die de ontwikkelaar uitvoert, bijvoorbeeld bij het aanmaken van jspx bestanden. Deze code wordt bewaard in, voor Unix omgevingen, verborgen mappen. De gegenereerde code is noodzakelijk voor de werking van de uiteindelijke Oracle ADF applicatie.

Nu bekend is dat de ADF Library bestaat uit gecompileerde en gegenereerde code, is er ook nog een ander grijs vlak dat door JDeveloper veroorzaakt wordt. Dit is code die gegenereerd is door JDeveloper en, tijdens de bouwfase gecompileerd en meegenomen wordt binnen de ADF Library.

De code wordt gegenereerd uit de .jspx bestanden van het project en wordt vervolgens geplaatst in de map .jsps onder de map classes. Dit is dezelfde source code die eerder werd genoemd bij het verrijken van de faces-config.xml.

Het is, voor het compileren van het Maven project, noodzakelijk dat de gegenereerde sources mee worden genomen met het inchecken van de source in de source repository. In de pom moet de locatie van de gegenereerde sources als "source pad" worden opgegeven.

Maven project

Nu de bijzonderheden van JDeveloper in kaart zijn gebracht, kan er een "pom.xml" bestand aan het ADF Library project worden toegevoegd.

Als eerste worden de basiselementen van de pom gemaakt. Zo wordt er een groupId, artifactId, name, version, description en packaging ingesteld.

<?xml version="1.0" encoding="UTF-8" ?>
<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>groupId</groupId>
	<artifactId>artifactId</artifactId>
	<name>artifactId</name>
	<version>1.0-SNAPSHOT</version>
	<description>Generated POM from JDeveloper for project artifactId</description>
	<packaging>jar</packaging>

Als tweede worden de resources bepaald.

<build>
	<sourceDirectory>src/</sourceDirectory>
	<testSourceDirectory>test/</testSourceDirectory>
	<outputDirectory>classes/</outputDirectory>
	<testOutputDirectory>classes/</testOutputDirectory>
	<resources>
		<resource>
			<directory>adfLibrary</directory>
		</resource>
		<resource>
			<directory>public_html</directory>
		</resource>
		<resource>
			<directory>src</directory>
			<includes>
				<include>**/*.xml</include>
				<include>**/*.xsd</include>
				<include>**/*.wsdl</include>
				<include>**/*.properties</include>
				<include>**/*.jpx</include>
				<include>**/*.xml</include>
			</includes>
		</resource>
	</resources>

Wat hier opvalt is de map "adfLibrary". Dit is de map die ik heb aangemaakt om de specifieke ADF bestanden in te bewaren. Deze bestanden heb ik uit de deployment (EAR) gehaald die de JDeveloper voor mij heeft gegenereerd. Het volgende onderdeel zijn de plugins.

<plugins>
	<plugin>
		<groupId>org.codehaus.mojo</groupId>
		<artifactId>build-helper-maven-plugin</artifactId>
		<executions>
			<execution>
				<phase>generate-sources</phase>
				<goals>
					<goal>add-source</goal>
				</goals>
				<configuration>
					<sources>
						<source>classes/.jsps/</source>
					</sources>
				</configuration>
			</execution>
		</executions>
	</plugin>
	<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-compiler-plugin</artifactId>
		<version>3.0</version>
		<configuration>
			<source>1.6</source>
			<target>1.6</target>
		</configuration>
	</plugin>
	<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-clean-plugin</artifactId>
		<version>2.5</version>
		<configuration>
			<skip>true</skip>
		</configuration>
	</plugin>
</plugins>
</build>

Wat hierin opvalt is dat er een build-helper-maven-plugin wordt aangeroepen om de .jsps java bestanden te compileren en dat de clean geskipt wordt. Het compileren van de .jsps java bestanden is noodzakelijk voor de werking van de applicatie. De reden waarom de clean niet mag worden aangeroepen zit in het feit dat deze de classes map verwijdert en dus ook de ".jspx" bestanden, die we speciaal bewaard hebben in de source repository. Hierna volgen de dependencies. Dit zijn libraries die noodzakelijk zijn voor het compileren van de sources en welke eventueel meegenomen moeten worden binnen het uiteindelijke EAR of WAR bestand.

<dependencies>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.8.1</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.jmock</groupId>
		<artifactId>jmock</artifactId>
		<version>2.5.1</version>
		<type>jar</type>
		<scope>test</scope>
	</dependency>
	<!-- Runtime Dependencies, some of these are JDeveloper library files that 
		are being packaged by JDev during a build -->
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Commons_Beanutils_1.6</artifactId>
		<version>${jdev.version}</version>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>com.oracle.jdeveloper.jars.jdeveloper.jlib</groupId>
		<artifactId>bundleresolver</artifactId>
		<version>11.1.2.3.0</version>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Commons_Collections_3.1</artifactId>
		<version>${jdev.version}</version>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Commons_Logging_1.0.4</artifactId>
		<version>${jdev.version}</version>
		<type>pom</type>
	</dependency>
	<!-- Begin JDeveloper Library Dependencies, these are only used at compile 
		time -->
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_DVT_Faces_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Model_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Model_Generic_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>JSTL_1.2</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>JSTL_1.2_Tags</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Trinidad_Runtime_11</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>JSF_2.0</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Resource_Bundle_Variable_Resolver</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_DVT_Faces_Databinding_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Faces_Databinding_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Page_Flow_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Controller_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Controller_Schema</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Faces_Runtime_11</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Common_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Web_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>MDS_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>MDS_Runtime_Dependencies</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Common_Web_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>JSP_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Oracle_JEWT</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>BC4J_Oracle_Domains</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>BC4J_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>BC4J_Security</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>BC4J_Tester</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Oracle_JDBC</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Resource_Bundle_Support</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<!-- End JDeveloper Library Dependencies -->
</dependencies>

Binnen de dependencies zitten geen bijzondere libraries. Sommige worden alleen gebruikt voor het uitvoeren van testen (<scope>test</scope>) andere worden alleen gebruik voor het compileren (<scope>provided</scope>). Wanneer dit project als packaging "WAR" heeft, worden de dependencies met scope compiler of wanneer er geen scope is gedefinieerd binnen de WAR opgenomen.

Als laatste moeten in de pom moeten de properties bekend worden gemaakt. Deze hebben betrekking op de ingevulde waardes van maven-adf (sample.properties). Daarnaast worden de scm en distributionManagement gegevens in de pom geplaatst om een project te kunnen deployen en eventueel te releasen via maven.

<properties>
	<jdev.version>11.1.2.3.0</jdev.version>
	<jdev.group.id>com.oracle.jdeveloper.library</jdev.group.id>
</properties>
<scm>
	<connection> </connection>
	<developerConnection> </developerConnection>
	<url> </url>
</scm>
<distributionManagement>
	<repository>
		<id>deploymentRepoReleases</id>
		<name>Releases (Nexus)</name>
		<url>http://<server>:<port>/nexus/content/repositories/releases/</url>
	</repository>
	<snapshotRepository>
		<id>deploymentRepoSnapshots</id>
		<name>Snapshots (Nexus)</name>
		<url>http://<server>:<port>/nexus/content/repositories/snapshots/</url>
	</snapshotRepository>
</distributionManagement>

War Project

Naast het gebruik van ADF Libraries in een Oracle applicatie is er ook een WAR nodig. Deze WAR is het hart van je Oracle ADF applicatie. Een WAR project wijkt niet zoveel af van een ADF library project. Daarom bespreek ik in dit hoofdstuk enkel het verschil van het Maven project.

<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>groupId</groupId>
	<artifactId>artifactId</artifactId>
	<name>artifactId</name>
	<version>1.0-SNAPSHOT</version>
	<description>Generated POM from JDeveloper for project artifactId</description>
	<packaging>war</packaging>

Het eerste verschil is dat deze gepackaged wordt als een WAR. Hiermee zorg je ervoor dat de WAR plugin van Maven gebruikt wordt. Deze plugin zorgt ervoor dat er uiteindelijk een ".war" bestand wordt aangemaakt dat gedeployed kan worden op de server.

<resources>
	<resource>
		<directory>adfmsrc</directory>
	</resource>
	<resource>
		<directory>src</directory>
		<includes>
			<include>**/*.xml</include>
			<include>**/*.xsd</include>
			<include>**/*.wsdl</include>
			<include>**/*.properties</include>
			<include>**/*.jpx</include>
			<include>**/*.xml</include>
		</includes>
	</resource>
</resources>

Het volgende verschil is dat binnen de WAR de map adfmsrc wordt meegenomen, hierin wordt door JDeveloper specifieke ADF projectinformatie bewaard. Deze wordt in de hoofdmap van de WAR meegenomen.

<plugins>
	<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-compiler-plugin</artifactId>
		<version>3.0</version>
		<configuration>
			<source>1.6</source>
			<target>1.6</target>
		</configuration>
	</plugin>
	<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-war-plugin</artifactId>
		<version>2.3</version>
		<configuration>
			<warSourceDirectory>public_html</warSourceDirectory>
			<warName>${project.name}-${project.version}</warName>
		</configuration>
	</plugin>
	<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-clean-plugin</artifactId>
		<version>2.5</version>
		<configuration>
			<skip>true</skip>
		</configuration>
	</plugin>
</plugins>

Bij de plugins is er een plugin bijgekomen, de "maven-war-plugin". JDeveloper gebruikt standaard de "public_html" map als hoofdmap voor de webapplicatie. Normaal verwacht de "maven-war-plugin" een map met de naam "webapps".

<dependencies>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-api</artifactId>
		<version>1.6.1</version>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.6.1</version>
		<scope>compile</scope>
	</dependency>
	<!-- Test Only Dependencies -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.8.1</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.jmock</groupId>
		<artifactId>jmock</artifactId>
		<version>2.5.1</version>
		<scope>test</scope>
	</dependency>
	<!-- Runtime Dependencies, some of these are JDeveloper library files that 
		are being packaged by JDev during a build -->
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Commons_Beanutils_1.6</artifactId>
		<version>${jdev.version}</version>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>com.oracle.jdeveloper.jars.jdeveloper.jlib</groupId>
		<artifactId>bundleresolver</artifactId>
		<version>11.1.2.3.0</version>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Commons_Collections_3.1</artifactId>
		<version>${jdev.version}</version>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Commons_Logging_1.0.4</artifactId>
		<version>${jdev.version}</version>
		<type>pom</type>
	</dependency>
		<!-- Begin JDeveloper Library Dependencies, these are only used at compile 
		time -->
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Model_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Model_Generic_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>JSTL_1.2</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>JSTL_1.2_Tags</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Trinidad_Runtime_11</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>JSF_2.0</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Resource_Bundle_Variable_Resolver</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_DVT_Faces_Databinding_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Faces_Databinding_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Page_Flow_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Controller_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Controller_Schema</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Faces_Runtime_11</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Common_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Web_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>MDS_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>MDS_Runtime_Dependencies</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>ADF_Common_Web_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>JSP_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Oracle_JEWT</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>BC4J_Oracle_Domains</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>BC4J_Runtime</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>BC4J_Security</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>BC4J_Tester</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Oracle_JDBC</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>${jdev.group.id}</groupId>
		<artifactId>Resource_Bundle_Support</artifactId>
		<version>${jdev.version}</version>
		<scope>provided</scope>
		<type>pom</type>
	</dependency>
</dependencies>

Bij de dependencies zijn er "slf4j" dependencies aan toegevoegd, deze zorgen voor het koppelen van "log4j" aan WebLogic logging. Natuurlijk kan er ook gebruik worden gemaakt van de standaard ADFLogger. Verder moeten hier ook de dependencies van de zelf gemaakte ADF libraries bijkomen. Dit kan op de volgende manier:

<dependency>
	<groupId>groupId</groupId>
	<artifactId>artifactId</artifactId>
	<version>version</version>
	<scope>compile</scope>
</dependency>

Oracle ADF Applicatie

Een ADF Library en een WAR zijn beide onderdeel van een ADF Applicatie. Normaal wordt er door JDeveloper voor WebLogic een EAR bestand gemaakt Dit EAR bestand kan dan gebruikt worden voor de deployment van complete Oracle ADF Applicatie op een WebLogic server. In dit hoofdstuk gaan we verder met het maken van een EAR bestand met behulp van Maven. Tevens maken we een parent pom, waarin project-overlappende gegevens worden verwerkt en andere project-gerelateerde informatie zoals ontwikkelaar-, bedrijfs- en omgevinggegevens.

EAR

Bij Oracle JDeveloper kan er via het deploymentmenu een EAR bestand gedeployed worden op een applicatieserver. Hiermee wordt door JDeveloper aan de hand van de aanwezige applicatie een EAR bestand gemaakt die dan weer gedeployed kan worden op een WebLogic omgeving. Binnen Maven is de tool niet aanwezig en moet het EAR bestand gemaakt worden met behulp van een extra project binnen de Oracle ADF Applicatie. Dit project bevat enkel een pom bestand met de gegevens zoals hieronder getoond.

<?xml version="1.0" encoding="UTF-8" ?>
<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId> groupId </groupId>
	<artifactId> artifactId </artifactId>
	<name> artifactId </name>
	<version>1.0-SNAPSHOT</version>
	<description>Project for artifactId</description>
	<packaging>ear</packaging>
	<build>
		<finalName>finalName</finalName>
		<outputDirectory>${project.build.directory}/${project.build.finalName}/adf</outputDirectory>
		<resources>
			<resource>
				<directory>../.adf</directory>
				<filtering>true</filtering>
				<includes>
					<include>**/*</include>
				</includes>
			</resource>
		</resources>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.0</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-ear-plugin</artifactId>
				<version>2.8</version>
				<configuration>
					<finalName>DigiForms</finalName>
					<version>1.4</version>
					<earSourceDirectory>../src/</earSourceDirectory>
					<archive>
						<addMavenDescriptor>false</addMavenDescriptor>
					</archive>
					<modules>
						<webModule>
							<groupId> groupId </groupId>
							<artifactId> artifactId </artifactId>
							<bundleFileName> FileName.war</bundleFileName>
							<contextRoot> FileName </contextRoot>
						</webModule>
					</modules>
					<defaultLibBundleDir>lib</defaultLibBundleDir>
					<resourcesDir>../target/classes</resourcesDir>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<version>2.4</version>
				<executions>
					<execution>
						<id>adf-loc-jar</id>
						<phase>prepare-package</phase>
						<configuration>
							<finalName>adf-loc</finalName>
							<outputDirectory>${project.build.directory}/${project.build.finalName}/lib</outputDirectory>
							<excludes>
								<exclude>**</exclude>
							</excludes>
							<archive>
								<manifestEntries>
									<Class-Path>../adf</Class-Path>
								</manifestEntries>
							</archive>
						</configuration>
						<goals>
							<goal>jar</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId> groupId </groupId>
			<artifactId> artifactId </artifactId>
			<version>1.0-SNAPSHOT</version>
			<type>war</type>
		</dependency>
	</dependencies>
	<parent>
		<groupId> groupId </groupId>
		<artifactId> artifactId </artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>
</project>

Wat binnen het pom bestand opvalt is dat er bepaalde mappen van de Oracle Applicatie mee worden genomen bij de samenstelling van het EAR bestand. Daarnaast wordt er van de adf map een adf-loc jar gemaakt die binnen het EAR bestand wordt meegenomen.

De enige dependency van het project is die van het WAR project. Deze wordt binnen de EAR file opgenomen als de aanwezige applicatie. Het is belangrijk dat bij het configureren van het WAR bestand in de Webmodule, de WAR dezelfde naam heeft als de WAR die door JDeveloper gemaakt is. De contextRoot heeft meestal dezelfde naam als het WAR bestand.

Parent pom

Om de Oracle applicatie als één project te zien kan er gekozen worden voor het maken van een Parent pom met modules. Binnen deze Pom kan dependenciesManagement worden opgenomen. Hiermee vertel je welke versies van de dependencies gebruikt moeten worden binnen de modules. Het is gebruikelijk om in deze pom alle overlappende informatie van de modules op te nemen. Zo wordt voorkomen dat informatie dubbel opgeslagen wordt.

<?xml version="1.0" encoding="UTF-8" ?>
<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId> groupId </groupId>
	<artifactId> artifactId </artifactId>
	<name> artifactId </name>
	<version>1.0-SNAPSHOT</version>
	<description>Super POM for artifactId </description>
	<modules>
		<module> </module>
		<module> </module>
		<module> </module>
		<module> </module>
	</modules>
	<packaging>pom</packaging>
	<scm>
		<connection></connection>
		<developerConnection></developerConnection>
		<url> </url>
	</scm>
	<issueManagement>
		<url>url</url>
		<system>JIRA</system>
	</issueManagement>
	<ciManagement>
		<url>url</url>
		<system>Jenkins</system>
	</ciManagement>
	<properties>
		<jdev.version>11.1.2.3.0</jdev.version>
		<jdev.group.id>com.oracle.jdeveloper.library</jdev.group.id>
	</properties>
	<distributionManagement>
		<repository>
			<id>deploymentRepoReleases</id>
			<name>Releases (Nexus)</name>
			<url>http://<server>:<port>/nexus/content/repositories/releases/</url>
		</repository>
		<snapshotRepository>
			<id>deploymentRepoSnapshots</id>
			<name>Snapshots (Nexus)</name>
			<url>http://<server>:<port>/nexus/content/repositories/snapshots/</url>
		</snapshotRepository>
	</distributionManagement>
</project>

De parent pom wordt opgeslagen in de hoofdmap van de Oracle Applicatie. Binnen de parent pom worden modules gedefinieerd. De naam van de modules is de artifact naam van het Oracle project dat onderdeel is van de Oracle applicatie. Het opnemen van een Oracle project als module binnen de parent pom heeft als voordeel dat bij het bouwen van de parent pom alle modules meegebouwd worden. Bij de projecten die gebruik willen maken van de gegevens van de parent pom moet het volgende stuk xml worden opgenomen in de pom.xml van het project.

<parent>
	<groupId> groupId </groupId>
	<artifactId> artifactId </artifactId>
	<version>1.0-SNAPSHOT</version>
</parent>

TIP: Maven gebruiken binnen JDeveloper, op de Oracle website is een stap voor stap instructie te vinden om Maven projecten binnen JDeveloper te gebruiken.

Continuous Integration

Nu de Oracle Applicatie klaar is en lokaal gebouwd kan worden met Maven gaan we verder met de volgende stap: Het bouwen van een ADF applicatie met behulp van Continuous Integration.

CI-Applicatie (Jenkins)

Jenkins is een van de meest gebruikte CI applicaties. Het is ontstaan uit Hudson. Toen Sun door Oracle werd overgenomen is bijna de gehele community achter Hudson overgestapt naar Jenkins en is hier zonder beperkingen mee doorgegaan. De keuze van Jenkins boven Hudson heeft te maken met de plugins. De community van Jenkins ontwikkelt de plugins specifiek voor Jenkins en deze werken niet altijd op Hudson.

Configuratie

Om Jenkins goed te kunnen gebruiken binnen een ontwikkelstraat met Maven is het verstandig Jenkins te configureren met een Java JDK en een installatie van Maven 3.0.4.

Verder zijn de volgende plugins erg handig:

  • Jenkins Maven Release Plug-in
  • Sonar plugin
  • Maven 2 Project plugin

De Jenkins Maven Release Plug-in zorgt ervoor dat je met één druk op de knop een project kan Releasen. Hiermee wordt de versie van je applicatie van 1.0.0-SNAPSHOT naar 1.0.0 omgezet. Deze wordt getagd en er wordt een 1.0.1-SNAPSHOT in de trunk geplaatst. De 1.0.0 versie van de applicatie wordt vervolgens in release van de Nexus repository gezet.

De Sonar plugin zorgt ervoor dat de sources aan het bouwproces van Sonar worden aangeboden. Sonar analyseert de code op basis van een aantal regels en tools.

De Maven 2 Project plugin zorgt ervoor dat er een Job aangemaakt kan worden om maven projecten te bouwen.

TIP: Zorg er voor dat je altijd de stabiele Jenkins release download in plaats van de wekelijkse builds. De stabiele releases zijn verder doorgetest dan de wekelijkse builds.

Job

Binnen Jenkins wordt voor de ADF Applicatie een Job aangemaakt, zodat deze gebouwd, gedeployed en gereleased kan worden door Jenkins. Hieronder wordt in een paar stappen beschreven hoe een Job aangemaakt wordt.

New Job
Figuur 1: New Job

Vul in bij Figuur 1 als Job name de naam van het maven project dat je wilt bouwen. Selecteer vervolgens "Build a maven 2/3 project".

Source Code Management
Figuur 2: Source Code Management

Selecteer bij Source Code Management de locatie waar de source code staat opgeslagen. Selecteer de map waarin de "parent pom" is opgeslagen.

Build
Figuur 3: Build

Vul in bij Figuur 3, Goals and options het woord deploy. Hiermee wordt bij elke uitvoering van de Job een SNAPSHOT in Nexus geplaatst.

Build Environment
Figuur 4: Build Environment

Vink aan bij figuur 4 de Maven release bulid. Met deze actie kan er van de source code een maven release gemaakt worden. Deze release wordt dan opgeslagen in Nexus. Een maven release levert standaard drie jar bestanden op een source jar , een gecompileerde jar en een java-doc jar. Daarnaast wordt de versie automatisch verhoogd en terug ingecheckt in de source code management.

Post Build Actions
Figuur 5: Post-build Actions

Bij figuur 5 selecteer bij "Add post-build action" "Sonar". Dit zorgt ervoor dat na een succesvolle compilatie van de source code, de set van source code aan Sonar wordt aangeboden. Sonar past vervolgens een grote set aan rules toe om de kwaliteit van de source code te controleren.

Conclusie

Maven in Combinatie met ADF en JDeveloper maakt het voor het ontwikkelteams eenvoudiger om gezamenlijk te werken aan een grote applicatie. JDeveloper heeft de wizards en tools om ADF applicaties eenvoudig te ontwikkelen, Maven heeft de tools en plugins om te compileren, deployen en de afhankelijkheden te beheren.

Elk Maven project heeft zijn eigen ontwikkel-lifecycle, hiermee kan duidelijk afgestemd worden welke functionaliteit er in welke versie zit. Op basis van de losse projecten kan een complete ADF applicatie samen gesteld worden en als één product worden opgeleverd.

Door het centraal beheren en registreren van de Java libraries, gebruikt iedereen dezelfde libraries om te ontwikkelen, hiermee wordt voorkomen dat er versie conflicten ontstaan tussen de sub-projecten.

Met behulp van de CI-Server kunnen de verschillende projecten centraal gebouwd, getest en geanalyseerd worden. Alle informatie om de sources te kunnen bouwen en deployen staat beschreven in het "pom" bestand. Alle hulpmiddelen die nodig zijn worden vervolgens gehaald uit de centrale Nexus repository, hierdoor wordt een project altijd op dezelfde manier gebouwd, onafhankelijk van de omgevingsvariabelen.

Referenties

Waardering:
 
Tags:

Reacties

Nieuwe reactie inzenden

De inhoud van dit veld is privé en zal niet openbaar worden gemaakt.

Meer informatie over formaatmogelijkheden

CAPTCHA
Deze vraag is om te testen of u een persoon bent en om spam te voorkomen
Image CAPTCHA
Enter the characters shown in the image.