After a long and arduous battle, I finally deployed a simple webapp that employs a combination of these technologies (JBoss EAP 6.2 [AS 7.3.0], Jackrabbit 2,7, Oracle 11g, and RestEasy 3.0). Since this would have been impossible without help from many forums, I thought I would share my trail of bread crumbs here on this forum, for what it's worth. The instructions from Brian Wallis were indeed very helpful, but certain steps were missing and/or out-of-date, thereby invoking further collision between my head and a nearby wall.
This example uses RestEasy to receive data from an HTTP POST and passes it via the JCR API to Jackrabbit and then to an Oracle database for storage. A subsequent HTTP GET will retreive the same data.
Start with JBoss EAP 6.2 (or JBoss AS 7.3.0 Final). This process also works with WildFly 8.1.0 Final.
Add a JCR module to the jboss-eap-6.2/modules directory. Here is what mine looks like:
$ cd jboss-eap-6.2/modules/ $ find javax -type f javax/jcr/main/jcr-2.0.jar javax/jcr/main/module.xml $ sha1sum javax/jcr/main/jcr-2.0.jar 08297216bcfe4aea369ed6ee0d1718133f752e97 javax/jcr/main/jcr-2.0.jar $ cat javax/jcr/main/module.xml <?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.1" name="javax.jcr"> <resources> <resource-root path="jcr-2.0.jar"/> </resources> <dependencies> <module name="javax.transaction.api" export="true"/> </dependencies> </module> $
Add an ojdbc module to the jboss-eap-6.2/modules directory. Here is what mine looks like:
$ find com -type f com/oracle/db/main/ojdbc6.jar com/oracle/db/main/module.xml $ sha1sum com/oracle/db/main/ojdbc6.jar 8d98e89385dafc7e1b8a2cfc1e016deb21246236 com/oracle/db/main/ojdbc6.jar $ cat com/oracle/db/main/module.xml <?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.1" name="com.oracle.db"> <resources> <resource-root path="ojdbc6.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module> $
Tell JBoss to register ojdbc as a core module, using jboss-cli.sh:
jboss-eap-6.2/bin$ ./jboss-cli.sh You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] connect [standalone@localhost:9999 /] /subsystem=datasources/jdbc-driver=oracle:add(driver-name=oracle,driver-module-name=com.oracle.db,driver-xa-datasource-class-name=oracle.jdbc.xa.client.OracleXADataSource) {"outcome" => "success"} [standalone@localhost:9999 /]
Add a datasource. Here's what mine looks like:
<subsystem xmlns="urn:jboss:domain:datasources:1.1"> <datasources> <datasource jta="false" jndi-name="java:/jdbc/DocumentStoreDS" pool-name="DocumentStoreDS" enabled="true" use-ccm="false"> <connection-url>jdbc:oracle:thin:@10.0.0.5:1521:xe</connection-url> <driver-class>oracle.jdbc.OracleDriver</driver-class> <driver>oracle</driver> <security> <user-name>rabbit</user-name> <password>rabbit</password> </security> <validation> <validate-on-match>false</validate-on-match> <background-validation>false</background-validation> </validation> <statement> <share-prepared-statements>false</share-prepared-statements> </statement> </datasource> <drivers> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> <driver name="oracle" module="com.oracle.db"> <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem>
Disable JCA validation. Note that this is a known (and apparently accepted?) workaround: https://issues.apache.org/jira/browse/JCR-3241
<subsystem xmlns="urn:jboss:domain:jca:1.1"> <archive-validation enabled="false" fail-on-error="true" fail-on-warn="false"/> ... </subsystem>
Add a Resource Adapter for Jackrabbit. The "HomeDir" and "ConfigFile" must reside somewhere on the server, but the actual repository contents will reside in the database, as specified in the repository.xml file. The repository.xml file that I used is attached.
<subsystem xmlns="urn:jboss:domain:resource-adapters:1.1"> <resource-adapters> <resource-adapter id="jackrabbit-jca-2.8.0.rar"> <archive> jackrabbit-jca-2.8.0.rar </archive> <transaction-support>XATransaction</transaction-support> <connection-definitions> <connection-definition class-name="org.apache.jackrabbit.jca.JCAManagedConnectionFactory" jndi-name="java:/jca/DocumentStore" enabled="true" pool-name="RabbitAdapter"> <config-property name="HomeDir"> /media/homespace/field </config-property> <config-property name="ConfigFile"> /media/homespace/field/repository.xml </config-property> <security> <application/> </security> <validation> <background-validation>false</background-validation> </validation> </connection-definition> </connection-definitions> </resource-adapter> </resource-adapters> </subsystem>
Before deploying the jackrabbit-jca-2.8.0.rar file, it must be modified. Decompress the file, and remove the two logback jars (core and classic). Then add the ojdbc6.jar. Then modify the MANIFEST.MF such that it states its dependency on javax.jcr. Shown below are the contents of my MANIFEST.MF. After adding the "Dependencies" line, compress it again, taking care to preserve your modification to the manifest (e.g. using the "m" option of the jar command).
$ cat META-INF/MANIFEST.MF Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Created-By: Apache Maven Built-By: jzitting Build-Jdk: 1.7.0_40 Dependencies: javax.jcr export,org.slf4j $
Deploy jackrabbit-jca-2.8.0.rar. This should connect to your database and create tables and sequences. The attached repository.xml file will result in the creation of the following tables and sequences:
TABLE_NAME ------------------------------ JR_DATASTORE JR_FSDEF_FSENTRY JR_FSVER_FSENTRY JR_FS_FSENTRY JR_PMDEF_BINVAL JR_PMDEF_BUNDLE JR_PMDEF_NAMES JR_PMDEF_REFS JR_PMVER_BINVAL JR_PMVER_BUNDLE JR_PMVER_NAMES JR_PMVER_REFS SEQUENCE_NAME ------------------------------ JR_PMDEF_SEQ_NAMES_ID JR_PMVER_SEQ_NAMES_ID
Deploy conejo.war. The source code (maven project) for conejo.war is attached. Note that the maven-war-plugin is used to add the "Dependencies" line to MANIFEST.MF, as was done manually in a previous step for the rar file. It should deploy without error and be ready to respond to GET and PUT requests over HTTP.
Usage examples:
Plain text:
$ cat test.xml <?xml version="1.0" encoding="UTF-8"?> <test> <hello>hola</hello> <bye>adios</bye> </test> $ curl -X PUT --data-binary '@test.xml' http://localhost:8080/conejo/repo/123/test.xml ok $ curl http://localhost:8080/conejo/repo/123/test.xml <?xml version="1.0" encoding="UTF-8"?> <test> <hello>hola</hello> <bye>adios</bye> </test> $
Binary data:
$ curl -X PUT --data-binary '@mario.png' http://localhost:8080/conejo/repo/123/mario.png ok $ curl http://localhost:8080/conejo/repo/123/mario.png > data % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 700k 100 700k 0 0 1526k 0 --:--:-- --:--:-- --:--:-- 1526k $ cksum data mario.png 1451617279 717492 data 1451617279 717492 mario.png $
Note: The Produces("*/*") annotation of FedEx.getContent() tells the browser that the HTTP body "could be anything". The browser will then use the filename extension to guess at how to handle the content – so with the above example, putting http://localhost:8080/conejo/repo/123/mario.png in the browser will actually show the image. Without the Produces("*/*") annotation, RestEasy seems to specify "application/octet-stream", or somehow declare binary data, and the browser does not guess at the filetype.
Note: It seems to me that jackrabbit-jca-2.8.0.rar should not need to contain a copy of ojdbc6.jar, but it will not deploy without it. I imagine there is (yet another) subtle configuration detail that would resolve this oddity, and if there is then I'd be glad to know it.
Comments