From: Sanjay Dalal Date: Fri, 24 Jul 2009 18:29:44 +0000 (+0000) Subject: CSPACE-173, CSPACE-325, CSPACE-71, CSPACE-72, CSPACE-73, CSPACE-74. Introduced key... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=39bd6cb403303d585fea1807b9276cf4252a3b0b;p=tmp%2Fjakarta-migration.git CSPACE-173, CSPACE-325, CSPACE-71, CSPACE-72, CSPACE-73, CSPACE-74. Introduced key abstractions for repository client, document handler, factory and document wrapper in the services layer. Boiler plate code for interfacing with a repository via either Java Remote APIs or REST is moved to respective repository client implementations. A CS service only needs to implement a resource and a document handler. Exception management is improved such that GET, UPDATE and DELETE now return proper HTTP status codes if csid is invalid or not found. CollectionObject service is revamped to use new repository client framework. CollectionObjectService client test now asserts returned codes. Still need more rigorous negative tests. --- diff --git a/services/JaxRsServiceProvider/pom.xml b/services/JaxRsServiceProvider/pom.xml index 80073564a..a57a6c969 100644 --- a/services/JaxRsServiceProvider/pom.xml +++ b/services/JaxRsServiceProvider/pom.xml @@ -24,8 +24,8 @@ 5.2-SNAPSHOT 1.5-SNAPSHOT - - + + org.collectionspace.services @@ -74,9 +74,9 @@ 4.1 test - + - + jboss @@ -139,7 +139,7 @@ - + cspace-services @@ -157,6 +157,7 @@ undeploy + pre-integration-test ${project.build.directory}/${project.build.finalName}.war @@ -168,6 +169,7 @@ deploy + pre-integration-test ${project.build.directory}/${project.build.finalName}.war @@ -193,3 +195,4 @@ + diff --git a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java index f5d9fe086..d9f1845fe 100644 --- a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java +++ b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java @@ -1,6 +1,6 @@ package org.collectionspace.services.jaxrs; -import org.collectionspace.services.CollectionObjectResource; +import org.collectionspace.services.collectionobject.CollectionObjectResource; import org.collectionspace.services.id.IDResource; import org.collectionspace.services.IntakeResource; diff --git a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/jboss-web.xml b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/jboss-web.xml index c91efe084..33a226218 100644 --- a/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/jboss-web.xml +++ b/services/JaxRsServiceProvider/src/main/webapp/WEB-INF/jboss-web.xml @@ -1,5 +1,6 @@ - - java:/jaas/cspace - \ No newline at end of file + + java:/jaas/cspace + /cspace-services + diff --git a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java index 093400cc8..f9d778bd7 100644 --- a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java +++ b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java @@ -34,6 +34,7 @@ public class CollectionObjectServiceTest { CollectionObject collectionObject = createCollectionObject(identifier); ClientResponse res = collectionObjectClient.createCollectionObject(collectionObject); + verbose("createCollectionObject: status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), Response.Status.CREATED.getStatusCode()); //store updateId locally for "update" test @@ -48,6 +49,7 @@ public class CollectionObjectServiceTest { @Test(dependsOnMethods = {"createCollectionObject"}) public void updateCollectionObject() { ClientResponse res = collectionObjectClient.getCollectionObject(updateId); + verbose("getCollectionObject: status = " + res.getStatus()); CollectionObject collectionObject = res.getEntity(); verbose("Got CollectionObject to update with ID: " + updateId, collectionObject, CollectionObject.class); @@ -58,7 +60,7 @@ public class CollectionObjectServiceTest { // make call to update service res = collectionObjectClient.updateCollectionObject(updateId, collectionObject); - + verbose("updateCollectionObject: status = " + res.getStatus()); // check the response CollectionObject updatedCollectionObject = res.getEntity(); Assert.assertEquals(updatedCollectionObject.getObjectName(), collectionObject.getObjectName()); @@ -77,7 +79,10 @@ public class CollectionObjectServiceTest { @Test(dependsOnMethods = {"createCollection"}) public void getCollectionObjectList() { //the resource method is expected to return at least an empty list - CollectionObjectList coList = collectionObjectClient.getCollectionObjectList().getEntity(); + ClientResponse res = collectionObjectClient.getCollectionObjectList(); + CollectionObjectList coList = res.getEntity(); + verbose("getCollectionObjectList: status = " + res.getStatus()); + List coItemList = coList.getCollectionObjectListItem(); int i = 0; for(CollectionObjectList.CollectionObjectListItem pli : coItemList){ @@ -94,7 +99,7 @@ public class CollectionObjectServiceTest { ClientResponse res = collectionObjectClient.deleteCollectionObject(deleteId); verbose("deleteCollectionObject: csid=" + deleteId); verbose("deleteCollectionObject: status = " + res.getStatus()); - Assert.assertEquals(res.getStatus(), Response.Status.NO_CONTENT.getStatusCode()); + Assert.assertEquals(res.getStatus(), Response.Status.OK.getStatusCode()); } private CollectionObject createCollectionObject(long identifier) { diff --git a/services/collectionobject/service/pom.xml b/services/collectionobject/service/pom.xml index 203fc596f..a040d515c 100644 --- a/services/collectionobject/service/pom.xml +++ b/services/collectionobject/service/pom.xml @@ -25,6 +25,14 @@ org.collectionspace.services.collectionobject.jaxb 1.0 + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-log4j12 + junit @@ -38,7 +46,18 @@ 5.6 - + + + commons-beanutils + commons-beanutils + 1.6.1 + + + + commons-logging + commons-logging + 1.1 + diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectResource.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectResource.java deleted file mode 100644 index 28b6ea95f..000000000 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectResource.java +++ /dev/null @@ -1,266 +0,0 @@ -package org.collectionspace.services; - -import java.util.Iterator; -import java.util.List; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.DELETE; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.PathParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; -import javax.ws.rs.core.UriInfo; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; - -import org.collectionspace.services.CollectionObjectService; -import org.collectionspace.services.collectionobject.*; -import org.collectionspace.services.collectionobject.CollectionObjectList.*; -import org.collectionspace.services.CollectionObjectJAXBSchema; - -import org.dom4j.Document; -import org.dom4j.Element; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Path("/collectionobjects") -@Consumes("application/xml") -@Produces("application/xml") -public class CollectionObjectResource { - - final Logger logger = LoggerFactory - .getLogger(CollectionObjectResource.class); - - // This should be a DI wired by a container like Spring, Seam, or EJB3 - final static CollectionObjectService service = new CollectionObjectServiceNuxeoImpl(); - - public CollectionObjectResource() { - // do nothing - } - - @GET - public CollectionObjectList getCollectionObjectList(@Context UriInfo ui) { - CollectionObjectList p = new CollectionObjectList(); - try { - Document document = service.getCollectionObjectList(); - Element root = document.getRootElement(); - - // debug - System.err.println(document.asXML()); - - List list = p - .getCollectionObjectListItem(); - for (Iterator i = root.elementIterator(); i.hasNext();) { - Element element = (Element) i.next(); - // debug - System.err.println(); - element.asXML(); - - // set the CollectionObject list item entity elements - CollectionObjectListItem pli = new CollectionObjectListItem(); - pli.setObjectNumber(element.attributeValue("title")); - pli.setUri(element.attributeValue("url")); - pli.setCsid(element.attributeValue("id")); - list.add(pli); - } - - } catch (Exception e) { - e.printStackTrace(); - } - - return p; - } - - @POST - public Response createCollectionObject(CollectionObject co) { - - String csid = null; - try { - - Document document = service.postCollectionObject(co); - Element root = document.getRootElement(); - for (Iterator i = root.elementIterator(); i.hasNext();) { - Element element = (Element) i.next(); - if ("docRef".equals(element.getName())) { - csid = (String) element.getData(); - co.setCsid(csid); - } - } - } catch (Exception e) { - Response response = Response.status(Response.Status.NOT_FOUND) - .entity("Create failed").type("text/plain").build(); - throw new WebApplicationException(response); - } - - verbose("createCollectionObject: ", co); - UriBuilder path = UriBuilder - .fromResource(CollectionObjectResource.class); - path.path("" + csid); - Response response = Response.created(path.build()).build(); - - return response; - } - - @GET - @Path("{csid}") - public CollectionObject getCollectionObject(@PathParam("csid") String csid) { - - CollectionObject co = null; - try { - Document document = service.getCollectionObject(csid); - Element root = document.getRootElement(); - co = new CollectionObject(); - - // TODO: recognize schema thru namespace uri - // Namespace ns = new Namespace("collectionobject", - // "http://collectionspace.org/collectionobject"); - - Iterator siter = root.elementIterator("schema"); - while (siter.hasNext()) { - - Element schemaElement = siter.next(); - System.err - .println("CollectionObject.getCollectionObject() called."); - - // TODO: recognize schema thru namespace uri - if (CollectionObjectService.CO_SCHEMA_NAME.equals(schemaElement.attribute("name") - .getValue())) { - Element ele = schemaElement - .element(CollectionObjectJAXBSchema.OBJECT_NUMBER); - if (ele != null) { - co.setObjectNumber((String) ele.getData()); - } - ele = schemaElement - .element(CollectionObjectJAXBSchema.OTHER_NUMBER); - if (ele != null) { - co.setOtherNumber((String) ele.getData()); - } - ele = schemaElement - .element(CollectionObjectJAXBSchema.BRIEF_DESCRIPTION); - if (ele != null) { - co.setBriefDescription((String) ele.getData()); - } - ele = schemaElement - .element(CollectionObjectJAXBSchema.COMMENTS); - if (ele != null) { - co.setComments((String) ele.getData()); - } - ele = schemaElement - .element(CollectionObjectJAXBSchema.DIST_FEATURES); - if (ele != null) { - co.setDistFeatures((String) ele.getData()); - } - ele = schemaElement - .element(CollectionObjectJAXBSchema.OBJECT_NAME); - if (ele != null) { - co.setObjectName((String) ele.getData()); - } - ele = schemaElement - .element(CollectionObjectJAXBSchema.RESPONSIBLE_DEPT); - if (ele != null) { - co.setResponsibleDept((String) ele.getData()); - } - ele = schemaElement - .element(CollectionObjectJAXBSchema.TITLE); - if (ele != null) { - co.setTitle((String) ele.getData()); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - Response response = Response.status( - Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed") - .type("text/plain").build(); - throw new WebApplicationException(response); - } - if (co == null) { - Response response = Response.status(Response.Status.NOT_FOUND) - .entity( - "Get failed, the requested CollectionObject CSID:" - + csid + ": was not found.").type( - "text/plain").build(); - throw new WebApplicationException(response); - } - verbose("getCollectionObject: ", co); - - return co; - } - - @PUT - @Path("{csid}") - public CollectionObject updateCollectionObject( - @PathParam("csid") String csid, CollectionObject theUpdate) { - - verbose("updateCollectionObject with input: ", theUpdate); - - String status = null; - try { - - Document document = service.putCollectionObject(csid, theUpdate); - Element root = document.getRootElement(); - for (Iterator i = root.elementIterator(); i.hasNext();) { - Element element = (Element) i.next(); - if ("docRef".equals(element.getName())) { - status = (String) element.getData(); - verbose("updateCollectionObject response: " + status); - } - } - } catch (Exception e) { - // FIXME: NOT_FOUND? - Response response = Response.status(Response.Status.NOT_FOUND) - .entity("Update failed ").type("text/plain").build(); - throw new WebApplicationException(response); - } - - return theUpdate; - } - - @DELETE - @Path("{csid}") - public void deleteCollectionObject(@PathParam("csid") String csid) { - - verbose("deleteCollectionObject with csid=" + csid); - try { - - Document document = service.deleteCollectionObject(csid); - Element root = document.getRootElement(); - for (Iterator i = root.elementIterator(); i.hasNext();) { - Element element = (Element) i.next(); - if ("docRef".equals(element.getName())) { - String status = (String) element.getData(); - verbose("deleteCollectionObjectt response: " + status); - } - } - } catch (Exception e) { - // FIXME: NOT_FOUND? - Response response = Response.status(Response.Status.NOT_FOUND) - .entity("Delete failed ").type("text/plain").build(); - throw new WebApplicationException(response); - } - - } - - private void verbose(String msg, CollectionObject co) { - try { - verbose(msg); - JAXBContext jc = JAXBContext.newInstance(CollectionObject.class); - - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - m.marshal(co, System.out); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void verbose(String msg) { - System.out.println("CollectionObjectResource. " + msg); - } - -} diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java new file mode 100644 index 000000000..25daff72b --- /dev/null +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectResource.java @@ -0,0 +1,243 @@ +package org.collectionspace.services.collectionobject; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.PathParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; + +import org.collectionspace.services.collectionobject.CollectionObjectList.*; + +import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectConstants; +import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectHandlerFactory; +import org.collectionspace.services.common.NuxeoClientType; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.repository.DocumentNotFoundException; +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.RepositoryClient; +import org.collectionspace.services.common.repository.RepositoryClientFactory; +import org.jboss.resteasy.util.HttpResponseCodes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Path("/collectionobjects") +@Consumes("application/xml") +@Produces("application/xml") +public class CollectionObjectResource { + + public final static String CO_SERVICE_NAME = "collectionobjects"; + final Logger logger = LoggerFactory.getLogger(CollectionObjectResource.class); + //FIXME retrieve client type from configuration + final static NuxeoClientType CLIENT_TYPE = ServiceMain.getInstance().getNuxeoClientType(); + + public CollectionObjectResource() { + // do nothing + } + + @POST + public Response createCollectionObject( + CollectionObject co) { + + String csid = null; + try{ + RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); + RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); + CollectionObjectHandlerFactory handlerFactory = CollectionObjectHandlerFactory.getInstance(); + DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); + handler.setCommonObject(co); + csid = client.create(CO_SERVICE_NAME, CollectionObjectConstants.CO_NUXEO_DOCTYPE, handler); + co.setCsid(csid); + if(logger.isDebugEnabled()){ + verbose("createCollectionObject: ", co); + } + UriBuilder path = UriBuilder.fromResource(CollectionObjectResource.class); + path.path("" + csid); + Response response = Response.created(path.build()).build(); + return response; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception in createCollectionObject", e); + } + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Crate failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + } + + @GET + @Path("{csid}") + public CollectionObject getCollectionObject( + @PathParam("csid") String csid) { + if(logger.isDebugEnabled()){ + verbose("getCollectionObject with csid=" + csid); + } + if(csid == null || "".equals(csid)){ + logger.error("getCollectionObject: missing csid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "get failed on CollectionObject csid=" + csid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + CollectionObject co = null; + try{ + RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); + RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); + CollectionObjectHandlerFactory handlerFactory = CollectionObjectHandlerFactory.getInstance(); + DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); + client.get(csid, handler); + co = (CollectionObject) handler.getCommonObject(); + }catch(DocumentNotFoundException dnfe){ + if(logger.isDebugEnabled()){ + logger.debug("getCollectionObject", dnfe); + } + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Get failed on CollectionObject csid=" + csid).type( + "text/plain").build(); + throw new WebApplicationException(response); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("getCollectionObject", e); + } + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + + if(co == null){ + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Get failed, the requested CollectionObject CSID:" + csid + ": was not found.").type( + "text/plain").build(); + throw new WebApplicationException(response); + } + if(logger.isDebugEnabled()){ + verbose("getCollectionObject: ", co); + } + return co; + } + + @GET + public CollectionObjectList getCollectionObjectList(@Context UriInfo ui) { + CollectionObjectList coList = new CollectionObjectList(); + try{ + RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); + RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); + CollectionObjectHandlerFactory handlerFactory = CollectionObjectHandlerFactory.getInstance(); + DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); + client.getAll(CO_SERVICE_NAME, handler); + coList = (CollectionObjectList) handler.getCommonObjectList(); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception in getCollectionObjectList", e); + } + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("index failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + return coList; + } + + @PUT + @Path("{csid}") + public CollectionObject updateCollectionObject( + @PathParam("csid") String csid, + CollectionObject theUpdate) { + if(logger.isDebugEnabled()){ + verbose("updateCollectionObject with csid=" + csid); + } + if(csid == null || "".equals(csid)){ + logger.error("updateCollectionObject: missing csid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "update failed on CollectionObject csid=" + csid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + if(logger.isDebugEnabled()){ + verbose("updateCollectionObject with input: ", theUpdate); + } + try{ + RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); + RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); + CollectionObjectHandlerFactory handlerFactory = CollectionObjectHandlerFactory.getInstance(); + DocumentHandler handler = (DocumentHandler) handlerFactory.getHandler(CLIENT_TYPE.toString()); + handler.setCommonObject(theUpdate); + client.update(csid, handler); + }catch(DocumentNotFoundException dnfe){ + if(logger.isDebugEnabled()){ + logger.debug("caugth exception in updateCollectionObject", dnfe); + } + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Update failed on CollectionObject csid=" + csid).type( + "text/plain").build(); + throw new WebApplicationException(response); + }catch(Exception e){ + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + return theUpdate; + } + + @DELETE + @Path("{csid}") + public Response deleteCollectionObject(@PathParam("csid") String csid) { + + if(logger.isDebugEnabled()){ + verbose("deleteCollectionObject with csid=" + csid); + } + if(csid == null || "".equals(csid)){ + logger.error("deleteCollectionObject: missing csid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "delete failed on CollectionObject csid=" + csid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + try{ + RepositoryClientFactory clientFactory = RepositoryClientFactory.getInstance(); + RepositoryClient client = clientFactory.getClient(CLIENT_TYPE.toString()); + client.delete(csid); + return Response.status(HttpResponseCodes.SC_OK).build(); + }catch(DocumentNotFoundException dnfe){ + if(logger.isDebugEnabled()){ + logger.debug("caught exception in deleteCollectionObject", dnfe); + } + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Delete failed on CollectionObject csid=" + csid).type( + "text/plain").build(); + throw new WebApplicationException(response); + }catch(Exception e){ + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + + } + + private void verbose(String msg, CollectionObject co) { + try{ + verbose(msg); + JAXBContext jc = JAXBContext.newInstance( + CollectionObject.class); + + Marshaller m = jc.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + m.marshal(co, System.out); + }catch(Exception e){ + e.printStackTrace(); + } + + } + + private void verbose(String msg) { + System.out.println("CollectionObjectResource. " + msg); + } +} diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectService.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectService.java similarity index 90% rename from services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectService.java rename to services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectService.java index 785302bfb..a08b6289d 100644 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectService.java +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/CollectionObjectService.java @@ -1,7 +1,7 @@ /** * */ -package org.collectionspace.services; +package org.collectionspace.services.collectionobject; import java.io.IOException; import org.dom4j.Document; diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectConstants.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectConstants.java new file mode 100644 index 000000000..9911f4244 --- /dev/null +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectConstants.java @@ -0,0 +1,36 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.collectionobject.nuxeo; + +/** + * CollectionObjectConstants processes CollectionObject document + * + */ +public class CollectionObjectConstants { + + public final static String CO_NUXEO_DOCTYPE = "CollectionObject"; + public final static String CO_NUXEO_SCHEMA_NAME = "collectionobject"; + public final static String CO_NUXEO_DC_TITLE = "CollectionSpace-CollectionObject"; + +} diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectDocumentModelHandler.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectDocumentModelHandler.java new file mode 100644 index 000000000..80d631408 --- /dev/null +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectDocumentModelHandler.java @@ -0,0 +1,290 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.collectionobject.nuxeo; + +import java.util.Iterator; +import java.util.List; +import org.collectionspace.services.CollectionObjectJAXBSchema; +import org.collectionspace.services.collectionobject.CollectionObject; +import org.collectionspace.services.collectionobject.CollectionObjectList; +import org.collectionspace.services.collectionobject.CollectionObjectList.CollectionObjectListItem; +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler; +import org.nuxeo.ecm.core.api.DocumentModel; +import org.nuxeo.ecm.core.api.DocumentModelList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * CollectionObjectDocumentModelHandler + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class CollectionObjectDocumentModelHandler + extends DocumentModelHandler { + + private final Logger logger = LoggerFactory.getLogger(CollectionObjectDocumentModelHandler.class); + /** + * collectionObject is used to stash JAXB object to use when handle is called + * for Action.CREATE, Action.UPDATE or Action.GET + */ + private CollectionObject collectionObject; + /** + * collectionObjectList is stashed when handle is called + * for ACTION.GET_ALL + */ + private CollectionObjectList collectionObjectList; + + @Override + public void prepare(Action action) throws Exception { + //no specific action needed + } + + @Override + public void handle(Action action, DocumentWrapper wrapDoc) throws Exception { + switch(action){ + case CREATE: + handleCreate(wrapDoc); + break; + case UPDATE: + handleUpdate(wrapDoc); + break; + case GET: + handleGet(wrapDoc); + break; + case GET_ALL: + handleGetAll(wrapDoc); + break; + } + } + + /** + * handleCreate processes create operation response + * @param wrapDoc + * @throws Exception + */ + public void handleCreate(DocumentWrapper wrapDoc) throws Exception { + CollectionObject co = getCommonObject(); + if(co == null){ + String msg = "Error creating document: Missing input data"; + logger.error(msg); + throw new IllegalStateException(msg); + } + //FIXME set other parts as well + fillCommonObject(co, wrapDoc); + } + + /** + * handleUpdate processes update operation response + * @param wrapDoc + * @throws Exception + */ + public void handleUpdate(DocumentWrapper wrapDoc) throws Exception { + CollectionObject co = getCommonObject(); + if(co == null){ + String msg = "Error updating document: Missing input data"; + logger.error(msg); + throw new IllegalStateException(msg); + } + //FIXME set other parts as well + fillCommonObject(co, wrapDoc); + } + + /** + * handleGet processes get operation response + * @param wrapDoc + * @throws Exception + */ + public void handleGet(DocumentWrapper wrapDoc) throws Exception { + CollectionObject co = extractCommonObject(wrapDoc); + setCommonObject(co); + + //FIXME retrive other parts as well + } + + /** + * handleGetAll processes index operation response + * @param wrapDoc + * @throws Exception + */ + public void handleGetAll(DocumentWrapper wrapDoc) throws Exception { + CollectionObjectList coList = extractCommonObjectList(wrapDoc); + //FIXME, this is unncessarily called on each call from client + setCommonObjectList(coList); + } + + /** + * getCommonObject get associated CollectionObject + * @return + */ + @Override + public CollectionObject getCommonObject() { + return collectionObject; + } + + /** + * setCommonObject set associated collectionobject + * @param collectionObject + */ + @Override + public void setCommonObject(CollectionObject collectionObject) { + this.collectionObject = collectionObject; + } + + /** + * getCollectionObjectList get associated CollectionObject (for index/GET_ALL) + * @return + */ + @Override + public CollectionObjectList getCommonObjectList() { + return collectionObjectList; + } + + @Override + public void setCommonObjectList(CollectionObjectList collectionObjectList) { + this.collectionObjectList = collectionObjectList; + } + + @Override + public CollectionObject extractCommonObject(DocumentWrapper wrapDoc) + throws Exception { + DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); + CollectionObject co = new CollectionObject(); + + //FIXME property get should be dynamically set using schema inspection + //so it does not require hard coding + + // CollectionObject core values + co.setObjectNumber((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.OBJECT_NUMBER))); + co.setOtherNumber((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.OTHER_NUMBER))); + co.setBriefDescription((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.BRIEF_DESCRIPTION))); + co.setComments((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.COMMENTS))); + co.setDistFeatures((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.DIST_FEATURES))); + co.setObjectName((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.OBJECT_NAME))); + co.setResponsibleDept((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.RESPONSIBLE_DEPT))); + co.setTitle((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.TITLE))); + + return co; + } + + @Override + public void fillCommonObject(CollectionObject co, DocumentWrapper wrapDoc) throws Exception { + DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); + //FIXME property setter should be dynamically set using schema inspection + //so it does not require hard coding + + // a default title for the Dublin Core schema + docModel.setPropertyValue("dublincore:title", CollectionObjectConstants.CO_NUXEO_DC_TITLE); + + // CollectionObject core values + if(co.getObjectNumber() != null){ + docModel.setPropertyValue( + getQProperty(CollectionObjectJAXBSchema.OBJECT_NUMBER), + co.getObjectNumber()); + } + if(co.getOtherNumber() != null){ + docModel.setPropertyValue( + getQProperty(CollectionObjectJAXBSchema.OTHER_NUMBER), + co.getOtherNumber()); + } + if(co.getBriefDescription() != null){ + docModel.setPropertyValue( + getQProperty(CollectionObjectJAXBSchema.BRIEF_DESCRIPTION), + co.getBriefDescription()); + } + if(co.getComments() != null){ + docModel.setPropertyValue( + getQProperty(CollectionObjectJAXBSchema.COMMENTS), + co.getComments()); + } + if(co.getDistFeatures() != null){ + docModel.setPropertyValue( + getQProperty(CollectionObjectJAXBSchema.DIST_FEATURES), + co.getDistFeatures()); + } + if(co.getObjectName() != null){ + docModel.setPropertyValue( + getQProperty(CollectionObjectJAXBSchema.OBJECT_NAME), + co.getObjectName()); + } + if(co.getResponsibleDept() != null){ + docModel.setPropertyValue( + getQProperty(CollectionObjectJAXBSchema.RESPONSIBLE_DEPT), + co.getResponsibleDept()); + } + if(co.getTitle() != null){ + docModel.setPropertyValue( + getQProperty(CollectionObjectJAXBSchema.TITLE), + co.getTitle()); + } + } + + @Override + public CollectionObjectList extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception { + DocumentModelList docList = (DocumentModelList) wrapDoc.getWrappedObject(); + + CollectionObjectList coList = new CollectionObjectList(); + List list = coList.getCollectionObjectListItem(); + + //FIXME: iterating over a long list of documents is not a long term + //strategy...need to change to more efficient iterating in future + Iterator iter = docList.iterator(); + while(iter.hasNext()){ + DocumentModel docModel = iter.next(); + CollectionObjectListItem coListItem = new CollectionObjectListItem(); + coListItem.setObjectNumber((String) docModel.getPropertyValue( + getQProperty(CollectionObjectJAXBSchema.OBJECT_NUMBER))); + //need fully qualified context for URI + coListItem.setUri("/collectionobjects/" + docModel.getId()); + coListItem.setCsid(docModel.getId()); + list.add(coListItem); + } + + return coList; + } + + @Override + public void fillCommonObjectList(CollectionObjectList obj, DocumentWrapper wrapDoc) throws Exception { + throw new UnsupportedOperationException(); + } + + /** + * getQProperty converts the given property to qualified schema property + * @param prop + * @return + */ + private String getQProperty(String prop) { + return CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + ":" + prop; + } +} + diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectHandlerFactory.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectHandlerFactory.java new file mode 100644 index 000000000..bcaa606b1 --- /dev/null +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectHandlerFactory.java @@ -0,0 +1,55 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.collectionobject.nuxeo; + +import org.collectionspace.services.common.NuxeoClientType; +import org.collectionspace.services.common.repository.DocumentHandler; + +/** + * CollectionObjectHandlerFactory creates handlers for collectionobject based + * on type of Nuxeo client used + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class CollectionObjectHandlerFactory { + + private static final CollectionObjectHandlerFactory self = new CollectionObjectHandlerFactory(); + + private CollectionObjectHandlerFactory() { + } + + public static CollectionObjectHandlerFactory getInstance() { + return self; + } + + public DocumentHandler getHandler(String clientType) { + if(NuxeoClientType.JAVA.toString().equals(clientType)){ + return new CollectionObjectDocumentModelHandler(); + } else if(NuxeoClientType.REST.toString().equals(clientType)) { + return new CollectionObjectRepresenationHandler(); + } + throw new IllegalArgumentException("Not supported client=" + clientType); + } +} diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectRepresenationHandler.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectRepresenationHandler.java new file mode 100644 index 000000000..dd58dfcf2 --- /dev/null +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectRepresenationHandler.java @@ -0,0 +1,319 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.collectionobject.nuxeo; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.collectionspace.services.CollectionObjectJAXBSchema; +import org.collectionspace.services.collectionobject.CollectionObject; +import org.collectionspace.services.collectionobject.CollectionObjectList; +import org.collectionspace.services.collectionobject.CollectionObjectList.CollectionObjectListItem; +import org.collectionspace.services.collectionobject.CollectionObjectService; +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.collectionspace.services.nuxeo.client.rest.RepresentationHandler; +import org.dom4j.Document; +import org.dom4j.Element; +import org.nuxeo.ecm.core.api.DocumentModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * CollectionObjectDocumentModelHandler + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class CollectionObjectRepresenationHandler + extends RepresentationHandler +{ + + private final Logger logger = LoggerFactory.getLogger(CollectionObjectRepresenationHandler.class); + /** + * collectionObject is used to stash JAXB object to use when handle is called + * for Action.CREATE, Action.UPDATE or Action.GET + */ + private CollectionObject collectionObject; + /** + * collectionObjectList is stashed when handle is called + * for ACTION.GET_ALL + */ + private CollectionObjectList collectionObjectList; + + @Override + public void prepare(Action action) throws Exception { + switch(action){ + case CREATE: + case UPDATE: + prepare(); + } + } + + @Override + public void handle(Action action, DocumentWrapper wrapDoc) + throws Exception { + switch(action){ + case CREATE: + handleCreate(wrapDoc); + break; + case UPDATE: + handleUpdate(wrapDoc); + break; + case GET: + handleGet(wrapDoc); + break; + case GET_ALL: + handleGetAll(wrapDoc); + break; + } + } + + /** + * handleCreate processes create operation response + * @param wrapDoc + * @throws Exception + */ + public void handleCreate(DocumentWrapper wrapDoc) throws Exception { + CollectionObject co = getCommonObject(); + if(co == null){ + String msg = "Error creating document: Missing input data"; + logger.error(msg); + throw new IllegalStateException(msg); + } + //FIXME set other parts as well + fillCommonObject(co, wrapDoc); + } + + /** + * handleUpdate processes update operation response + * @param wrapDoc + * @throws Exception + */ + public void handleUpdate(DocumentWrapper wrapDoc) throws Exception { + CollectionObject co = getCommonObject(); + if(co == null){ + String msg = "Error updating document: Missing input data"; + logger.error(msg); + throw new IllegalStateException(msg); + } + //FIXME set other parts as well + fillCommonObject(co, wrapDoc); + } + + /** + * handleGet processes get operation response + * @param wrapDoc + * @throws Exception + */ + public void handleGet(DocumentWrapper wrapDoc) throws Exception { + CollectionObject co = extractCommonObject(wrapDoc); + setCommonObject(co); + //FIXME retrive other parts as well + } + + /** + * handleGetAll processes index operation response + * @param wrapDoc + * @throws Exception + */ + public void handleGetAll(DocumentWrapper wrapDoc) throws Exception { + CollectionObjectList coList = extractCommonObjectList(wrapDoc); + setCommonObjectList(coList); + } + + private void prepare() { + Map queryParams = getQueryParams(); + CollectionObject co = getCommonObject(); + // todo: intelligent merge needed + if(co.getObjectNumber() != null){ + queryParams.put(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + + ":" + CollectionObjectJAXBSchema.OBJECT_NUMBER, co.getObjectNumber()); + } + + if(co.getOtherNumber() != null){ + queryParams.put(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + + ":" + CollectionObjectJAXBSchema.OTHER_NUMBER, co.getOtherNumber()); + } + + if(co.getBriefDescription() != null){ + queryParams.put(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + + ":" + CollectionObjectJAXBSchema.BRIEF_DESCRIPTION, co.getBriefDescription()); + } + + if(co.getComments() != null){ + queryParams.put(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + + ":" + CollectionObjectJAXBSchema.COMMENTS, co.getComments()); + } + + if(co.getDistFeatures() != null){ + queryParams.put(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + + ":" + CollectionObjectJAXBSchema.DIST_FEATURES, co.getDistFeatures()); + } + + if(co.getObjectName() != null){ + queryParams.put(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + + ":" + CollectionObjectJAXBSchema.OBJECT_NAME, co.getObjectName()); + } + + if(co.getResponsibleDept() != null){ + queryParams.put(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + + ":" + CollectionObjectJAXBSchema.RESPONSIBLE_DEPT, co.getResponsibleDept()); + } + + if(co.getTitle() != null){ + queryParams.put(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + + ":" + CollectionObjectJAXBSchema.TITLE, co.getTitle()); + } + } + + @Override + public CollectionObject extractCommonObject(DocumentWrapper wrapDoc) + throws Exception { + Document document = (Document) wrapDoc.getWrappedObject(); + CollectionObject co = new CollectionObject(); + + //FIXME property get should be dynamically set using schema inspection + //so it does not require hard coding + Element root = document.getRootElement(); + + // TODO: recognize schema thru namespace uri + // Namespace ns = new Namespace("collectionobject", + // "http://collectionspace.org/collectionobject"); + + Iterator siter = root.elementIterator("schema"); + while(siter.hasNext()){ + + Element schemaElement = siter.next(); + if(logger.isDebugEnabled()){ + logger.debug("getCommonObject() populating Common Object"); + } + // TODO: recognize schema thru namespace uri + if(CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME.equals(schemaElement.attribute("name").getValue())){ + Element ele = schemaElement.element(CollectionObjectJAXBSchema.OBJECT_NUMBER); + if(ele != null){ + co.setObjectNumber((String) ele.getData()); + } + ele = schemaElement.element(CollectionObjectJAXBSchema.OTHER_NUMBER); + if(ele != null){ + co.setOtherNumber((String) ele.getData()); + } + ele = schemaElement.element(CollectionObjectJAXBSchema.BRIEF_DESCRIPTION); + if(ele != null){ + co.setBriefDescription((String) ele.getData()); + } + ele = schemaElement.element(CollectionObjectJAXBSchema.COMMENTS); + if(ele != null){ + co.setComments((String) ele.getData()); + } + ele = schemaElement.element(CollectionObjectJAXBSchema.DIST_FEATURES); + if(ele != null){ + co.setDistFeatures((String) ele.getData()); + } + ele = schemaElement.element(CollectionObjectJAXBSchema.OBJECT_NAME); + if(ele != null){ + co.setObjectName((String) ele.getData()); + } + ele = schemaElement.element(CollectionObjectJAXBSchema.RESPONSIBLE_DEPT); + if(ele != null){ + co.setResponsibleDept((String) ele.getData()); + } + ele = schemaElement.element(CollectionObjectJAXBSchema.TITLE); + if(ele != null){ + co.setTitle((String) ele.getData()); + } + } + } + return co; + } + + @Override + public void fillCommonObject(CollectionObject co, DocumentWrapper wrapDoc) + throws Exception { + //Nuxeo REST takes create/update through queryParams, nothing to do here + } + + @Override + public CollectionObjectList extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception { + Document document = (Document) wrapDoc.getWrappedObject(); + // debug + if(logger.isDebugEnabled()){ + logger.debug(document.asXML()); + } + CollectionObjectList coList = new CollectionObjectList(); + List list = coList.getCollectionObjectListItem(); + Element root = document.getRootElement(); + for(Iterator i = root.elementIterator(); i.hasNext();){ + + Element element = (Element) i.next(); + if(logger.isDebugEnabled()){ + logger.debug(element.asXML()); + } + // set the CollectionObject list item entity elements + CollectionObjectListItem coListItem = new CollectionObjectListItem(); + coListItem.setObjectNumber(element.attributeValue("title")); + String id = element.attributeValue("id"); + coListItem.setCsid(id); + coListItem.setUri("/collectionobjects/" + id); + + list.add(coListItem); + } + return coList; + } + + @Override + public void fillCommonObjectList(CollectionObjectList obj, DocumentWrapper wrapDoc) + throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public CollectionObject getCommonObject() { + return collectionObject; + } + + @Override + public void setCommonObject(CollectionObject obj) { + this.collectionObject = obj; + } + + @Override + public CollectionObjectList getCommonObjectList() { + return collectionObjectList; + } + + @Override + public void setCommonObjectList(CollectionObjectList obj) { + this.collectionObjectList = obj; + } + + /** + * getQProperty converts the given property to qualified schema property + * @param prop + * @return + */ + private String getQProperty(String prop) { + return CollectionObjectConstants.CO_NUXEO_SCHEMA_NAME + ":" + prop; + } +} + diff --git a/services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectServiceNuxeoImpl.java b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectServiceNuxeoImpl.java similarity index 85% rename from services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectServiceNuxeoImpl.java rename to services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectServiceNuxeoImpl.java index fe863707f..d0d8a9760 100644 --- a/services/collectionobject/service/src/main/java/org/collectionspace/services/CollectionObjectServiceNuxeoImpl.java +++ b/services/collectionobject/service/src/main/java/org/collectionspace/services/collectionobject/nuxeo/CollectionObjectServiceNuxeoImpl.java @@ -1,8 +1,10 @@ /** * */ -package org.collectionspace.services; +package org.collectionspace.services.collectionobject.nuxeo; +import org.collectionspace.services.collectionobject.CollectionObjectService; +import org.collectionspace.services.*; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; @@ -11,11 +13,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.collectionspace.services.nuxeo.NuxeoRESTClient; +import org.collectionspace.services.nuxeo.client.rest.NuxeoRESTClient; import org.collectionspace.services.nuxeo.CollectionSpaceServiceNuxeoImpl; import org.collectionspace.services.collectionobject.CollectionObject; import org.collectionspace.services.CollectionObjectJAXBSchema; -import org.collectionspace.services.nuxeo.NuxeoUtils; +import org.collectionspace.services.nuxeo.util.NuxeoUtils; import org.dom4j.Document; import org.dom4j.DocumentException; @@ -84,35 +86,7 @@ public class CollectionObjectServiceNuxeoImpl extends return document; } - /* - * Prototype method for calling the Nuxeo Java API - */ - private Document getCollectionObjectViaJavaAPI(String csid) - throws DocumentException, IOException { - Document result = null; - RepositoryInstance repoSession = null; - - try { - repoSession = getRepositorySession(); - DocumentRef documentRef = new IdRef(csid); - DocumentModel documentModel = repoSession.getDocument(documentRef); - result = NuxeoUtils.getDocument(repoSession, documentModel); - } catch (Exception e) { - if (logger.isDebugEnabled()) { - e.printStackTrace(); - } - } finally { - if (repoSession != null) { - releaseRepositorySession(repoSession); - } - } - - // Dump out the contents of the result to stdout - System.out.println(result.asXML()); - - return result; - } - + public Document getCollectionObjectList() throws DocumentException, IOException { Document result = null; diff --git a/services/common/src/main/config/service-config.xml b/services/common/src/main/config/service-config.xml index 614d01ad3..6085d4a8d 100644 --- a/services/common/src/main/config/service-config.xml +++ b/services/common/src/main/config/service-config.xml @@ -15,7 +15,9 @@ 127.0.0.1 - 62474 + 62474 + + java Administrator Administrator @@ -23,15 +25,21 @@ persons People + + - + collectionobjects CollectionObjects + + intakes Intakes - + + + diff --git a/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java b/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java index c55a2f71e..75c6efc4e 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java +++ b/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java @@ -10,7 +10,7 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import org.collectionspace.services.common.ServiceConfig.NuxeoWorkspace; import org.collectionspace.services.common.ServiceConfig.NuxeoWorkspace.Workspace; -import org.collectionspace.services.nuxeo.NuxeoConnector; +import org.collectionspace.services.nuxeo.client.java.NuxeoConnector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,6 +30,7 @@ public class ServiceMain { private Hashtable serviceWorkspaces = new Hashtable(); private NuxeoConnector nuxeoConnector; private String serverRootDir = null; + private NuxeoClientType nuxeoClientType = null; private ServiceMain() { } @@ -64,8 +65,10 @@ public class ServiceMain { private void initialize() throws Exception { setServerRootDir(); serviceConfig = readConfig(); - nuxeoConnector = NuxeoConnector.getInstance(); - nuxeoConnector.initialize(serviceConfig.getNuxeoClientConfig()); + if(getNuxeoClientType().equals(NuxeoClientType.JAVA)){ + nuxeoConnector = NuxeoConnector.getInstance(); + nuxeoConnector.initialize(serviceConfig.getNuxeoClientConfig()); + } } /** @@ -81,7 +84,7 @@ public class ServiceMain { instance = null; }catch(Exception e){ e.printStackTrace(); - //gobble it + //gobble it } } @@ -102,20 +105,39 @@ public class ServiceMain { if(logger.isDebugEnabled()){ logger.debug("readConfig() read config file " + configFile.getAbsolutePath()); } + nuxeoClientType = sconfig.getNuxeoClientConfig().getClientType(); + if(logger.isDebugEnabled()) { + logger.debug("using Nuxeo client=" + nuxeoClientType.toString()); + } return sconfig; } synchronized public void getWorkspaceIds() throws Exception { - Hashtable workspaceIds = nuxeoConnector.retrieveWorkspaceIds(); + Hashtable workspaceIds = new Hashtable(); + + if(getNuxeoClientType().equals(NuxeoClientType.JAVA)){ + workspaceIds = nuxeoConnector.retrieveWorkspaceIds(); + } NuxeoWorkspace nuxeoWorkspace = serviceConfig.getNuxeoWorkspace(); List workspaces = nuxeoWorkspace.getWorkspace(); + String workspaceId = null; for(Workspace workspace : workspaces){ - String workspaceId = workspaceIds.get(workspace.getWorkspaceName().toLowerCase()); - if(workspaceId == null){ - logger.error("failed to retrieve workspace id for " + workspace.getWorkspaceName()); - //FIXME: should we throw an exception here? - continue; + if(getNuxeoClientType().equals(NuxeoClientType.JAVA)){ + workspaceId = workspaceIds.get(workspace.getWorkspaceName().toLowerCase()); + if(workspaceId == null){ + logger.warn("failed to retrieve workspace id for " + workspace.getWorkspaceName()); + //FIXME: should we throw an exception here? + continue; + } + }else{ + workspaceId = workspace.getWorkspaceId(); + if(workspaceId == null || "".equals(workspaceId)){ + logger.error("could not find workspace id for " + workspace.getWorkspaceName()); + //FIXME: should we throw an exception here? + continue; + } } + serviceWorkspaces.put(workspace.getServiceName(), workspaceId); if(logger.isDebugEnabled()){ logger.debug("retrieved workspace id=" + workspaceId + @@ -156,4 +178,11 @@ public class ServiceMain { public String getServerRootDir() { return serverRootDir; } + + /** + * @return the nuxeoClientType + */ + public NuxeoClientType getNuxeoClientType() { + return nuxeoClientType; + } } diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/BadRequestException.java b/services/common/src/main/java/org/collectionspace/services/common/repository/BadRequestException.java new file mode 100644 index 000000000..af31a438f --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/BadRequestException.java @@ -0,0 +1,84 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.collectionspace.services.common.repository; + +/** + * BadRequestException + * + */ +public class BadRequestException extends Exception { + + /** + * Creates a new instance of BadRequestException without detail message. + */ + public BadRequestException() { + } + + + /** + * Constructs an instance of BadRequestException with the specified detail message. + * @param msg the detail message. + */ + public BadRequestException(String msg) { + super(msg); + } + + + /** + * Constructs a new exception with the specified detail message and + * cause.

Note that the detail message associated with + * cause is not automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public BadRequestException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail + * message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of cause). + * This constructor is useful for exceptions that are little more than + * wrappers for other throwables (for example, {@link + * java.security.PrivilegedActionException}). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public BadRequestException(Throwable cause) { + super(cause); + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentException.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentException.java new file mode 100644 index 000000000..39043b068 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentException.java @@ -0,0 +1,106 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ + +package org.collectionspace.services.common.repository; + +/** + * DocumentException + * Nuxeo document handling exception + */ +public class DocumentException extends Exception { + + /** + * collectionspace specific error code + */ + private int errorCode; + + /** + * Creates a new instance of DocumentException without detail message. + */ + public DocumentException() { + } + + /** + * Constructs an instance of DocumentException with the specified detail message. + * @param msg the detail message. + */ + public DocumentException(String msg) { + super(msg); + } + + + /** + * DocumentException with application specific code and message + * @param code + * @param msg + */ + public DocumentException(int code, String msg) { + super(msg); + this.errorCode = code; + } + /** + * Constructs a new exception with the specified detail message and + * cause.

Note that the detail message associated with + * cause is not automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public DocumentException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail + * message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of cause). + * This constructor is useful for exceptions that are little more than + * wrappers for other throwables (for example, {@link + * java.security.PrivilegedActionException}). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public DocumentException(Throwable cause) { + super(cause); + } + + + /** + * @return the collectionspace errorCode + */ + public int getErrorCode() { + return errorCode; + } + + /** + * @param errorCode the errorCode to set + */ + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentHandler.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentHandler.java new file mode 100644 index 000000000..1d92db6c1 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentHandler.java @@ -0,0 +1,141 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.common.repository; + +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.collectionspace.services.common.repository.DocumentException; +import java.util.Map; +import org.dom4j.Document; + +/** + * + * DocumentHandler provides document processing methods. It is an interface + * between Nuxeo repository client and CollectionSpace service resource. It provides + * methods to setup request via repository client and handle its response. + * + * Typical call sequence is: + * Create handler and repository client + * Call XXX operation on the repository client and pass the handler + * repository client calls prepare on the handler + * The repository client then calls handle on the handler + * + */ +public interface DocumentHandler { + + public enum Action { + + CREATE, GET, GET_ALL, UPDATE, DELETE + } + + /** + * prepare is called by the Nuxeo client to prepare required parameters to set + * before invoking repository operation. this is mainly useful for create and + * update kind of actions + * @param action + * @throws Exception + */ + public void prepare(Action action) throws Exception; + + /** + * handle is called by the Nuxeo client to hand over the document processing on create + * function to the CollectionSpace service + * @param action + * @param doc wrapped Nuxeo doc + * @throws Exception + */ + public void handle(Action action, DocumentWrapper docWrap) throws Exception; + + /** + * extractCommonObject extracts common part of a CS document from given Nuxeo document. + * @param docWrap nuxeo document + * @return common part of CS object + * @throws Exception + */ + public T extractCommonObject(DocumentWrapper docWrap) throws Exception; + + /** + * fillCommonObject sets common part of CS object into given Nuxeo document + * @param obj input object + * @param docWrap target Nuxeo document + * @throws Exception + */ + public void fillCommonObject(T obj, DocumentWrapper docWrap) throws Exception; + + /** + * extractCommonObject extracts common part of a CS document from given Nuxeo document. + * @param docWrap nuxeo document + * @return common part of CS object + * @throws Exception + */ + public TL extractCommonObjectList(DocumentWrapper docWrap) throws Exception; + + /** + * fillCommonObject sets common part of CS object into given Nuxeo document + * @param obj input object + * @param docWrap target Nuxeo document + * @throws Exception + */ + public void fillCommonObjectList(TL obj, DocumentWrapper docWrap) throws Exception; + + /** + * getCommonObject provides the common part of a CS document. + * @return common part of CS document + */ + public T getCommonObject(); + + /** + * setCommonObject sets common part of CS document as input for operation on + * Nuxeo repository + * @param obj input object + */ + public void setCommonObject(T obj); + + /** + * getCommonObjectList provides the default list object of a CS document. + * @return default list of CS document + */ + public TL getCommonObjectList(); + + /** + * setCommonObjectList sets default list object for CS document as input for operation on + * Nuxeo repository + * @param default list of CS document + */ + public void setCommonObjectList(TL obj); + + /** + * getDocument get org.dom4j.Document from given DocumentModel + * @param Nuxeo document wrapper + * @return + * @throws DocumentException + */ + public Document getDocument(DocumentWrapper docWrap) throws DocumentException; + + /** + * getProperties + * @return + */ + public Map getProperties(); + + /** + * setProperties provides means to the CollectionSpace service resource to + * set up parameters before invoking create request via the Nuxeo client. + * @param properties + */ + public void setProperties(Map properties); +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentNotFoundException.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentNotFoundException.java new file mode 100644 index 000000000..5cb6ac7fe --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentNotFoundException.java @@ -0,0 +1,78 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ + +package org.collectionspace.services.common.repository; + +/** + * DocumentNotFoundException + * + */ +public class DocumentNotFoundException extends DocumentException { + + /** + * Creates a new instance of DocumentNotFoundException without detail message. + */ + public DocumentNotFoundException() { + } + + + /** + * Constructs an instance of DocumentNotFoundException with the specified detail message. + * @param msg the detail message. + */ + public DocumentNotFoundException(String msg) { + super(msg); + } + + + /** + * Constructs a new exception with the specified detail message and + * cause.

Note that the detail message associated with + * cause is not automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public DocumentNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail + * message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of cause). + * This constructor is useful for exceptions that are little more than + * wrappers for other throwables (for example, {@link + * java.security.PrivilegedActionException}). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public DocumentNotFoundException(Throwable cause) { + super(cause); + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentWrapper.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentWrapper.java new file mode 100644 index 000000000..43743ce13 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentWrapper.java @@ -0,0 +1,40 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.collectionspace.services.common.repository; + +/** + * + * DocumentWrapper wraps DocumentModel (java) or Representation (REST) + * + */ +public interface DocumentWrapper { + + /** + * getWrappedObject + * @return wrapped object + */ + public Object getWrappedObject(); + +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClient.java b/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClient.java new file mode 100644 index 000000000..a5a7e8335 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClient.java @@ -0,0 +1,88 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.common.repository; + + +/** + * RepositoryClient is a generic Document Repository client + * + * Typical call sequence is: + * Create handler and repository client + * Call XXX operation on the repository client and pass the handler + * repository client calls prepare on the handler + * The repository client then calls handle on the handler + * + */ +public interface RepositoryClient { + + /** + * create document in the Document repository + * @param serviceName entity service for which document is created. for example + * this is used to find mapping + * to a Nuxeo workspace using service-config.xml + * @param docType of the document created + * @param handler should be used by the caller to provide and transform the document + * @return id in repository of the newly created document + * @throws BadRequestException data input is bad + * @throws DocumentException + */ + String create(String serviceName, String docType, DocumentHandler handler) throws BadRequestException, DocumentException; + + /** + * delete a document from the Document repository + * @param id of the document + * @throws DocumentNotFoundException if document not found + * @throws DocumentException + */ + void delete(String id) throws DocumentNotFoundException, DocumentException; + + /** + * get document from the Document repository + * @param id of the document to retrieve + * @param handler should be used by the caller to provide and transform the document + * @throws DocumentNotFoundException if document not found + * @throws DocumentException + */ + void get(String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; + + /** + * getAll get all documents for an entity entity service from the Document repository + * @param serviceName entity service for which documents are retrieved. this is used to find mapping + * to a Nuxeo workspace using service-config.xml + * @param handler should be used by the caller to provide and transform the document + * @throws DocumentNotFoundException if workspace not found + * @throws DocumentException + */ + void getAll(String serviceName, DocumentHandler handler) throws DocumentNotFoundException, DocumentException; + + /** + * update given document in the Document repository + * @param id of the document + * @param handler should be used by the caller to provide and transform the document + * @throws BadRequestException data input is bad + * @throws DocumentNotFoundException if document not found + * @throws DocumentException + */ + void update(String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException; +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClientFactory.java b/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClientFactory.java new file mode 100644 index 000000000..c14549322 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/RepositoryClientFactory.java @@ -0,0 +1,66 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.common.repository; + +import java.util.Hashtable; +import org.collectionspace.services.common.NuxeoClientType; + +/** + * RepositoryClientFactory is a singleton factory that provides required Nuxeo client + * it does not create clients as the clients are singletons + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class RepositoryClientFactory { + + + private static final RepositoryClientFactory self = new RepositoryClientFactory(); + private Hashtable clients = new Hashtable(); + + private RepositoryClientFactory() { + try{ + ClassLoader cloader = Thread.currentThread().getContextClassLoader(); + + Class jclazz = cloader.loadClass("org.collectionspace.services.nuxeo.client.java.RepositoryJavaClient"); + Object jclient = jclazz.newInstance(); + clients.put(NuxeoClientType.JAVA.toString(), (RepositoryClient) jclient); + + Class rclazz = cloader.loadClass("org.collectionspace.services.nuxeo.client.rest.RepositoryRESTClient"); + Object rclient = rclazz.newInstance(); + clients.put(NuxeoClientType.REST.toString(), (RepositoryClient) rclient); + + }catch(Exception e){ + throw new RuntimeException(e); + } + } + + public static RepositoryClientFactory getInstance() { + return self; + } + + public RepositoryClient getClient(String clientType) { + return clients.get(clientType); + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/CollectionSpaceServiceNuxeoImpl.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/CollectionSpaceServiceNuxeoImpl.java index 9b2318b9c..deb8112ce 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/CollectionSpaceServiceNuxeoImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/CollectionSpaceServiceNuxeoImpl.java @@ -3,8 +3,7 @@ */ package org.collectionspace.services.nuxeo; -import org.nuxeo.ecm.core.api.repository.RepositoryInstance; -import org.nuxeo.ecm.core.client.NuxeoClient; +import org.collectionspace.services.nuxeo.client.rest.NuxeoRESTClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,21 +28,4 @@ public abstract class CollectionSpaceServiceNuxeoImpl { return nxClient; } - protected RepositoryInstance getRepositorySession() throws Exception { - //FIXME: is it possible to reuse repository session? - //Authentication failures happen while trying to reuse the session - NuxeoConnector nuxeoConnector = NuxeoConnector.getInstance(); - return nuxeoConnector.getRepositorySession(); - } - - protected void releaseRepositorySession(RepositoryInstance repoSession) { - try{ - //release session - NuxeoConnector nuxeoConnector = NuxeoConnector.getInstance(); - nuxeoConnector.releaseRepositorySession(repoSession); - }catch(Exception e){ - logger.error("Could not close the repository session", e); - //no need to throw this service specific exception - } - } } diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoCallback.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoCallback.java deleted file mode 100644 index 6954ae55a..000000000 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoCallback.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - -package org.collectionspace.services.nuxeo; - - -import javax.security.auth.callback.Callback; - -/** - * Copied from jbossx - * - * An implementation of Callback that simply obtains an Object to be used - * as the authentication credential. Interpretation of the Object is up to - * the LoginModules that validate the credential. - * - * @author Scott.Stark@jboss.org - */ -public class NuxeoCallback implements Callback { - - private final String prompt; - - private Object credential; - - public NuxeoCallback() { - this(""); - } - - public NuxeoCallback(String prompt) { - this.prompt = prompt; - } - - public String getPrompt() { - return prompt; - } - - public Object getCredential() { - return credential; - } - - public void setCredential(Object credential) { - this.credential = credential; - } - - public void clearCredential() { - credential = null; - } - -} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoCallbackHandler.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoCallbackHandler.java deleted file mode 100644 index 565b64a5e..000000000 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoCallbackHandler.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.collectionspace.services.nuxeo; - -/** - * - * @author sanjaydalal - */ -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; - -/** - * Copied from jbossx. - * - * @author Scott.Stark@jboss.org - */ -public class NuxeoCallbackHandler implements CallbackHandler { - - private final String username; - private char[] password; - private final Object credential; - - /** - * Initializes the UsernamePasswordHandler with the username and password to - * use. - * - * @param username the user name - * @param password the password for this user - */ - public NuxeoCallbackHandler(String username, char[] password) { - this.username = username; - this.password = password; - credential = password; - } - - public NuxeoCallbackHandler(String username, Object credential) { - this.username = username; - this.credential = credential; - if (credential instanceof char[]) { - password = (char[]) credential; - } else if (credential instanceof CharSequence) { - password = credential.toString().toCharArray(); - } - } - - /** - * Sets any NameCallback name property to the instance username, sets any - * PasswordCallback password property to the instance, and any password. - * - * @exception UnsupportedCallbackException, - * thrown if any callback of type other than NameCallback or - * PasswordCallback are seen. - */ - public void handle(Callback[] callbacks) - throws UnsupportedCallbackException { - for (Callback c : callbacks) { - if (c instanceof NameCallback) { - NameCallback nc = (NameCallback) c; - nc.setName(username); - } else if (c instanceof PasswordCallback) { - PasswordCallback pc = (PasswordCallback) c; - if (password == null) { - // We were given an opaque Object credential but a char[] is - // requested? - if (credential != null) { - String tmp = credential.toString(); - password = tmp.toCharArray(); - } - } - pc.setPassword(password); - } else if (c instanceof NuxeoCallback) { - NuxeoCallback oc = (NuxeoCallback) c; - oc.setCredential(credential); - } else { - throw new UnsupportedCallbackException(c, - "Unrecognized Callback"); - } - } - } -} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoLoginConfiguration.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoLoginConfiguration.java deleted file mode 100644 index e008f4783..000000000 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoLoginConfiguration.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.collectionspace.services.nuxeo; - -/** - * - * @author sanjaydalal - */ -import java.util.HashMap; -import java.util.Map; - -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.Configuration; -import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; - -public class NuxeoLoginConfiguration extends Configuration { - - private final Configuration parent; - public static final String LOGIN_DOMAIN = "nuxeo-client-login"; - - public NuxeoLoginConfiguration(Configuration parent) { - this.parent = parent; - } - - @Override - public AppConfigurationEntry[] getAppConfigurationEntry(String name) { - - if (LOGIN_DOMAIN.equals(name)) { - AppConfigurationEntry[] entries = new AppConfigurationEntry[1]; - - Map options = new HashMap(); - - options.put("restore-login-identity", "True"); - options.put("multi-threaded", "True"); - - entries[0] = new AppConfigurationEntry("org.jboss.security.ClientLoginModule", LoginModuleControlFlag.REQUIRED, options); - - - return entries; - } else { - return parent.getAppConfigurationEntry(name); - } - } - - @Override - public void refresh() { - if (parent != null) { - parent.refresh(); - } - } -} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoLoginContextFactory.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoLoginContextFactory.java deleted file mode 100644 index fd02d18e2..000000000 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoLoginContextFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - -package org.collectionspace.services.nuxeo; - -/** - * - * @author sanjaydalal - */ - -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.Configuration; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; - -public class NuxeoLoginContextFactory { - - - private static boolean initDone=false; - - private static void initLoginConfig() - { - if (initDone) - return; - - Configuration parentConfig = null; - try { - parentConfig = Configuration.getConfiguration(); - } catch (Exception e) { - // do nothing - this can happen if default configuration provider is not correctly configured - // for examnple FileConfig fails if no config file was defined - } - Configuration config = new NuxeoLoginConfiguration(parentConfig); - Configuration.setConfiguration(config); - - initDone=true; - - } - - - public static LoginContext getLoginContext(CallbackHandler handler) throws LoginException - { - initLoginConfig(); - return new LoginContext(NuxeoLoginConfiguration.LOGIN_DOMAIN, handler); - } -} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java new file mode 100644 index 000000000..ada2139e3 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java @@ -0,0 +1,117 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.nuxeo.client.java; + +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.collectionspace.services.common.repository.DocumentException; +import java.util.HashMap; +import java.util.Map; +import org.collectionspace.services.nuxeo.client.*; +import org.collectionspace.services.nuxeo.util.NuxeoUtils; +import org.dom4j.Document; +import org.nuxeo.ecm.core.api.DocumentModel; +import org.nuxeo.ecm.core.api.repository.RepositoryInstance; + +/** + * DocumentModelHandler is a base abstract Nuxeo document handler + * using Nuxeo Java Remote APIs for CollectionSpace services + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public abstract class DocumentModelHandler + implements DocumentHandler { + + private Map properties = new HashMap(); + private RepositoryInstance repositorySession; + + @Override + public abstract void prepare(Action action) throws Exception; + + @Override + public abstract void handle(Action action, DocumentWrapper wrap) throws Exception; + + /** + * getRepositorySession returns Nuxeo Repository Session + * @return + */ + public RepositoryInstance getRepositorySession() { + return repositorySession; + } + + /** + * setRepositorySession sets repository session + * @param repoSession + */ + public void setRepositorySession(RepositoryInstance repoSession) { + this.repositorySession = repoSession; + } + + @Override + public abstract T extractCommonObject(DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract void fillCommonObject(T obj, DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract TL extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract void fillCommonObjectList(TL obj, DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract T getCommonObject(); + + @Override + public abstract void setCommonObject(T obj); + + @Override + public abstract TL getCommonObjectList(); + + @Override + public abstract void setCommonObjectList(TL obj); + + @Override + public Document getDocument(DocumentWrapper wrapDoc) throws DocumentException { + DocumentModel docModel = (DocumentModel) wrapDoc.getWrappedObject(); + return NuxeoUtils.getDocument(getRepositorySession(), docModel); + } + + /** + * @return the properties + */ + @Override + public Map getProperties() { + return properties; + } + + /** + * @param properties the properties to set + */ + @Override + public void setProperties(Map properties) { + this.properties = properties; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelListWrapper.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelListWrapper.java new file mode 100644 index 000000000..9248c2154 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelListWrapper.java @@ -0,0 +1,49 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.collectionspace.services.nuxeo.client.java; + +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.nuxeo.ecm.core.api.DocumentModelList; + +/** +* DocumentModelListWrapper wraps Nuxeo DocumentModel +* +* $LastChangedRevision: $ +* $LastChangedDate: $ +*/ +public class DocumentModelListWrapper implements DocumentWrapper { + + private DocumentModelList docModelList; + + public DocumentModelListWrapper(DocumentModelList docModelList) { + this.docModelList = docModelList; + } + + @Override + public Object getWrappedObject() { + return docModelList; + } + +} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelWrapper.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelWrapper.java new file mode 100644 index 000000000..75d993846 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelWrapper.java @@ -0,0 +1,49 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.collectionspace.services.nuxeo.client.java; + +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.nuxeo.ecm.core.api.DocumentModel; + +/** +* DocumentModelWrapper wraps Nuxeo DocumentModel +* +* $LastChangedRevision: $ +* $LastChangedDate: $ +*/ +public class DocumentModelWrapper implements DocumentWrapper { + + private DocumentModel docModel; + + public DocumentModelWrapper(DocumentModel docModel) { + this.docModel = docModel; + } + + @Override + public Object getWrappedObject() { + return docModel; + } + +} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoConnector.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoConnector.java similarity index 89% rename from services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoConnector.java rename to services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoConnector.java index ff61a8c72..491a105e5 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoConnector.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoConnector.java @@ -1,7 +1,27 @@ /** - * Copyright 2009 University of California at Berkeley + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ -package org.collectionspace.services.nuxeo; +package org.collectionspace.services.nuxeo.client.java; import java.io.File; import java.util.Collection; @@ -63,7 +83,7 @@ public class NuxeoConnector { initialized = true; }catch(Exception e){ if(logger.isDebugEnabled()){ - e.printStackTrace(); + logger.debug("Caught exception while initializing", e); } } } @@ -134,7 +154,7 @@ public class NuxeoConnector { // return client; // }else{ //authentication failure error comes when reusing the client - //fore connect for now + //force connect for now client.forceConnect(nuxeoClientConfig.getHost(), nuxeoClientConfig.getPort()); if(logger.isDebugEnabled()){ logger.debug("getClient(): connection successful port=" + diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClient.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClient.java new file mode 100644 index 000000000..3831c4565 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClient.java @@ -0,0 +1,310 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.nuxeo.client.java; + +import org.collectionspace.services.common.repository.RepositoryClient; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.repository.BadRequestException; +import org.collectionspace.services.common.repository.DocumentNotFoundException; +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.DocumentException; +import org.collectionspace.services.common.repository.DocumentHandler.Action; +import org.nuxeo.common.utils.IdUtils; +import org.nuxeo.ecm.core.api.ClientException; +import org.nuxeo.ecm.core.api.DocumentModel; +import org.nuxeo.ecm.core.api.DocumentModelList; +import org.nuxeo.ecm.core.api.DocumentRef; +import org.nuxeo.ecm.core.api.IdRef; +import org.nuxeo.ecm.core.api.repository.RepositoryInstance; +import org.nuxeo.ecm.core.client.NuxeoClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * RepositoryJavaClient is used to perform CRUD operations on documents + * in Nuxeo repository using Remote Java APIs. It uses @see DocumentHandler + * as IOHandler with the client. + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class RepositoryJavaClient implements RepositoryClient { + + private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClient.class); + + public RepositoryJavaClient() { + } + + /** + * create document in the Nuxeo repository + * @param serviceName entity service for which document is created. this is used to find mapping + * to a Nuxeo workspace using service-config.xml + * @param docType of the document created + * @param handler should be used by the caller to provide and transform the document + * @return id in repository of the newly created document + * @throws DocumentException + */ + @Override + public String create(String serviceName, String docType, DocumentHandler handler) throws BadRequestException, DocumentException { + + if(serviceName == null){ + throw new IllegalArgumentException("RemoteRepositoryClient.create: serviceName is missing"); + } + if(docType == null){ + throw new IllegalArgumentException("RemoteRepositoryClient.create: docType is missing"); + } + if(handler == null){ + throw new IllegalArgumentException("RemoteRepositoryClient.create: handler is missing"); + } + ServiceMain smain = ServiceMain.getInstance(); + String nuxeoWspaceId = smain.getWorkspaceId(serviceName); + if(nuxeoWspaceId == null){ + throw new DocumentNotFoundException("Unable to find workspace for service " + serviceName + + " check if the mapping exists in service-config.xml or " + + " the the mapped workspace exists in the Nuxeo repository"); + } + RepositoryInstance repoSession = null; + try{ + handler.prepare(Action.CREATE); + repoSession = getRepositorySession(); + + DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId); + DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace); + String wspacePath = wspaceDoc.getPathAsString(); + String id = IdUtils.generateId("New " + docType); + //create document model + DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, docType); + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); + handler.handle(Action.CREATE, wrapDoc); + //create document with documentmodel + doc = repoSession.createDocument(doc); + repoSession.save(); + return doc.getId(); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + + } + + /** + * get document from the Nuxeo repository + * @param id of the document to retrieve + * @param handler should be used by the caller to provide and transform the document + * @throws DocumentException + */ + @Override + public void get(String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { + + if(handler == null){ + throw new IllegalArgumentException("RemoteRepositoryClient.get: handler is missing"); + } + RepositoryInstance repoSession = null; + + try{ + handler.prepare(Action.GET); + repoSession = getRepositorySession(); + DocumentRef docRef = new IdRef(id); + DocumentModel doc = null; + try{ + doc = repoSession.getDocument(docRef); + }catch(ClientException ce){ + String msg = "could not find document with id=" + id; + logger.error(msg, ce); + throw new DocumentNotFoundException(msg, ce); + } + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); + handler.handle(Action.GET, wrapDoc); + }catch(IllegalArgumentException iae) { + throw iae; + }catch(DocumentException de){ + throw de; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + } + + /** + * getAll get all documents for an entity entity service from the Nuxeo repository + * @param serviceName entity service for which documents are retrieved. this is used to find mapping + * to a Nuxeo workspace using service-config.xml + * @param handler should be used by the caller to provide and transform the document + * @throws DocumentException + */ + @Override + public void getAll(String serviceName, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { + if(serviceName == null){ + throw new IllegalArgumentException("RemoteRepositoryClient.getAll: serviceName is missing"); + } + if(handler == null){ + throw new IllegalArgumentException("RemoteRepositoryClient.getAll: handler is missing"); + } + ServiceMain smain = ServiceMain.getInstance(); + String nuxeoWspaceId = smain.getWorkspaceId(serviceName); + if(nuxeoWspaceId == null){ + throw new DocumentNotFoundException("Unable to find workspace for service " + serviceName + + " check if the mapping exists in service-config.xml or " + + " the the mapped workspace exists in the Nuxeo repository"); + } + RepositoryInstance repoSession = null; + + try{ + handler.prepare(Action.GET_ALL); + repoSession = getRepositorySession(); + DocumentRef wsDocRef = new IdRef(nuxeoWspaceId); + DocumentModelList docList = repoSession.getChildren(wsDocRef); + + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentModelListWrapper wrapDoc = new DocumentModelListWrapper(docList); + handler.handle(Action.GET_ALL, wrapDoc); + + }catch(DocumentException de){ + throw de; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + } + + /** + * update given document in the Nuxeo repository + * @param id of the document + * @param handler should be used by the caller to provide and transform the document + * @throws DocumentException + */ + @Override + public void update(String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException { + if(id == null){ + throw new BadRequestException("RemoteRepositoryClient.update: id is missing"); + } + if(handler == null){ + throw new IllegalArgumentException("RemoteRepositoryClient.update: handler is missing"); + } + RepositoryInstance repoSession = null; + try{ + handler.prepare(Action.UPDATE); + repoSession = getRepositorySession(); + DocumentRef docRef = new IdRef(id); + DocumentModel doc = null; + try{ + doc = repoSession.getDocument(docRef); + }catch(ClientException ce){ + String msg = "Could not find document to update with id=" + id; + logger.error(msg, ce); + throw new DocumentNotFoundException(msg, ce); + } + ((DocumentModelHandler) handler).setRepositorySession(repoSession); + DocumentModelWrapper wrapDoc = new DocumentModelWrapper(doc); + handler.handle(Action.UPDATE, wrapDoc); + repoSession.saveDocument(doc); + repoSession.save(); + }catch(DocumentException de){ + throw de; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + } + + /** + * delete a document from the Nuxeo repository + * @param id of the document + * @throws DocumentException + */ + @Override + public void delete(String id) throws DocumentNotFoundException, DocumentException { + + if(logger.isDebugEnabled()){ + logger.debug("deleting document with id=" + id); + } + RepositoryInstance repoSession = null; + try{ + repoSession = getRepositorySession(); + DocumentRef docRef = new IdRef(id); + try{ + repoSession.removeDocument(docRef); + }catch(ClientException ce){ + String msg = "could not find document to delete with id=" + id; + logger.error(msg, ce); + throw new DocumentNotFoundException(msg, ce); + } + repoSession.save(); + }catch(DocumentException de){ + throw de; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + if(repoSession != null){ + releaseRepositorySession(repoSession); + } + } + } + + private RepositoryInstance getRepositorySession() throws Exception { + //FIXME: is it possible to reuse repository session? + //Authentication failures happen while trying to reuse the session + NuxeoClient client = NuxeoConnector.getInstance().getClient(); + RepositoryInstance repoSession = client.openRepository(); + if(logger.isDebugEnabled()){ + logger.debug("getRepository() repository root: " + + repoSession.getRootDocument()); + } + return repoSession; + } + + private void releaseRepositorySession(RepositoryInstance repoSession) { + try{ + NuxeoClient client = NuxeoConnector.getInstance().getClient(); + //release session + client.releaseRepository(repoSession); + }catch(Exception e){ + logger.error("Could not close the repository session", e); + //no need to throw this service specific exception + } + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoRESTClient.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/NuxeoRESTClient.java similarity index 76% rename from services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoRESTClient.java rename to services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/NuxeoRESTClient.java index f8785852c..e4e42e875 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoRESTClient.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/NuxeoRESTClient.java @@ -16,7 +16,7 @@ * * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ */ -package org.collectionspace.services.nuxeo; +package org.collectionspace.services.nuxeo.client.rest; import java.io.IOException; import java.io.InputStream; @@ -68,13 +68,13 @@ public class NuxeoRESTClient { sb.append(protocol); sb.append("://"); sb.append(serverIP); - if (serverPort != null && !serverIP.equals("80")) { + if(serverPort != null && !serverIP.equals("80")){ sb.append(':'); sb.append(serverPort); } - sb.append(servletPath); sb.append('/'); - baseURL = sb.toString(); + sb.append(servletPath); + this.baseURL = sb.toString(); } public void setBasicAuthentication(String userName, String password) { @@ -99,8 +99,8 @@ public class NuxeoRESTClient { String path = ""; StringBuffer pathBuffer = new StringBuffer(); - if (pathParams != null) { - for (String p : pathParams) { + if(pathParams != null){ + for(String p : pathParams){ pathBuffer.append(p); pathBuffer.append('/'); } @@ -114,10 +114,10 @@ public class NuxeoRESTClient { Map queryParams, InputStream istream) { StringBuffer urlBuffer = new StringBuffer(); - if (subPath.startsWith("/")) { + if(subPath.startsWith("/")){ subPath = subPath.substring(1); } - if (subPath.endsWith("/")) { + if(subPath.endsWith("/")){ subPath = subPath.substring(0, subPath.length() - 1); } @@ -127,16 +127,16 @@ public class NuxeoRESTClient { urlBuffer.append('/'); urlBuffer.append(subPath); - if (queryParams != null) { + if(queryParams != null){ urlBuffer.append('?'); - + String qpValue = null; - for (String qpName : queryParams.keySet()) { + for(String qpName : queryParams.keySet()){ urlBuffer.append(qpName); urlBuffer.append('='); qpValue = queryParams.get(qpName); - if (qpValue != null) { - urlBuffer.append(qpValue.replaceAll(" ", "%20")); + if(qpValue != null){ + urlBuffer.append(qpValue.replaceAll(" ", "%20")); } urlBuffer.append('&'); } @@ -156,7 +156,7 @@ public class NuxeoRESTClient { public void write(OutputStream outputStream) throws IOException { byte[] buffer = new byte[1024 * 64]; int read; - while ((read = in.read(buffer)) != -1) { + while((read = in.read(buffer)) != -1){ outputStream.write(buffer, 0, read); } @@ -171,8 +171,8 @@ public class NuxeoRESTClient { String path = ""; StringBuffer pathBuffer = new StringBuffer(); - if (pathParams != null) { - for (String p : pathParams) { + if(pathParams != null){ + for(String p : pathParams){ pathBuffer.append(p); pathBuffer.append('/'); } @@ -186,10 +186,10 @@ public class NuxeoRESTClient { Map queryParams) { StringBuffer urlBuffer = new StringBuffer(); - if (subPath.startsWith("/")) { + if(subPath.startsWith("/")){ subPath = subPath.substring(1); } - if (subPath.endsWith("/")) { + if(subPath.endsWith("/")){ subPath = subPath.substring(0, subPath.length() - 1); } @@ -199,9 +199,9 @@ public class NuxeoRESTClient { urlBuffer.append('/'); urlBuffer.append(subPath); - if (queryParams != null) { + if(queryParams != null){ urlBuffer.append('?'); - for (String qpName : queryParams.keySet()) { + for(String qpName : queryParams.keySet()){ urlBuffer.append(qpName); urlBuffer.append('='); urlBuffer.append(queryParams.get(qpName).replaceAll(" ", "%20")); @@ -220,19 +220,19 @@ public class NuxeoRESTClient { protected void setupAuth(Request request) { - if (authType == AUTH_TYPE_BASIC) { + if(authType == AUTH_TYPE_BASIC){ ChallengeScheme scheme = ChallengeScheme.HTTP_BASIC; ChallengeResponse authentication = new ChallengeResponse(scheme, userName, password); request.setChallengeResponse(authentication); - } else if (authType == AUTH_TYPE_SECRET) { + }else if(authType == AUTH_TYPE_SECRET){ Series additionnalHeaders = new Form(); Map securityHeaders = PortalSSOAuthenticationProvider.getHeaders( secretToken, userName); - for (String hn : securityHeaders.keySet()) { + for(String hn : securityHeaders.keySet()){ additionnalHeaders.add(hn, securityHeaders.get(hn)); } @@ -242,20 +242,20 @@ public class NuxeoRESTClient { } protected void setupCookies(Request request) { - if (cookies != null) { + if(cookies != null){ request.getCookies().clear(); - for (Cookie cookie : cookies) { + for(Cookie cookie : cookies){ request.getCookies().add(cookie); } } } - protected Client getRestClient() { - if (restClient == null) { - if (baseURL.startsWith("https")) { + Client getRestClient() { + if(restClient == null){ + if(baseURL.startsWith("https")){ restClient = new Client(Protocol.HTTPS); - } else { + }else{ restClient = new Client(Protocol.HTTP); } } @@ -310,4 +310,56 @@ public class NuxeoRESTClient { public void setUserName(String userName) { this.userName = userName; } + + /** + * buildUrl build URL from given path and query parameters + * @param pathParams + * @param queryParams + * @return + */ + String buildUrl(List pathParams, + Map queryParams) { + String subPath = ""; + StringBuffer pathBuffer = new StringBuffer(); + + if(pathParams != null){ + for(String p : pathParams){ + pathBuffer.append(p); + pathBuffer.append('/'); + } + subPath = pathBuffer.toString(); + } + + StringBuffer urlBuffer = new StringBuffer(); + + if(subPath.startsWith("/")){ + subPath = subPath.substring(1); + } + if(subPath.endsWith("/")){ + subPath = subPath.substring(0, subPath.length() - 1); + } + + urlBuffer.append(baseURL); + urlBuffer.append('/'); + urlBuffer.append(restPrefix); + urlBuffer.append('/'); + urlBuffer.append(subPath); + + if(queryParams != null){ + urlBuffer.append('?'); + + String qpValue = null; + for(String qpName : queryParams.keySet()){ + urlBuffer.append(qpName); + urlBuffer.append('='); + qpValue = queryParams.get(qpName); + if(qpValue != null){ + urlBuffer.append(qpValue.replaceAll(" ", "%20")); + } + urlBuffer.append('&'); + } + } + + return urlBuffer.toString(); + } } diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/PortalSSOAuthenticationProvider.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/PortalSSOAuthenticationProvider.java similarity index 97% rename from services/common/src/main/java/org/collectionspace/services/nuxeo/PortalSSOAuthenticationProvider.java rename to services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/PortalSSOAuthenticationProvider.java index 0bd2e5189..144c1ac23 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/PortalSSOAuthenticationProvider.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/PortalSSOAuthenticationProvider.java @@ -17,7 +17,7 @@ * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ */ -package org.collectionspace.services.nuxeo; +package org.collectionspace.services.nuxeo.client.rest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Date; diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepositoryRESTClient.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepositoryRESTClient.java new file mode 100644 index 000000000..ec755214a --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepositoryRESTClient.java @@ -0,0 +1,397 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.nuxeo.client.rest; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import org.collectionspace.services.common.repository.DocumentException; +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.RepositoryClient; + +import org.restlet.data.Request; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; + +import org.collectionspace.services.common.ServiceConfig; +import org.collectionspace.services.common.ServiceConfig.NuxeoClientConfig; +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.repository.BadRequestException; +import org.collectionspace.services.common.repository.DocumentNotFoundException; +import org.collectionspace.services.common.repository.DocumentHandler.Action; +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; +import org.dom4j.tree.DefaultDocument; +import org.restlet.data.MediaType; +import org.restlet.data.Method; +import org.restlet.data.Response; +import org.restlet.data.Status; +import org.restlet.resource.OutputRepresentation; +import org.restlet.resource.Representation; + +/** + * RepositoryRESTClient is used to perform CRUD operations on documents + * in Nuxeo repository using Nuxeo RESTful APIs. It uses @see DocumentHandler + * as IOHandler with the client. + * + * v2 NuxeoClient + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class RepositoryRESTClient implements RepositoryClient { + + private final Logger logger = LoggerFactory.getLogger(RepositoryRESTClient.class); + private NuxeoRESTClient nuxeoRestClient; + + public RepositoryRESTClient() { + } + + @Override + public String create(String serviceName, String docType, DocumentHandler handler) throws BadRequestException, DocumentException { + if(serviceName == null){ + throw new IllegalArgumentException("RepositoryRESTClient.create: serviceName is missing"); + } + if(docType == null){ + throw new IllegalArgumentException("RepositoryRESTClient.create: docType is missing"); + } + if(handler == null){ + throw new IllegalArgumentException("RepositoryRESTClient.create: handler is missing"); + } + ServiceMain smain = ServiceMain.getInstance(); + String nuxeoWspaceId = smain.getWorkspaceId(serviceName); + if(nuxeoWspaceId == null){ + throw new DocumentNotFoundException("Unable to find workspace for service " + serviceName + + " check if the mapping exists in service-config.xml or " + + " the the mapped workspace exists in the Nuxeo repository"); + } + try{ + RepresentationHandler repHandler = (RepresentationHandler) handler; + repHandler.prepare(Action.CREATE); + List pathParams = new ArrayList(); + pathParams.add("default"); + pathParams.add(nuxeoWspaceId); + pathParams.add("createDocument"); + if(repHandler.getPathParams().size() > 0){ + pathParams.addAll(repHandler.getPathParams()); + } + Map queryParams = new HashMap(); + queryParams.put("docType", docType); + // a default title for the Dublin Core schema + queryParams.put("dublincore:title", "CollectionSpace-" + docType); + if(repHandler.getQueryParams().size() > 0){ + queryParams.putAll(repHandler.getQueryParams()); + } + + String completeURL = getNuxeoRestClient().buildUrl(pathParams, queryParams); + if(logger.isDebugEnabled()){ + logger.debug("create using url=" + completeURL); + } + Request request = buildRequest(Method.POST, completeURL); + + //write out create stream, this is not needed as queryParams + //contain the document + final InputStream in = new ByteArrayInputStream(new byte[0]); + request.setEntity(new OutputRepresentation( + MediaType.MULTIPART_FORM_DATA) { + + @Override + public void write(OutputStream outputStream) throws IOException { + byte[] buffer = new byte[1024 * 64]; + int read; + while((read = in.read(buffer)) != -1){ + outputStream.write(buffer, 0, read); + } + } + }); + //following call to handler.handle is not needed as queryparams + //contains the real data + RepresentationWrapper wrapDoc = new RepresentationWrapper(new DefaultDocument()); + repHandler.handle(Action.CREATE, wrapDoc); + //read response + //Nuxeo does not set 201 SUCCESS_CREATED on successful creation + Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); + //handle is not needed on create as queryparams have all data + return extractId(document); + + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + } + } + + @Override + public void get(String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { + + if(handler == null){ + throw new IllegalArgumentException("RepositoryRESTClient.get: handler is missing"); + } + + try{ + RepresentationHandler repHandler = (RepresentationHandler) handler; + repHandler.prepare(Action.GET); + ArrayList pathParams = new ArrayList(); + pathParams.add("default"); + pathParams.add(id); + pathParams.add("export"); + if(repHandler.getPathParams().size() > 0){ + pathParams.addAll(repHandler.getPathParams()); + } + HashMap queryParams = new HashMap(); + queryParams.put("format", "XML"); + if(repHandler.getQueryParams().size() > 0){ + queryParams.putAll(repHandler.getQueryParams()); + } + String completeURL = getNuxeoRestClient().buildUrl(pathParams, queryParams); + if(logger.isDebugEnabled()){ + logger.debug("get using url=" + completeURL); + } + Request request = buildRequest(Method.GET, completeURL); + Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); + RepresentationWrapper wrapDoc = new RepresentationWrapper(document); + repHandler.handle(Action.GET, wrapDoc); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + } + } + + @Override + public void getAll(String serviceName, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { + if(serviceName == null){ + throw new IllegalArgumentException("RepositoryRESTClient.getAll: serviceName is missing"); + } + if(handler == null){ + throw new IllegalArgumentException("RepositoryRESTClient.getAll: handler is missing"); + } + ServiceMain smain = ServiceMain.getInstance(); + String nuxeoWspaceId = smain.getWorkspaceId(serviceName); + if(nuxeoWspaceId == null){ + throw new DocumentNotFoundException("Unable to find workspace for service " + serviceName + + " check if the mapping exists in service-config.xml or " + + " the the mapped workspace exists in the Nuxeo repository"); + } + try{ + RepresentationHandler repHandler = (RepresentationHandler) handler; + repHandler.prepare(Action.GET_ALL); + ArrayList pathParams = new ArrayList(); + pathParams.add("default"); + pathParams.add(nuxeoWspaceId); + pathParams.add("browse"); + if(repHandler.getPathParams().size() > 0){ + pathParams.addAll(repHandler.getPathParams()); + } + String completeURL = getNuxeoRestClient().buildUrl(pathParams, repHandler.getQueryParams()); + if(logger.isDebugEnabled()){ + logger.debug("getAll using url=" + completeURL); + } + Request request = buildRequest(Method.GET, completeURL); + Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); + RepresentationWrapper wrapDoc = new RepresentationWrapper(document); + repHandler.handle(Action.GET_ALL, wrapDoc); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + } + } + + @Override + public void update(String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException { + if(handler == null){ + throw new IllegalArgumentException("RepositoryRESTClient.update: handler is missing"); + } + + try{ + RepresentationHandler repHandler = (RepresentationHandler) handler; + repHandler.prepare(Action.UPDATE); + List pathParams = new ArrayList(); + pathParams.add("default"); + pathParams.add(id); + pathParams.add("updateDocumentRestlet"); + if(repHandler.getPathParams().size() > 0){ + pathParams.addAll(repHandler.getPathParams()); + } + String completeURL = getNuxeoRestClient().buildUrl(pathParams, repHandler.getQueryParams()); + if(logger.isDebugEnabled()){ + logger.debug("update using url=" + completeURL); + } + //repHandler.handle is not needed as queryParams contain all the data + RepresentationWrapper wrapDoc = new RepresentationWrapper(new DefaultDocument()); + repHandler.handle(Action.UPDATE, wrapDoc); + Request request = buildRequest(Method.PUT, completeURL); + Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); + + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + } + } + + @Override + public void delete(String id) throws DocumentNotFoundException, DocumentException { + + if(logger.isDebugEnabled()){ + logger.debug("deleting document with id=" + id); + } + + try{ + List pathParams = new ArrayList(); + pathParams.add("default"); + pathParams.add(id); + pathParams.add("deleteDocumentRestlet"); + + Map queryParams = new HashMap(); + String completeURL = getNuxeoRestClient().buildUrl(pathParams, queryParams); + if(logger.isDebugEnabled()){ + logger.debug("delete using url=" + completeURL); + } + Request request = buildRequest(Method.DELETE, completeURL); + Document document = executeRequest(request, completeURL, Status.SUCCESS_OK); + //FIXME error handling? + // Document document = service.deleteCollectionObject(csid); +// Element root = document.getRootElement(); +// for(Iterator i = root.elementIterator(); i.hasNext();){ +// Element element = (Element) i.next(); +// if("docRef".equals(element.getName())){ +// String status = (String) element.getData(); +// verbose("deleteCollectionObjectt response: " + status); +// } +// } + + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + }finally{ + } + } + + /** + * buildRequest build HTTP request given parameters + * @param method + * @param completeURL + * @return + */ + private Request buildRequest(Method method, String completeURL) { + Request request = new Request(method, completeURL); + getNuxeoRestClient().setupAuth(request); + getNuxeoRestClient().setupCookies(request); + return request; + } + + /** + * executeRequest execute given HTTP request + * @param request + * @param completeURL + * @return + * @throws Exception + */ + private Document executeRequest(Request request, String completeURL, Status expected) throws Exception { + //execute + Response res = getNuxeoRestClient().getRestClient().handle(request); + Status status = res.getStatus(); + if(status.getCode() != expected.getCode()){ + logger.error("failed to execute request=" + request.getMethod() + + " with error status=" + status + + " url=" + completeURL + + " response=" + res.toString()); + throw new DocumentException(status.getCode(), status.getDescription()); + } + Representation rep = res.getEntity(); + + //read response + return retrieveResponse(rep); + } + + /** + * retrieveResponse retrieves DOM document from Restlet Represeantion + * @param request + * @return + * @throws Exception + */ + private Document retrieveResponse(Representation rep) throws Exception { + SAXReader reader = new SAXReader(); + Document document = reader.read(rep.getStream()); + return document; + } + + /** + * extractId extract document id from response + * @param document + * @return + */ + private String extractId(Document document) { + String csid = null; + Element root = document.getRootElement(); + for(Iterator i = root.elementIterator(); i.hasNext();){ + Element element = (Element) i.next(); + if("docRef".equals(element.getName())){ + csid = (String) element.getData(); + break; + } + } + return csid; + } + + private NuxeoRESTClient getNuxeoRestClient() { + if(nuxeoRestClient == null){ + ServiceConfig sconfig = ServiceMain.getInstance().getServiceConfig(); + NuxeoClientConfig nxConfig = sconfig.getNuxeoClientConfig(); + String protocol = "http"; + if(nxConfig.getProtocol() != null && !"".equals(nxConfig.getProtocol())){ + protocol = nxConfig.getProtocol(); + } + NuxeoRESTClient tempClient = new NuxeoRESTClient(protocol, + nxConfig.getHost(), "" + nxConfig.getPort()); + + tempClient.setBasicAuthentication(nxConfig.getUser(), nxConfig.getPassword()); + + nuxeoRestClient = tempClient; + + } + return nuxeoRestClient; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationHandler.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationHandler.java new file mode 100644 index 000000000..91828ea18 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationHandler.java @@ -0,0 +1,161 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.nuxeo.client.rest; + +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.collectionspace.services.common.repository.DocumentException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.collectionspace.services.nuxeo.client.*; +import org.dom4j.Document; + +/** + * RepresentationHandler is a base abstract Nuxeo document handler + * using Nuxeo RESTful APIs for CollectionSpace services + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public abstract class RepresentationHandler + implements DocumentHandler { + + private Map properties = new HashMap(); + private List pathParams = new ArrayList(); + private Map queryParams = new HashMap(); + private Document document; + private InputStream inputStream = null; + + @Override + public abstract void prepare(Action action) throws Exception; + + @Override + public abstract void handle(Action action, DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract T extractCommonObject(DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract void fillCommonObject(T obj, DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract TL extractCommonObjectList(DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract void fillCommonObjectList(TL obj, DocumentWrapper wrapDoc) throws Exception; + + @Override + public abstract T getCommonObject(); + + @Override + public abstract void setCommonObject(T obj); + + @Override + public abstract TL getCommonObjectList(); + + @Override + public abstract void setCommonObjectList(TL obj); + + @Override + public Document getDocument(DocumentWrapper wrapDoc) throws DocumentException { + throw new UnsupportedOperationException("DocumentHandler.getDocument(wrapDoc)"); + } + + /** + * @return the pathParams + */ + public List getPathParams() { + return pathParams; + } + + /** + * @param pathParams the pathParams to set + */ + public void setPathParams(List pathParams) { + this.pathParams = pathParams; + } + + /** + * @return the queryParams + */ + public Map getQueryParams() { + return queryParams; + } + + /** + * @param queryParams the queryParams to set + */ + public void setQueryParams(Map queryParams) { + this.queryParams = queryParams; + } + + /** + * getInputStream to retrieve input stream by client for posting a document + * @return the inputStream + */ + public InputStream getInputStream() { + return inputStream; + } + + /** + * setInputStream to set input stream to read for posting document + * @param inputStream the inputStream to set + */ + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + + /** + * @return the document + */ + public Document getDocument() { + return document; + } + + /** + * @param document the document to set + */ + public void setDocument(Document document) { + this.document = document; + } + + /** + * @return the properties + */ + @Override + public Map getProperties() { + return properties; + } + + /** + * @param properties the properties to set + */ + @Override + public void setProperties(Map properties) { + this.properties = properties; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationWrapper.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationWrapper.java new file mode 100644 index 000000000..60227dcfe --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/rest/RepresentationWrapper.java @@ -0,0 +1,47 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.nuxeo.client.rest; + +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.dom4j.Document; + +/** + * RepresentationWrapper wraps RESTful representation (Restlet) + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class RepresentationWrapper implements DocumentWrapper { + + private Document document; + + public RepresentationWrapper(Document doc) { + document = doc; + } + + @Override + public Object getWrappedObject() { + return document; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoUtils.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java similarity index 59% rename from services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoUtils.java rename to services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java index 059f2656c..cc4cf4733 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/NuxeoUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java @@ -1,12 +1,26 @@ /** - * Copyright 2009 University of California at Berkeley + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt */ -package org.collectionspace.services.nuxeo; +package org.collectionspace.services.nuxeo.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import javax.ws.rs.WebApplicationException; +import org.collectionspace.services.common.repository.DocumentException; import org.dom4j.Document; import org.dom4j.io.SAXReader; import org.nuxeo.ecm.core.api.DocumentModel; @@ -22,14 +36,20 @@ import org.slf4j.LoggerFactory; /** * Various utilities related to Nuxeo - * @author */ public class NuxeoUtils { private static Logger logger = LoggerFactory.getLogger(NuxeoUtils.class); - public static Document getDocument(RepositoryInstance repoSession, DocumentModel helloDoc) - throws Exception { + /** + * getDocument retrieve org.dom4j.Document from Nuxeo DocumentModel + * @param repoSession + * @param nuxeoDoc + * @return + * @throws DocumentException + */ + public static Document getDocument(RepositoryInstance repoSession, DocumentModel nuxeoDoc) + throws DocumentException { Document doc = null; DocumentWriter writer = null; DocumentReader reader = null; @@ -38,7 +58,7 @@ public class NuxeoUtils { try{ baos = new ByteArrayOutputStream(); //nuxeo io.impl begin - reader = new SingleDocumentReader(repoSession, helloDoc); + reader = new SingleDocumentReader(repoSession, nuxeoDoc); writer = new XMLDocumentWriter(baos); DocumentPipe pipe = new DocumentPipeImpl(); //nuxeo io.impl end @@ -48,6 +68,11 @@ public class NuxeoUtils { bais = new ByteArrayInputStream(baos.toByteArray()); SAXReader saxReader = new SAXReader(); doc = saxReader.read(bais); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception while processing document ", e); + } + throw new DocumentException(e); }finally{ if(reader != null){ reader.close(); @@ -63,8 +88,9 @@ public class NuxeoUtils { baos.close(); } }catch(IOException ioe){ - logger.error("Failed to close io streams with {}", ioe); - throw new WebApplicationException(); + String msg = "Failed to close io streams"; + logger.error(msg + " {}", ioe); + throw new DocumentException(ioe); } } return doc; diff --git a/services/common/src/main/resources/service-config.xsd b/services/common/src/main/resources/service-config.xsd index 0dd79cfaa..78e85ba0f 100644 --- a/services/common/src/main/resources/service-config.xsd +++ b/services/common/src/main/resources/service-config.xsd @@ -22,9 +22,15 @@ + + + + + + @@ -35,7 +41,10 @@ + + + @@ -46,6 +55,14 @@ + + + + + + + + diff --git a/services/intake/service/src/main/java/org/collectionspace/services/IntakeServiceNuxeoImpl.java b/services/intake/service/src/main/java/org/collectionspace/services/IntakeServiceNuxeoImpl.java index 4bc1f43c3..d882fb66b 100644 --- a/services/intake/service/src/main/java/org/collectionspace/services/IntakeServiceNuxeoImpl.java +++ b/services/intake/service/src/main/java/org/collectionspace/services/IntakeServiceNuxeoImpl.java @@ -11,7 +11,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.collectionspace.services.nuxeo.NuxeoRESTClient; +import org.collectionspace.services.nuxeo.client.rest.NuxeoRESTClient; import org.collectionspace.services.nuxeo.CollectionSpaceServiceNuxeoImpl; import org.collectionspace.services.intake.Intake; import org.collectionspace.services.IntakeJAXBSchema;