From: Richard Millet Date: Wed, 11 Apr 2012 21:45:56 +0000 (-0700) Subject: Merge branch 'CSPACE-4964' back to trunk. Includes work in the service layer for... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=225dfbce9941938749987c0023d9f2ff58b23f46;p=tmp%2Fjakarta-migration.git Merge branch 'CSPACE-4964' back to trunk. Includes work in the service layer for supporting different workflow life cycles. --- 225dfbce9941938749987c0023d9f2ff58b23f46 diff --cc services/client/src/main/java/org/collectionspace/services/client/AbstractServiceClientImpl.java index f898152a3,f898152a3..377fb551a --- a/services/client/src/main/java/org/collectionspace/services/client/AbstractServiceClientImpl.java +++ b/services/client/src/main/java/org/collectionspace/services/client/AbstractServiceClientImpl.java @@@ -430,8 -430,8 +430,8 @@@ public abstract class AbstractServiceCl } @Override -- public ClientResponse updateWorkflow(String csid, PoxPayloadOut xmlPayload) { -- return getProxy().updateWorkflow(csid, xmlPayload.getBytes()); ++ public ClientResponse updateWorkflowWithTransition(String csid, String workflowTransition) { ++ return getProxy().updateWorkflowWithTransition(csid, workflowTransition); } /* diff --cc services/client/src/main/java/org/collectionspace/services/client/AuthorityProxy.java index 52493c81e,52493c81e..178f1409c --- a/services/client/src/main/java/org/collectionspace/services/client/AuthorityProxy.java +++ b/services/client/src/main/java/org/collectionspace/services/client/AuthorityProxy.java @@@ -37,7 -37,7 +37,7 @@@ public interface AuthorityProxy extend @Path("/{vcsid}/items/{csid}") ClientResponse readItem(@PathParam("vcsid") String vcsid, @PathParam("csid") String csid, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); //(U)pdate Item @PUT @@@ -64,7 -64,7 +64,7 @@@ ClientResponse getReferencingObjects( @PathParam("csid") String parentcsid, @PathParam("itemcsid") String itemcsid, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); // List Item Authority References @GET @@@ -82,7 -82,7 +82,7 @@@ @GET @Path("/urn:cspace:name({name})") ClientResponse readByName(@PathParam("name") String name, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); /* * Item subresource methods @@@ -93,21 -93,21 +93,21 @@@ @Path("/{vcsid}/items/urn:cspace:name({specifier})") ClientResponse readNamedItem(@PathParam("vcsid") String vcsid, @PathParam("specifier") String specifier, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); //(R)ead Item In Named Authority @GET @Path("/urn:cspace:name({specifier})/items/{csid}") ClientResponse readItemInNamedAuthority(@PathParam("specifier") String specifier, @PathParam("csid") String csid, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); //(R)ead Named Item In Named Authority @GET @Path("/urn:cspace:name({specifier})/items/urn:cspace:name({itemspecifier})") ClientResponse readNamedItemInNamedAuthority(@PathParam("specifier") String specifier, @PathParam("itemspecifier") String itemspecifier, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); /* * Item subresource List methods @@@ -121,7 -121,7 +121,7 @@@ @PathParam("csid") String vcsid, @QueryParam (IQueryManager.SEARCH_TYPE_PARTIALTERM) String partialTerm, @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); // List Items for a named authority matching a partial term or keywords. @GET @@@ -131,7 -131,7 +131,7 @@@ @PathParam("specifier") String specifier, @QueryParam (IQueryManager.SEARCH_TYPE_PARTIALTERM) String partialTerm, @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); /* * Workflow related methods diff --cc services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceClient.java index 668a8664d,668a8664d..7652020a1 --- a/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceClient.java +++ b/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceClient.java @@@ -193,7 -193,7 +193,7 @@@ public interface CollectionSpaceClient< */ public ClientResponse getWorkflow(String csid); -- public ClientResponse updateWorkflow(String csid, PoxPayloadOut xmlPayload); ++ public ClientResponse updateWorkflowWithTransition(String csid, String workflowTransition); /** * Gets the authority refs. diff --cc services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceCommonListPoxProxy.java index 6ca169844,6ca169844..6ee3dfd7f --- a/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceCommonListPoxProxy.java +++ b/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceCommonListPoxProxy.java @@@ -16,19 -16,19 +16,19 @@@ public interface CollectionSpaceCommonL @GET @Produces({"application/xml"}) ClientResponse readIncludeDeleted( -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @Override @GET @Produces({"application/xml"}) ClientResponse keywordSearchIncludeDeleted( @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @Override @GET @Produces({ "application/xml" }) ClientResponse advancedSearchIncludeDeleted( @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_AS) String whereClause, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); } diff --cc services/client/src/main/java/org/collectionspace/services/client/CollectionSpacePoxProxy.java index e09c6f538,e09c6f538..0e760ba4e --- a/services/client/src/main/java/org/collectionspace/services/client/CollectionSpacePoxProxy.java +++ b/services/client/src/main/java/org/collectionspace/services/client/CollectionSpacePoxProxy.java @@@ -30,7 -30,7 +30,7 @@@ public interface CollectionSpacePoxProx @Path("/{csid}") ClientResponse readIncludeDeleted( @PathParam("csid") String csid, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); // (U)pdate @PUT @@@ -41,26 -41,26 +41,26 @@@ @GET @Produces({ "application/xml" }) ClientResponse readIncludeDeleted( -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); /** * Keyword search. * * @param keywords * keywords on which to search -- * @param includeDeleted ++ * @param workflowState * @return the client response */ @GET @Produces({ "application/xml" }) ClientResponse keywordSearchIncludeDeleted( @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @GET @Produces({ "application/xml" }) ClientResponse advancedSearchIncludeDeleted( @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_AS) String whereClause, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); } diff --cc services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceProxy.java index 21df5873a,21df5873a..18acc9ece --- a/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceProxy.java +++ b/services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceProxy.java @@@ -67,8 -67,8 +67,8 @@@ public interface CollectionSpaceProxy updateWorkflow(@PathParam("csid") String csid, byte[] xmlPayload); ++ @Path("{csid}" + WorkflowClient.SERVICE_PATH + "/" + "{transition}") ++ ClientResponse updateWorkflowWithTransition(@PathParam("csid") String csid, @PathParam("transition") String transition); /* * (R)read List operations diff --cc services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTestImpl.java index 2a1edf9ad,2a1edf9ad..510ad38f2 --- a/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTestImpl.java +++ b/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTestImpl.java @@@ -530,7 -530,7 +530,7 @@@ public abstract class AbstractServiceTe int existingTestCreated = allResourceIdsCreated.size(); // assumption is that no other test created records were soft deleted String csid = allResourceIdsCreated.get(existingTestCreated - 1); //0-based index to get the last one added this.setupUpdate(); -- this.updateLifeCycleState(testName, csid, WorkflowClient.WORKFLOWSTATE_DELETED); ++ this.updateLifeCycleState(testName, csid, WorkflowClient.WORKFLOWTRANSITION_DELETE, WorkflowClient.WORKFLOWSTATE_DELETED); // // Read the list of existing non-deleted records // @@@ -597,7 -597,7 +597,7 @@@ int existingTestCreated = allResourceIdsCreated.size(); // assumption is that no other test created records were soft deleted String csid = allResourceIdsCreated.get(existingTestCreated - 1); //0-based index to get the last one added this.setupUpdate(); -- this.updateLifeCycleState(testName, csid, WorkflowClient.WORKFLOWSTATE_DELETED); ++ this.updateLifeCycleState(testName, csid, WorkflowClient.WORKFLOWTRANSITION_DELETE, WorkflowClient.WORKFLOWSTATE_DELETED); // // Search for the newly-created records, excluding the soft deleted record. @@@ -806,7 -806,7 +806,7 @@@ @SuppressWarnings("rawtypes") -- protected void updateLifeCycleState(String testName, String resourceId, String lifeCycleState) throws Exception { ++ protected void updateLifeCycleState(String testName, String resourceId, String workflowTransition, String lifeCycleState) throws Exception { // // Read the existing object // @@@ -835,7 -835,7 +835,7 @@@ // Perform the update // WorkflowCommon updatedWorkflowCommons = null; -- res = client.updateWorkflow(resourceId, output); ++ res = client.updateWorkflowWithTransition(resourceId, workflowTransition); try { assertStatusCode(res, testName); PoxPayloadIn input = new PoxPayloadIn(res.getEntity()); diff --cc services/client/src/main/java/org/collectionspace/services/client/workflow/WorkflowClient.java index 4e5ddc2eb,6db639d37..c3ea8854e --- a/services/client/src/main/java/org/collectionspace/services/client/workflow/WorkflowClient.java +++ b/services/client/src/main/java/org/collectionspace/services/client/workflow/WorkflowClient.java @@@ -39,13 -39,17 +39,23 @@@ public class WorkflowClient extends Abs // // Workflow states // ++ public static final String WORKFLOWTRANSITION_UNDELETE = "undelete"; ++ public static final String WORKFLOWTRANSITION_DELETE = "delete"; public static final String WORKFLOWSTATE_DELETED = "deleted"; -- public static final String WORKFLOWSTATE_PROJECT = "project"; - public static final String WORKFLOWSTATE_APPROVED = "approved"; - public static final String WORKFLOWSTATE_APPROVED = "approved"; ++ ++ public static final String WORKFLOWSTATE_ACTIVE = "active"; ++ ++ public static final String WORKFLOWTRANSITION_LOCK = "lock"; ++ public static final String WORKFLOWSTATE_LOCKED = "locked"; + // + // DocumentHandler passed properties + // + public static final String TRANSITION_ID = "transition_id"; // // Service Query Params // -- public static final String WORKFLOW_QUERY_NONDELETED = "wf_deleted"; ++ public static final String WORKFLOW_QUERY_NONDELETED = "wf_deleted"; ++ public static final String WORKFLOWSTATE_QUERY = "wf_deleted"; @Override diff --cc services/common/src/main/cspace/config/services/service-config.xml index 06b543238,890fa00c4..d4d669e4b --- a/services/common/src/main/cspace/config/services/service-config.xml +++ b/services/common/src/main/cspace/config/services/service-config.xml @@@ -26,6 -26,6 +26,7 @@@ org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl pageSizeDefault40 ++ refreshAuthZOnStartuptrue diff --cc services/common/src/main/cspace/config/services/tenants/lifesci/tenant-bindings.delta.xml index 3de2dde8a,e24cf4664..b9c0a76e3 --- a/services/common/src/main/cspace/config/services/tenants/lifesci/tenant-bindings.delta.xml +++ b/services/common/src/main/cspace/config/services/tenants/lifesci/tenant-bindings.delta.xml @@@ -40,8 -40,7 +40,8 @@@ authRef taxonomicIdentGroupList/*/institution + + + - + authRef contentConcepts|contentConcept + + + + - + authRef contentOrganizations|contentOrganization + + + + + + - + authRef contentPersons|contentPerson @@@ -234,27 -216,19 +234,27 @@@ authRef textualInscriptionGroupList/*/inscriptionContentInscriber + + - + authRef nonTextualInscriptionGroupList/*/inscriptionDescriptionInscriber + + + + + + - + authRef objectProductionOrganizationGroupList/*/objectProductionOrganization + + - + authRef objectProductionPersonGroupList/*/objectProductionPerson @@@ -338,14 -304,11 +338,14 @@@ authRef assocOrganizationGroupList/*/assocOrganization + + - + authRef assocPersonGroupList/*/assocPerson @@@ -371,15 -334,12 +371,15 @@@ + + - + authRef fieldCollectionPlace @@@ -391,9 -351,7 +391,9 @@@ authRef fieldCollectors|fieldCollector + + + - + authRef valuer @@@ -1363,14 -1317,12 +1363,14 @@@ authRef rightsHolder - + + - + authRef measuredPartGroupList/*/dimensionSubGroupList/*/measuredBy @@@ -1861,9 -1813,7 +1861,9 @@@ authRef foundingPlace + + + - + termRef salutation @@@ -2576,156 -2522,12 +2576,156 @@@ + + - /conceptauthorities/*/workflow/ - /conceptauthorities/*/items/*/workflow/ ++ /conceptauthorities/*/workflow/ ++ /conceptauthorities/*/items/*/workflow/ + + - default-domain - org.collectionspace.services.concept.nuxeo.ConceptAuthorityDocumentModelHandler - ++ default-domain ++ org.collectionspace.services.concept.nuxeo.ConceptAuthorityDocumentModelHandler ++ + + + + displayName + displayName + + + refName + refName + + + shortIdentifier + shortIdentifier + + + vocabType + vocabType + + + + - ++ + org.collectionspace.services.common.init.AddIndices + + + conceptauthorities_common + displayname + + + conceptauthorities_common + shortidentifier + + + - ++ + + - ++ + + + + + + + + + + + + + + + + + + - default-domain - org.collectionspace.services.concept.nuxeo.ConceptDocumentModelHandler - ++ default-domain ++ org.collectionspace.services.concept.nuxeo.ConceptDocumentModelHandler ++ + + + + + termType + termType + + + + - org.collectionspace.services.concept.nuxeo.ConceptValidatorHandler - ++ org.collectionspace.services.concept.nuxeo.ConceptValidatorHandler ++ + org.collectionspace.services.common.init.AddIndices + + + concepts_common + inauthority + + + concepts_common + displayname + + + concepts_common + shortidentifier + + + - - ++ ++ + objectNameProperty + displayName + - ++ + objectNumberProperty + shortIdentifier + + - ++ + + - ++ + + + - ++ + - ++ + termRef + recordType + - ++ + termRef + termStatus + + + + + + + + + + + + + + + - /acquisitions/*/workflow/ + /acquisitions/*/workflow/ @@@ -2785,15 -2587,12 +2785,15 @@@ authRef acquisitionSources|acquisitionSource + + - + termRef acquisitionFundingList/*/acquisitionFundingCurrency diff --cc services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java index 62ac660e8,bf4113d02..c52219206 --- a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java +++ b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java @@@ -1,8 -1,930 +1,937 @@@ package org.collectionspace.services.common.authorization_mgt; + import java.sql.Connection; + import java.sql.PreparedStatement; + import java.sql.ResultSet; + import java.sql.SQLException; + import java.sql.Statement; + import java.util.ArrayList; + import java.util.Date; + import java.util.HashMap; + import java.util.Hashtable; + import java.util.List; + import java.util.UUID; + + import javax.naming.NamingException; + import javax.persistence.EntityManager; + import javax.persistence.EntityManagerFactory; + + import org.collectionspace.services.authorization.AuthZ; + import org.collectionspace.services.authorization.CSpaceAction; + import org.collectionspace.services.authorization.PermissionException; + import org.collectionspace.services.authorization.PermissionRole; + import org.collectionspace.services.authorization.PermissionRoleRel; + import org.collectionspace.services.authorization.PermissionValue; + import org.collectionspace.services.authorization.Role; + import org.collectionspace.services.authorization.RoleValue; + import org.collectionspace.services.authorization.SubjectType; + import org.collectionspace.services.authorization.URIResourceImpl; + import org.collectionspace.services.authorization.perms.ActionType; + import org.collectionspace.services.authorization.perms.EffectType; + import org.collectionspace.services.authorization.perms.Permission; + import org.collectionspace.services.authorization.perms.PermissionAction; + + import org.collectionspace.services.client.RoleClient; + import org.collectionspace.services.client.workflow.WorkflowClient; + import org.collectionspace.services.common.config.ServiceConfigUtils; + import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; ++import org.collectionspace.services.common.context.ServiceBindingUtils; + import org.collectionspace.services.common.document.DocumentHandler; + import org.collectionspace.services.common.profile.Profiler; + import org.collectionspace.services.common.security.SecurityUtils; + import org.collectionspace.services.common.storage.DatabaseProductType; + import org.collectionspace.services.common.storage.JDBCTools; + import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; + import org.collectionspace.services.config.service.ServiceBindingType; + import org.collectionspace.services.config.tenant.TenantBindingType; + + import org.collectionspace.services.lifecycle.Lifecycle; + import org.collectionspace.services.lifecycle.TransitionDef; + import org.collectionspace.services.lifecycle.TransitionDefList; + + //import org.mortbay.log.Log; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + + import org.springframework.security.acls.model.AlreadyExistsException; + + public class AuthorizationCommon { + ++ final public static String REFRESH_AUTZ_PROP = "refreshAuthZOnStartup"; + // + // ActionGroup labels/constants + // + + // for READ-WRITE + final public static String ACTIONGROUP_CRUDL_NAME = "CRUDL"; + final public static ActionType[] ACTIONSET_CRUDL = {ActionType.CREATE, ActionType.READ, ActionType.UPDATE, ActionType.DELETE, ActionType.SEARCH}; + // for READ-ONLY + final public static String ACTIONGROUP_RL_NAME = "RL"; + final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH}; + + /* + * Inner class to deal with predefined ADMIN and READER action groupds + */ + public class ActionGroup { + String name; + ActionType[] actions; + } + + static ActionGroup ACTIONGROUP_CRUDL; + static ActionGroup ACTIONGROUP_RL; + + // A static block to initialize the predefined action groups + static { + AuthorizationCommon ac = new AuthorizationCommon(); + // For admin + ACTIONGROUP_CRUDL = ac.new ActionGroup(); + ACTIONGROUP_CRUDL.name = ACTIONGROUP_CRUDL_NAME; + ACTIONGROUP_CRUDL.actions = ACTIONSET_CRUDL; + // For reader + ACTIONGROUP_RL = ac.new ActionGroup(); + ACTIONGROUP_RL.name = ACTIONGROUP_RL_NAME; + ACTIONGROUP_RL.actions = ACTIONSET_RL; + + } + + final static Logger logger = LoggerFactory.getLogger(AuthorizationCommon.class); + + // + // The "super" role has a predefined ID of "0" and a tenant ID of "0"; + // + final public static String ROLE_ADMINISTRATOR = "ADMINISTRATOR"; + final public static String ROLE_ADMINISTRATOR_ID = "0"; + final public static String ADMINISTRATOR_TENANT_ID = "0"; + + final public static String ROLE_TENANT_ADMINISTRATOR = "TENANT_ADMINISTRATOR"; + final public static String ROLE_TENANT_READER = "TENANT_READER"; + + public static final String TENANT_ADMIN_ACCT_PREFIX = "admin@"; + public static final String TENANT_READER_ACCT_PREFIX = "reader@"; + public static final String ROLE_PREFIX = "ROLE_"; + public static final String SPRING_ADMIN_ROLE = "ROLE_SPRING_ADMIN"; + public static final String TENANT_ADMIN_ROLE_SUFFIX = "_TENANT_ADMINISTRATOR"; + public static final String TENANT_READER_ROLE_SUFFIX = "_TENANT_READER"; + public static final String DEFAULT_ADMIN_PASSWORD = "Administrator"; + public static final String DEFAULT_READER_PASSWORD = "reader"; public static String ROLE_SPRING_ADMIN_ID = "-1"; - public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN"; + public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN"; + + public static Role getRole(String tenantId, String displayName) { + Role role = null; + + String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName); + role = AuthorizationStore.getRoleByName(roleName, tenantId); + + return role; + } + + public static Role getRole(EntityManager em, String tenantId, String displayName) { + Role role = null; + + String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName); + role = AuthorizationStore.getRoleByName(em, roleName, tenantId); + + return role; + } + + + public static Role createRole(String tenantId, String name, String description) { + return createRole(tenantId, name, description, false /* mutable by default */); + } + + public static Role createRole(String tenantId, String name, String description, boolean immutable) { + Role role = new Role(); + + role.setCreatedAtItem(new Date()); + role.setDisplayName(name); + String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, name); + role.setRoleName(roleName); + String id = UUID.randomUUID().toString(); //FIXME: The qualified role name should be unique enough to use as an ID/key + role.setCsid(id); + role.setDescription(description); + role.setTenantId(tenantId); + if (immutable == true) { + role.setMetadataProtection(RoleClient.IMMUTABLE); + role.setPermsProtection(RoleClient.IMMUTABLE); + } + + return role; + } + + /** + * Add permission to the Spring Security tables + * with assumption that resource is of type URI + * @param permission configuration + */ + public static void addPermissionsForUri(Permission perm, + PermissionRole permRole) throws PermissionException { + // + // First check the integrity of the incoming arguments. + // + if (!perm.getCsid().equals(permRole.getPermission().get(0).getPermissionId())) { + throw new IllegalArgumentException("permission ids do not" + + " match for role=" + permRole.getRole().get(0).getRoleName() + + " with permissionId=" + permRole.getPermission().get(0).getPermissionId() + + " for permission with csid=" + perm.getCsid()); + } + + List principals = new ArrayList(); + for (RoleValue roleValue : permRole.getRole()) { + principals.add(roleValue.getRoleName()); + } + List permActions = perm.getAction(); + for (PermissionAction permAction : permActions) { + try { + CSpaceAction action = URIResourceImpl.getAction(permAction.getName()); + URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(), + perm.getResourceName(), action); + boolean grant = perm.getEffect().equals(EffectType.PERMIT) ? true : false; + AuthZ.get().addPermissions(uriRes, principals.toArray(new String[0]), grant);//CSPACE-4967 + } catch (PermissionException e) { + // + // Only throw the exception if it is *not* an already-exists exception + // + if (e.getCause() instanceof AlreadyExistsException == false) { + throw e; + } + } + } + } + + private static Connection getConnection() throws NamingException, SQLException { + return JDBCTools.getConnection(JDBCTools.CSPACE_REPOSITORY_NAME); + } + + /* + * Spring security seems to require that all of our role names start + * with the ROLE_PREFIX string. + */ + public static String getQualifiedRoleName(String tenantId, String name) { + String result = name; + + String qualifiedName = ROLE_PREFIX + tenantId.toUpperCase() + "_" + name.toUpperCase(); + if (name.equals(qualifiedName) == false) { + result = qualifiedName; + } + + return result; + } + + private static ActionGroup getActionGroup(String actionGroupStr) { + ActionGroup result = null; + + if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_CRUDL_NAME)) { + result = ACTIONGROUP_CRUDL; + } else if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_RL_NAME)) { + result = ACTIONGROUP_RL; + } + + return result; + } + + public static Permission createPermission(String tenantId, + String resourceName, + String description, + String actionGroupStr) { + Permission result = null; + + ActionGroup actionGroup = getActionGroup(actionGroupStr); + result = createPermission(tenantId, resourceName, description, actionGroup); + + return result; + } + + private static Permission createPermission(String tenantId, + String resourceName, + String description, + ActionGroup actionGroup) { + // String id = UUID.randomUUID().toString(); //FIXME: Could this be something like a refname instead of a UUID? + String id = tenantId + + "-" + resourceName + + "-" + actionGroup.name; + Permission perm = new Permission(); + perm.setCsid(id); + perm.setDescription(description); + perm.setCreatedAtItem(new Date()); + perm.setResourceName(resourceName.toLowerCase().trim()); + perm.setEffect(EffectType.PERMIT); + perm.setTenantId(tenantId); + + perm.setActionGroup(actionGroup.name); + ArrayList pas = new ArrayList(); + perm.setAction(pas); + for (ActionType actionType : actionGroup.actions) { + PermissionAction permAction = createPermissionAction(perm, actionType); + pas.add(permAction); + } + + return perm; + } + + private static Permission createWorkflowPermission(TenantBindingType tenantBinding, + ServiceBindingType serviceBinding, + TransitionDef transitionDef, + ActionGroup actionGroup) + { + Permission result = null; + String workFlowServiceSuffix; + String transitionName; + if (transitionDef != null) { + transitionName = transitionDef.getName(); + workFlowServiceSuffix = WorkflowClient.SERVICE_AUTHZ_SUFFIX; + } else { + transitionName = ""; //since the transitionDef was null, we're assuming that this is the base workflow permission to be created + workFlowServiceSuffix = WorkflowClient.SERVICE_PATH; + } + + String tenantId = tenantBinding.getId(); + String resourceName = "/" + + serviceBinding.getName().toLowerCase().trim() + + workFlowServiceSuffix + + transitionName; + String description = "A generated workflow permission for actiongroup " + actionGroup.name; + result = createPermission(tenantId, resourceName, description, actionGroup); + + if (logger.isDebugEnabled() == true) { + logger.debug("Generated a workflow permission: " + + result.getResourceName() + + ":" + transitionName + + ":" + "tenant id=" + result.getTenantId() + + ":" + actionGroup.name); + } + + return result; + } + + private static PermissionRole createPermissionRole(EntityManager em, + Permission permission, + Role role, + boolean enforceTenancy) throws Exception + { + PermissionRole permRole = new PermissionRole(); + // Check to see if the tenant ID of the permission and the tenant ID of the role match + boolean tenantIdsMatch = role.getTenantId().equalsIgnoreCase(permission.getTenantId()); + if (tenantIdsMatch == false && enforceTenancy == false) { + tenantIdsMatch = true; // If we don't need to enforce tenancy then we'll just consider them matched. + } + + if (tenantIdsMatch == true) { + permRole.setSubject(SubjectType.ROLE); + // + // Set of the permission value list of the permrole + // + List permValues = new ArrayList(); + PermissionValue permValue = new PermissionValue(); + permValue.setPermissionId(permission.getCsid()); + permValue.setResourceName(permission.getResourceName().toLowerCase()); + permValue.setActionGroup(permission.getActionGroup()); + permValues.add(permValue); + permRole.setPermission(permValues); + // + // Set of the role value list of the permrole + // + List roleValues = new ArrayList(); + RoleValue rv = new RoleValue(); + // This needs to use the qualified name, not the display name + rv.setRoleName(role.getRoleName()); + rv.setRoleId(role.getCsid()); + roleValues.add(rv); + permRole.setRole(roleValues); + } else { + String errMsg = "The tenant ID of the role: " + role.getTenantId() + + " did not match the tenant ID of the permission: " + permission.getTenantId(); + throw new Exception(errMsg); + } + + return permRole; + } + + + /* + * FIXME: REM - This method is way too big -over 300 lines! We need to break it up into + * smaller, discrete, sub-methods. + */ + public static void createDefaultAccounts(TenantBindingConfigReaderImpl tenantBindingConfigReader) { + if (logger.isDebugEnabled()) { + logger.debug("ServiceMain.createDefaultAccounts starting..."); + } + + Hashtable tenantBindings = + tenantBindingConfigReader.getTenantBindings(); + Hashtable tenantInfo = new Hashtable(); + for (TenantBindingType tenantBinding : tenantBindings.values()) { + String tId = tenantBinding.getId(); + String tName = tenantBinding.getName(); + tenantInfo.put(tId, tName); + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts found configured tenant id: "+tId+" name: "+tName); + } + } + Connection conn = null; + PreparedStatement pstmt = null; + Statement stmt = null; + // TODO - need to put in tests for existence first. + // We could just look for the accounts per tenant up front, and assume that + // the rest is there if the accounts are. + // Could add a sql script to remove these if need be - Spring only does roles, + // and we're not touching that, so we could safely toss the + // accounts, users, account-tenants, account-roles, and start over. + try { + conn = getConnection(); + // First find or create the tenants + String queryTenantSQL = + "SELECT id,name FROM tenants"; + stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(queryTenantSQL); + ArrayList existingTenants = new ArrayList(); + while (rs.next()) { + String tId = rs.getString("id"); + String tName = rs.getString("name"); + if(tenantInfo.containsKey(tId)) { + existingTenants.add(tId); + if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) { + logger.warn("Configured name for tenant: " + +tId+" in repository: "+tName + +" does not match config'd name: "+ tenantInfo.get(tId)); + } + } + } + rs.close(); + + String insertTenantSQL = + "INSERT INTO tenants (id,name,created_at) VALUES (?,?, now())"; + pstmt = conn.prepareStatement(insertTenantSQL); // create a statement + for(String tId : tenantInfo.keySet()) { + if(existingTenants.contains(tId)) { + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts: tenant exists (skipping): " + +tenantInfo.get(tId)); + } + continue; + } + pstmt.setString(1, tId); // set id param + pstmt.setString(2, tenantInfo.get(tId)); // set name param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts adding entry for tenant: "+tId); + } + pstmt.executeUpdate(); + } + pstmt.close(); + // Second find or create the users + String queryUserSQL = + "SELECT username FROM users WHERE username LIKE '" + +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '" + +TENANT_READER_ACCT_PREFIX+"%'"; + rs = stmt.executeQuery(queryUserSQL); + ArrayList usersInRepo = new ArrayList(); + while (rs.next()) { + String uName = rs.getString("username"); + usersInRepo.add(uName); + } + rs.close(); + String insertUserSQL = + "INSERT INTO users (username,passwd, created_at)" + +" VALUES (?,?, now())"; + pstmt = conn.prepareStatement(insertUserSQL); // create a statement + for(String tName : tenantInfo.values()) { + String adminAcctName = getDefaultAdminUserID(tName); + if(!usersInRepo.contains(adminAcctName)) { + String secEncPasswd = SecurityUtils.createPasswordHash( + adminAcctName, DEFAULT_ADMIN_PASSWORD); + pstmt.setString(1, adminAcctName); // set username param + pstmt.setString(2, secEncPasswd); // set passwd param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts adding user: " + +adminAcctName+" for tenant: "+tName); + } + pstmt.executeUpdate(); + } else if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts: user: "+adminAcctName + +" already exists - skipping."); + } + + + String readerAcctName = getDefaultReaderUserID(tName); + if(!usersInRepo.contains(readerAcctName)) { + String secEncPasswd = SecurityUtils.createPasswordHash( + readerAcctName, DEFAULT_READER_PASSWORD); + pstmt.setString(1, readerAcctName); // set username param + pstmt.setString(2, secEncPasswd); // set passwd param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts adding user: " + +readerAcctName+" for tenant: "+tName); + } + pstmt.executeUpdate(); + } else if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts: user: "+readerAcctName + +" already exists - skipping."); + } + } + pstmt.close(); + // Third, create the accounts. Assume that if the users were already there, + // then the accounts were as well + String insertAccountSQL = + "INSERT INTO accounts_common " + + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) " + + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())"; + Hashtable tenantAdminAcctCSIDs = new Hashtable(); + Hashtable tenantReaderAcctCSIDs = new Hashtable(); + pstmt = conn.prepareStatement(insertAccountSQL); // create a statement + for(String tId : tenantInfo.keySet()) { + String tName = tenantInfo.get(tId); + String adminCSID = UUID.randomUUID().toString(); + tenantAdminAcctCSIDs.put(tId, adminCSID); + String adminAcctName = getDefaultAdminUserID(tName); + if(!usersInRepo.contains(adminAcctName)) { + pstmt.setString(1, adminCSID); // set csid param + pstmt.setString(2, adminAcctName); // set email param (bogus) + pstmt.setString(3, adminAcctName); // set userid param + pstmt.setString(4, "Administrator");// set screen name param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts adding account: " + +adminAcctName+" for tenant: "+tName); + } + pstmt.executeUpdate(); + } else if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts: user: "+adminAcctName + +" already exists - skipping account generation."); + } + + String readerCSID = UUID.randomUUID().toString(); + tenantReaderAcctCSIDs.put(tId, readerCSID); + String readerAcctName = getDefaultReaderUserID(tName); + if(!usersInRepo.contains(readerAcctName)) { + pstmt.setString(1, readerCSID); // set csid param + pstmt.setString(2, readerAcctName); // set email param (bogus) + pstmt.setString(3, readerAcctName); // set userid param + pstmt.setString(4, "Reader"); // set screen name param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts adding account: " + +readerAcctName+" for tenant: "+tName); + } + pstmt.executeUpdate(); + } else if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts: user: "+readerAcctName + +" already exists - skipping account creation."); + } + } + pstmt.close(); + // Fourth, bind accounts to tenants. Assume that if the users were already there, + // then the accounts were bound to tenants correctly + String insertAccountTenantSQL; + DatabaseProductType databaseProductType = JDBCTools.getDatabaseProductType(); + if (databaseProductType == DatabaseProductType.MYSQL) { + insertAccountTenantSQL = + "INSERT INTO accounts_tenants (TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) " + + " VALUES(?, ?)"; + } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { + insertAccountTenantSQL = + "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) " + + " VALUES(nextval('hibernate_sequence'), ?, ?)"; + } else { + throw new Exception("Unrecognized database system."); + } + pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement + for(String tId : tenantInfo.keySet()) { + String tName = tenantInfo.get(tId); + if(!usersInRepo.contains(getDefaultAdminUserID(tName))) { + String adminAcct = tenantAdminAcctCSIDs.get(tId); + pstmt.setString(1, adminAcct); // set acct CSID param + pstmt.setString(2, tId); // set tenant_id param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account id: " + +adminAcct+" to tenant id: "+tId); + } + pstmt.executeUpdate(); + } + if(!usersInRepo.contains(getDefaultReaderUserID(tName))) { + String readerAcct = tenantReaderAcctCSIDs.get(tId); + pstmt.setString(1, readerAcct); // set acct CSID param + pstmt.setString(2, tId); // set tenant_id param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account id: " + +readerAcct+" to tenant id: "+tId); + } + pstmt.executeUpdate(); + } + } + pstmt.close(); + // Fifth, fetch and save the default roles + String springAdminRoleCSID = null; + String querySpringRole = + "SELECT csid from roles WHERE rolename='"+SPRING_ADMIN_ROLE+"'"; + rs = stmt.executeQuery(querySpringRole); + if(rs.next()) { + springAdminRoleCSID = rs.getString(1); + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts found Spring Admin role: " + +springAdminRoleCSID); + } + } else { + String insertSpringAdminRoleSQL = + "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) " + + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')"; + stmt.executeUpdate(insertSpringAdminRoleSQL); + springAdminRoleCSID = "-1"; + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts CREATED Spring Admin role: " + +springAdminRoleCSID); + } + } + rs.close(); + String getRoleCSIDSql = + "SELECT csid from roles WHERE tenant_id=? and rolename=?"; + pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement + rs = null; + Hashtable tenantAdminRoleCSIDs = new Hashtable(); + Hashtable tenantReaderRoleCSIDs = new Hashtable(); + for(String tId : tenantInfo.keySet()) { + pstmt.setString(1, tId); // set tenant_id param + pstmt.setString(2, getDefaultAdminRole(tId)); // set rolename param + rs = pstmt.executeQuery(); + // extract data from the ResultSet + if(!rs.next()) { + throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId) + +" for tenant id: "+tId+" in roles!"); + } + String tenantAdminRoleCSID = rs.getString(1); + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts found role: " + +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID + +") for tenant id: "+tId); + } + tenantAdminRoleCSIDs.put(tId, tenantAdminRoleCSID); + pstmt.setString(1, tId); // set tenant_id param + pstmt.setString(2, getDefaultReaderRole(tId)); // set rolename param + rs.close(); + rs = pstmt.executeQuery(); + // extract data from the ResultSet + if(!rs.next()) { + throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId) + +" for tenant id: "+tId+" in roles!"); + } + String tenantReaderRoleCSID = rs.getString(1); + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts found role: " + +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID + +") for tenant id: "+tId); + } + tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID); + rs.close(); + } + pstmt.close(); + // Sixth, bind the accounts to roles. If the users already existed, + // we'll assume they were set up correctly. + String insertAccountRoleSQL; + if (databaseProductType == DatabaseProductType.MYSQL) { + insertAccountRoleSQL = + "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)" + +" VALUES(?, ?, ?, ?, now())"; + } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { + insertAccountRoleSQL = + "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)" + +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())"; + } else { + throw new Exception("Unrecognized database system."); + } + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n" + +insertAccountRoleSQL); + } + pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement + for(String tId : tenantInfo.keySet()) { + String adminUserId = getDefaultAdminUserID(tenantInfo.get(tId)); + if(!usersInRepo.contains(adminUserId)) { + String adminAcct = tenantAdminAcctCSIDs.get(tId); + String adminRoleId = tenantAdminRoleCSIDs.get(tId); + pstmt.setString(1, adminAcct); // set acct CSID param + pstmt.setString(2, adminUserId); // set user_id param + pstmt.setString(3, adminRoleId); // set role_id param + pstmt.setString(4, getDefaultAdminRole(tId)); // set rolename param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account: " + +adminUserId+" to Admin role("+adminRoleId + +") for tenant id: "+tId); + } + pstmt.executeUpdate(); + // Now add the Spring Admin Role to the admin accounts + pstmt.setString(3, springAdminRoleCSID); // set role_id param + pstmt.setString(4, SPRING_ADMIN_ROLE); // set rolename param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account: " + +adminUserId+" to Spring Admin role: "+springAdminRoleCSID); + } + pstmt.executeUpdate(); + } + String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId)); + if(!usersInRepo.contains(readerUserId)) { + String readerAcct = tenantReaderAcctCSIDs.get(tId); + String readerRoleId = tenantReaderRoleCSIDs.get(tId); + pstmt.setString(1, readerAcct); // set acct CSID param + pstmt.setString(2, readerUserId); // set user_id param + pstmt.setString(3, readerRoleId); // set role_id param + pstmt.setString(4, getDefaultReaderRole(tId)); // set rolename param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account: " + +readerUserId+" to Reader role("+readerRoleId + +") for tenant id: "+tId); + } + pstmt.executeUpdate(); + } + } + pstmt.close(); + stmt.close(); + } catch (RuntimeException rte) { + if (logger.isDebugEnabled()) { + logger.debug("Exception in createDefaultAccounts: "+ + rte.getLocalizedMessage()); + logger.debug(rte.getStackTrace().toString()); + } + throw rte; + } catch (SQLException sqle) { + // SQLExceptions can be chained. We have at least one exception, so + // set up a loop to make sure we let the user know about all of them + // if there happens to be more than one. + if (logger.isDebugEnabled()) { + SQLException tempException = sqle; + while (null != tempException) { + logger.debug("SQL Exception: " + sqle.getLocalizedMessage()); + tempException = tempException.getNextException(); + } + logger.debug(sqle.getStackTrace().toString()); + } + throw new RuntimeException("SQL problem in createDefaultAccounts: ", sqle); + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Exception in createDefaultAccounts: "+ + e.getLocalizedMessage()); + } + } finally { + try { + if(conn!=null) + conn.close(); + if(pstmt!=null) + pstmt.close(); + if(stmt!=null) + stmt.close(); + } catch (SQLException sqle) { + if (logger.isDebugEnabled()) { + logger.debug("SQL Exception closing statement/connection: " + + sqle.getLocalizedMessage()); + } + } + } + } + + private static String getDefaultAdminRole(String tenantId) { + return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX; + } + + private static String getDefaultReaderRole(String tenantId) { + return ROLE_PREFIX+tenantId+TENANT_READER_ROLE_SUFFIX; + } + + private static String getDefaultAdminUserID(String tenantName) { + return TENANT_ADMIN_ACCT_PREFIX+tenantName; + } + + private static String getDefaultReaderUserID(String tenantName) { + return TENANT_READER_ACCT_PREFIX+tenantName; + } + + static public PermissionAction createPermissionAction(Permission perm, + ActionType actionType) { + PermissionAction pa = new PermissionAction(); + + CSpaceAction action = URIResourceImpl.getAction(actionType); + URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(), + perm.getResourceName(), action); + pa.setName(actionType); + pa.setObjectIdentity(uriRes.getHashedId().toString()); + pa.setObjectIdentityResource(uriRes.getId()); + + return pa; + } + + static public PermissionAction update(Permission perm, PermissionAction permAction) { + PermissionAction pa = new PermissionAction(); + + CSpaceAction action = URIResourceImpl.getAction(permAction.getName()); + URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(), + perm.getResourceName(), action); + pa.setObjectIdentity(uriRes.getHashedId().toString()); + pa.setObjectIdentityResource(uriRes.getId()); + + return pa; + } + + private static TransitionDefList getTransitionDefList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) { + TransitionDefList result = null; + try { + String serviceObjectName = serviceBinding.getObject().getName(); + DocumentHandler docHandler = ServiceConfigUtils.createDocumentHandlerInstance( + tenantBinding, serviceBinding); + Lifecycle lifecycle = docHandler.getLifecycle(serviceObjectName); + if (lifecycle != null) { + result = lifecycle.getTransitionDefList(); + } + } catch (Exception e) { + // Ignore this exception and return an empty non-null TransitionDefList + } + + if (result == null) { + logger.warn("Could not retrieve a lifecycle transition definition list from: " + + serviceBinding.getName() + + " with tenant ID = " + + tenantBinding.getId()); + // return an empty list + result = new TransitionDefList(); + } else { + logger.debug("Successfully etrieved a lifecycle transition definition list from: " + + serviceBinding.getName() + + " with tenant ID = " + + tenantBinding.getId()); + } + + return result; + } + - public static void createDefaultPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) throws Exception ++ public static void createDefaultPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions + { + AuthZ.get().login(); //login to Spring Security manager + + EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT); + EntityManager em = null; + + try { + em = emf.createEntityManager(); + + Role superRole = AuthorizationCommon.getRole(em, ADMINISTRATOR_TENANT_ID, ROLE_ADMINISTRATOR); + Hashtable tenantBindings = + tenantBindingConfigReader.getTenantBindings(); + for (String tenantId : tenantBindings.keySet()) { + TenantBindingType tenantBinding = tenantBindings.get(tenantId); + Role adminRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_ADMINISTRATOR); + Role readonlyRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_READER); + for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) { - try { - em.getTransaction().begin(); - // - // For the default admin role, create the base workflow (aka, "/workflow" permissions for the service. - Permission baseAdminPerm = createWorkflowPermission(tenantBinding, serviceBinding, null, ACTIONGROUP_CRUDL); - persist(em, baseAdminPerm, adminRole, true); - // - // For the default read-only role, create the base workflow (aka, "/workflow" permissions for the service. - Permission baseReadonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, null, ACTIONGROUP_RL); - persist(em, baseReadonlyPerm, readonlyRole, true); - // - // Next, create a permission for each workflow transition supported by the service's document type. - // - TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding); - for (TransitionDef transitionDef : transitionDefList.getTransitionDef()) { ++ String prop = ServiceBindingUtils.getPropertyValue(serviceBinding, REFRESH_AUTZ_PROP); ++ if (prop == null ? true : Boolean.parseBoolean(prop)) { ++ try { ++ em.getTransaction().begin(); + // - // Create the permission for the admin role - Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_CRUDL); - persist(em, adminPerm, adminRole, true); ++ // For the default admin role, create the base workflow (aka, "/workflow" permissions for the service. ++ Permission baseAdminPerm = createWorkflowPermission(tenantBinding, serviceBinding, null, ACTIONGROUP_CRUDL); ++ persist(em, baseAdminPerm, adminRole, true); + // - // Create the permission for the read-only role - Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_RL); - - Profiler profiler = new Profiler(AuthorizationCommon.class, 1); - profiler.start("createDefaultPermissions started:" + readonlyPerm.getCsid()); - persist(em, readonlyPerm, readonlyRole, true); // Persist/store the permission and permrole records and related Spring Security info - profiler.stop(); - logger.debug("Finished full perm generation for " - + ":" + tenantBinding.getId() - + ":" + serviceBinding.getName() - + ":" + transitionDef.getName() - + ":" + ACTIONGROUP_RL - + ":" + profiler.getCumulativeTime()); - /* ++ // For the default read-only role, create the base workflow (aka, "/workflow" permissions for the service. ++ Permission baseReadonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, null, ACTIONGROUP_RL); ++ persist(em, baseReadonlyPerm, readonlyRole, true); + // - // Create the permission for the super-admin role. Note we use the same "adminPerm" instance we used for the "adminPermRole" instance ++ // Next, create a permission for each workflow transition supported by the service's document type. + // - persist(em, adminPerm, superRole, false); - */ ++ TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding); ++ for (TransitionDef transitionDef : transitionDefList.getTransitionDef()) { ++ // ++ // Create the permission for the admin role ++ Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_CRUDL); ++ persist(em, adminPerm, adminRole, true); ++ // ++ // Create the permission for the read-only role ++ Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_RL); ++ ++ Profiler profiler = new Profiler(AuthorizationCommon.class, 1); ++ profiler.start("createDefaultPermissions started:" + readonlyPerm.getCsid()); ++ persist(em, readonlyPerm, readonlyRole, true); // Persist/store the permission and permrole records and related Spring Security info ++ profiler.stop(); ++ logger.debug("Finished full perm generation for " ++ + ":" + tenantBinding.getId() ++ + ":" + serviceBinding.getName() ++ + ":" + transitionDef.getName() ++ + ":" + ACTIONGROUP_RL ++ + ":" + profiler.getCumulativeTime()); ++ /* ++ // ++ // Create the permission for the super-admin role. Note we use the same "adminPerm" instance we used for the "adminPermRole" instance ++ // ++ persist(em, adminPerm, superRole, false); ++ */ ++ } ++ em.getTransaction().commit(); ++ } catch (IllegalStateException e) { ++ logger.debug(e.getLocalizedMessage(), e); //We end up here if there is no document handler for the service -this is ok for some of the services. + } - em.getTransaction().commit(); - } catch (IllegalStateException e) { - logger.debug(e.getLocalizedMessage(), e); //We end up here if there is no document handler for the service -this is ok for some of the services. ++ } else { ++ logger.warn("AuthZ refresh service binding property is set to FALSE so default roles and permissions will NOT be refreshed."); + } + } + } + em.close(); + } catch (Exception e) { + if (em != null && em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + if (logger.isDebugEnabled()) { + logger.debug("Caught exception and rolling back permission creation: ", e); + } + throw e; + } finally { + if (em != null) { + JpaStorageUtils.releaseEntityManagerFactory(emf); + } + } + } + + private static PermissionRoleRel findPermRoleRel(EntityManager em, String permissionId, String RoleId) { + PermissionRoleRel result = null; + + try { + String whereClause = "where permissionId = :id and roleId = :roleId"; + HashMap params = new HashMap(); + params.put("id", permissionId); + params.put("roleId", RoleId); + + result = (PermissionRoleRel) JpaStorageUtils.getEntity(em, + PermissionRoleRel.class.getCanonicalName(), whereClause, params); + } catch (Exception e) { + //Do nothing. Will return null; + } + + return result; + } + + /* + * Persists the Permission, PermissionRoleRel, and Spring Security table entries all in one transaction + */ + private static void persist(EntityManager em, Permission permission, Role role, boolean enforceTenancy) throws Exception { + AuthorizationStore authzStore = new AuthorizationStore(); + // First persist the Permission record + authzStore.store(em, permission); + + // If the PermRoleRel doesn't already exists then relate the permission and the role in a new PermissionRole (the service payload) + // Create a PermissionRoleRel (the database relation table for the permission and role) + PermissionRoleRel permRoleRel = findPermRoleRel(em, permission.getCsid(), role.getCsid()); + if (permRoleRel == null) { + PermissionRole permRole = createPermissionRole(em, permission, role, enforceTenancy); + List permRoleRels = new ArrayList(); + PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels, false /*not for delete*/); + for (PermissionRoleRel prr : permRoleRels) { + authzStore.store(em, prr); + } + Profiler profiler = new Profiler(AuthorizationCommon.class, 2); + profiler.start(); + // Add a corresponding entry in the Spring Security Tables + addPermissionsForUri(permission, permRole); + profiler.stop(); + logger.debug("Finished full perm generation for " + + ":" + permission.getTenantId() + + ":" + permission.getResourceName() + + ":" + ACTIONGROUP_RL + + ":" + profiler.getCumulativeTime()); + } + + } } diff --cc services/common/src/main/java/org/collectionspace/services/common/context/ServiceBindingUtils.java index 9d6afc82d,934a90cac..58de69b16 --- a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceBindingUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceBindingUtils.java @@@ -3,17 -3,13 +3,16 @@@ package org.collectionspace.services.co import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import org.collectionspace.services.common.config.PropertyItemUtils; - import org.collectionspace.services.common.service.ObjectPartType; - import org.collectionspace.services.common.service.ServiceBindingType; - import org.collectionspace.services.common.service.ServiceObjectType; - import org.collectionspace.services.common.tenant.TenantBindingType; - import org.collectionspace.services.common.types.PropertyItemType; - import org.collectionspace.services.common.types.PropertyType; + import org.collectionspace.services.config.service.ObjectPartType; + import org.collectionspace.services.config.service.ServiceBindingType; + import org.collectionspace.services.config.service.ServiceObjectType; + import org.collectionspace.services.config.types.PropertyItemType; + import org.collectionspace.services.config.types.PropertyType; import org.collectionspace.services.nuxeo.util.NuxeoUtils; import org.nuxeo.ecm.core.api.ClientException; import org.nuxeo.ecm.core.api.DocumentModel; diff --cc services/common/src/main/java/org/collectionspace/services/common/workflow/service/nuxeo/WorkflowDocumentModelHandler.java index 59b334800,29f297b59..f4d12ae6e --- a/services/common/src/main/java/org/collectionspace/services/common/workflow/service/nuxeo/WorkflowDocumentModelHandler.java +++ b/services/common/src/main/java/org/collectionspace/services/common/workflow/service/nuxeo/WorkflowDocumentModelHandler.java @@@ -118,6 -113,6 +113,7 @@@ public class WorkflowDocumentModelHandl * @return an identifier for the transition required to * place the document in that workflow state. */ ++ @Deprecated private String getTransitionFromState(String state) { String result = TRANSITION_UNKNOWN; @@@ -126,11 -121,11 +122,11 @@@ // destination workflow state and the set of allowable state transitions. if (state.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_DELETED)) { -- result = TRANSITION_DELETE; -- } else if (state.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_APPROVED)) { -- result = TRANSITION_APPROVE; -- } else if (state.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_PROJECT)) { -- result = TRANSITION_UNDELETE; ++ result = WorkflowClient.WORKFLOWTRANSITION_DELETE; ++ } else if (state.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_ACTIVE)) { ++ result = WorkflowClient.WORKFLOWTRANSITION_UNDELETE; //FIXME, could also be transition WORKFLOWTRANSITION_UNLOCK ++ } else if (state.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_LOCKED)) { ++ result = WorkflowClient.WORKFLOWTRANSITION_LOCK; } else { logger.warn("An attempt was made to transition a document to an unknown workflow state = " + state); diff --cc services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/DocumentModelHandler.java index fd43e68ef,9fb971bd5..e9a2d8ebe --- 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 @@@ -71,8 -78,115 +78,116 @@@ public abstract class DocumentModelHand public final static String COLLECTIONSPACE_CORE_UPDATED_AT = "updatedAt"; public final static String COLLECTIONSPACE_CORE_CREATED_BY = "createdBy"; public final static String COLLECTIONSPACE_CORE_UPDATED_BY = "updatedBy"; + public final static String COLLECTIONSPACE_CORE_WORKFLOWSTATE = "workflowState"; + /* + * Map Nuxeo's life cycle object to our JAX-B based life cycle object + */ + private Lifecycle createCollectionSpaceLifecycle(org.nuxeo.ecm.core.lifecycle.LifeCycle nuxeoLifecyle) { + Lifecycle result = null; + + if (nuxeoLifecyle != null) { + // + // Copy the life cycle's name + result = new Lifecycle(); + result.setName(nuxeoLifecyle.getName()); + + // We currently support only one initial state, so take the first one from Nuxeo + Collection initialStateNames = nuxeoLifecyle.getInitialStateNames(); + result.setDefaultInitial(initialStateNames.iterator().next()); + + // Next, we copy the state and corresponding transition lists + StateList stateList = new StateList(); + List states = stateList.getState(); + Collection nuxeoStates = nuxeoLifecyle.getStates(); + for (org.nuxeo.ecm.core.lifecycle.LifeCycleState nuxeoState : nuxeoStates) { + State tempState = new State(); + tempState.setDescription(nuxeoState.getDescription()); + tempState.setInitial(nuxeoState.isInitial()); + tempState.setName(nuxeoState.getName()); + // Now get the list of transitions + TransitionList transitionList = new TransitionList(); + List transitions = transitionList.getTransition(); + Collection nuxeoTransitions = nuxeoState.getAllowedStateTransitions(); + for (String nuxeoTransition : nuxeoTransitions) { + transitions.add(nuxeoTransition); + } + tempState.setTransitionList(transitionList); + states.add(tempState); + } + result.setStateList(stateList); + + // Finally, we create the transition definitions + TransitionDefList transitionDefList = new TransitionDefList(); + List transitionDefs = transitionDefList.getTransitionDef(); + Collection nuxeoTransitionDefs = nuxeoLifecyle.getTransitions(); + for (org.nuxeo.ecm.core.lifecycle.LifeCycleTransition nuxeoTransitionDef : nuxeoTransitionDefs) { + TransitionDef tempTransitionDef = new TransitionDef(); + tempTransitionDef.setDescription(nuxeoTransitionDef.getDescription()); + tempTransitionDef.setDestinationState(nuxeoTransitionDef.getDestinationStateName()); + tempTransitionDef.setName(nuxeoTransitionDef.getName()); + transitionDefs.add(tempTransitionDef); + } + result.setTransitionDefList(transitionDefList); + } + + return result; + } + + /* + * Returns the the life cycle definition of the related Nuxeo document type for this handler. + * (non-Javadoc) + * @see org.collectionspace.services.common.document.DocumentHandler#getLifecycle() + */ + @Override + public Lifecycle getLifecycle() { + Lifecycle result = null; + + String docTypeName = null; + try { + docTypeName = this.getServiceContext().getDocumentType(); + result = getLifecycle(docTypeName); + } catch (Exception e) { + if (logger.isTraceEnabled() == true) { + logger.trace("Could not retrieve lifecycle definition for Nuxeo doctype: " + docTypeName); + } + } + + return result; + } + + /* + * Returns the the life cycle definition of the related Nuxeo document type for this handler. + * (non-Javadoc) + * @see org.collectionspace.services.common.document.DocumentHandler#getLifecycle(java.lang.String) + */ + @Override + public Lifecycle getLifecycle(String docTypeName) { + org.nuxeo.ecm.core.lifecycle.LifeCycle nuxeoLifecyle; + Lifecycle result = null; + + try { + LifeCycleService lifeCycleService = null; + try { + lifeCycleService = NXCore.getLifeCycleService(); + } catch (Exception e) { + e.printStackTrace(); + } + + String lifeCycleName; + lifeCycleName = lifeCycleService.getLifeCycleNameFor(docTypeName); + nuxeoLifecyle = lifeCycleService.getLifeCycleByName(lifeCycleName); + + result = createCollectionSpaceLifecycle(nuxeoLifecyle); + // result = (Lifecycle)FileTools.getJaxbObjectFromFile(Lifecycle.class, "default-lifecycle.xml"); + } catch (Exception e) { + // TODO Auto-generated catch block + logger.error("Could not retreive life cycle information for Nuxeo doctype: " + docTypeName, e); + } + + return result; + } + /* * We're using the "name" field of Nuxeo's DocumentModel to store * the CSID. diff --cc services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java index 2bb8aa96a,2bb8aa96a..113ea8fe6 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java @@@ -17,7 -17,7 +17,6 @@@ */ package org.collectionspace.services.nuxeo.client.java; --import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; diff --cc services/dimension/client/src/main/java/org/collectionspace/services/client/DimensionProxy.java index f8d729dc9,f8d729dc9..b3a848674 --- a/services/dimension/client/src/main/java/org/collectionspace/services/client/DimensionProxy.java +++ b/services/dimension/client/src/main/java/org/collectionspace/services/client/DimensionProxy.java @@@ -25,12 -25,12 +25,12 @@@ public interface DimensionProxy extend @GET @Produces({"application/xml"}) ClientResponse readIncludeDeleted( -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @Override @GET @Produces({"application/xml"}) ClientResponse keywordSearchIncludeDeleted( @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); } diff --cc services/imports/service/src/main/java/org/collectionspace/services/imports/ImportsResource.java index 8fe6b217f,75109b400..b55710945 --- a/services/imports/service/src/main/java/org/collectionspace/services/imports/ImportsResource.java +++ b/services/imports/service/src/main/java/org/collectionspace/services/imports/ImportsResource.java @@@ -35,14 -32,12 +35,14 @@@ import org.collectionspace.services.com import org.collectionspace.services.common.api.Tools; import org.collectionspace.services.common.api.ZipTools; import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.MultipartServiceContextFactory; +import org.collectionspace.services.common.context.ServiceContextFactory; - import org.collectionspace.services.common.tenant.RepositoryDomainType; - import org.collectionspace.services.common.tenant.TenantBindingType; + import org.collectionspace.services.config.tenant.RepositoryDomainType; + import org.collectionspace.services.config.tenant.TenantBindingType; -import org.collectionspace.authentication.AuthN; - +import org.collectionspace.services.imports.ImportsCommon; import org.collectionspace.services.imports.nuxeo.ImportCommand; import org.collectionspace.services.nuxeo.util.NuxeoUtils; + import org.jboss.resteasy.plugins.providers.multipart.InputPart; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput; import org.xml.sax.InputSource; diff --cc services/imports/service/src/main/java/org/collectionspace/services/imports/nuxeo/ImportCommand.java index 255ba79f7,37b23919e..11f2cb54a --- a/services/imports/service/src/main/java/org/collectionspace/services/imports/nuxeo/ImportCommand.java +++ b/services/imports/service/src/main/java/org/collectionspace/services/imports/nuxeo/ImportCommand.java @@@ -1,120 -1,57 +1,116 @@@ -package org.collectionspace.services.imports.nuxeo; - -import java.io.File; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.collectionspace.services.nuxeo.client.java.NuxeoClientEmbedded; -import org.collectionspace.services.nuxeo.client.java.NuxeoConnectorEmbedded; -import org.nuxeo.ecm.core.api.repository.RepositoryInstance; -import org.nuxeo.ecm.core.io.DocumentPipe; -import org.nuxeo.ecm.core.io.DocumentReader; -import org.nuxeo.ecm.core.io.DocumentWriter; -import org.nuxeo.ecm.core.io.impl.DocumentPipeImpl; -import org.nuxeo.ecm.core.io.impl.plugins.DocumentModelWriter; -// we use our own override of this: import org.nuxeo.ecm.core.io.impl.plugins.XMLDirectoryReader; - -// based loosely on package org.nuxeo.ecm.shell.commands.io.ImportCommand; -public class ImportCommand { - private static final Log logger = LogFactory.getLog(ImportCommand.class); - - public String run(String src, String dest) throws Exception { - File file = new File(src); - ///cspace way of configuring client and auth: - NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient(); - RepositoryInstance repoSession = client.openRepository(); - try { - return importTree(repoSession, file, dest); - } finally { -// repository.close(); - client.releaseRepository(repoSession); - } - } - - String importTree(RepositoryInstance repository, File file, String toPath) throws Exception { - DocumentReader reader = null; - DocumentWriter writer = null; - String dump = "NO RESULTS"; - try { - System.out.println("importTree reading file: "+file+(file!=null ? " exists? "+file.exists() : " file param is null")); - reader = new LoggedXMLDirectoryReader(file); //our overload of XMLDirectoryReader. - writer = new DocumentModelWriter(repository, toPath, 10); - DocumentPipe pipe = new DocumentPipeImpl(10); - // pipe.addTransformer(transformer); - pipe.setReader(reader); - pipe.setWriter(writer); - pipe.run(); - } finally { - if (reader != null) { - reader.close(); - dump = ((LoggedXMLDirectoryReader)reader).report(); - } - if (writer != null) { - writer.close(); - } - } - return dump; - } +package org.collectionspace.services.imports.nuxeo; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeSet; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; - import org.collectionspace.services.client.PoxPayloadIn; - import org.collectionspace.services.client.PoxPayloadOut; - import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.nuxeo.client.java.NuxeoClientEmbedded; +import org.collectionspace.services.nuxeo.client.java.NuxeoConnectorEmbedded; - import org.collectionspace.services.nuxeo.util.NuxeoUtils; +import org.nuxeo.ecm.core.api.DocumentModel; +import org.nuxeo.ecm.core.api.DocumentRef; +import org.nuxeo.ecm.core.api.repository.RepositoryInstance; +import org.nuxeo.ecm.core.io.DocumentPipe; +import org.nuxeo.ecm.core.io.DocumentReader; +import org.nuxeo.ecm.core.io.DocumentTranslationMap; +import org.nuxeo.ecm.core.io.DocumentWriter; +import org.nuxeo.ecm.core.io.impl.DocumentPipeImpl; +import org.nuxeo.ecm.core.io.impl.plugins.DocumentModelWriter; +// we use our own override of this: import org.nuxeo.ecm.core.io.impl.plugins.XMLDirectoryReader; + +// based loosely on package org.nuxeo.ecm.shell.commands.io.ImportCommand; +public class ImportCommand { + private static final Log logger = LogFactory.getLog(ImportCommand.class); + + public String run(String src, String dest) throws Exception { + File file = new File(src); + ///cspace way of configuring client and auth: + NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient(); + RepositoryInstance repoSession = client.openRepository(); + try { + return importTree(repoSession, file, dest); + } catch (Exception e) { + throw e; + } finally { +// repository.close(); + client.releaseRepository(repoSession); + } + } + + String importTree(RepositoryInstance repoSession, File file, String toPath) throws Exception { + DocumentReader reader = null; + DocumentWriter writer = null; + DocumentModel docModel = null; + DocumentRef keyDocRef, valueDocRef; + String docType; + StringBuffer dump = new StringBuffer(); + Map recordsImportedForDocType = new HashMap(); + Integer numRecordsImportedForDocType = new Integer(0); + int totalRecordsImported = 0; + try { + System.out.println("importTree reading file: "+file+(file!=null ? " exists? "+file.exists() : " file param is null")); + reader = new LoggedXMLDirectoryReader(file); //our overload of XMLDirectoryReader. + writer = new DocumentModelWriter(repoSession, toPath, 10); + DocumentPipe pipe = new DocumentPipeImpl(10); + // pipe.addTransformer(transformer); + pipe.setReader(reader); + pipe.setWriter(writer); + // FIXME: pipe.run() appears to return at least one type + // of Exception that is logged but not thrown; this is a + // potential workaround + DocumentTranslationMap dtm = pipe.run(); + Map documentRefs = dtm.getDocRefMap(); + dump.append(""); + for (Map.Entry entry: documentRefs.entrySet()) { + keyDocRef = (DocumentRef) entry.getKey(); + valueDocRef = (DocumentRef) entry.getValue(); + if (keyDocRef == null || valueDocRef == null) { + continue; + } + // System.out.println("value="+entry.getValue()); + // System.out.println("key="+entry.getKey()); + + docModel = repoSession.getDocument((DocumentRef) entry.getValue()); + // System.out.println("value doctype="+docModel.getDocumentType().toString()); + + dump.append(""); + docModel = repoSession.getDocument(valueDocRef); + docType = docModel.getDocumentType().getName(); + // System.out.println(docType); + dump.append(""+docType+""); + dump.append(""+keyDocRef.toString()+""); + dump.append(""); + // System.out.println(dump.toString()); + if (recordsImportedForDocType.containsKey(docType)) { + numRecordsImportedForDocType = (Integer) recordsImportedForDocType.get(docType); + numRecordsImportedForDocType = Integer.valueOf(numRecordsImportedForDocType.intValue() + 1); + recordsImportedForDocType.put(docType, numRecordsImportedForDocType); + } else { + recordsImportedForDocType.put(docType, 1); + } + totalRecordsImported++; + } + dump.append(""); + } catch (Exception e) { + throw e; + } finally { + dump.append(""+totalRecordsImported+""); + dump.append(""); + TreeSet keys = new TreeSet(recordsImportedForDocType.keySet()); + for (String key : keys) { + dump.append(""+key+""); + dump.append(""+recordsImportedForDocType.get(key).intValue()+""); + } + dump.append(""); + if (reader != null) { + dump.append(""+(((LoggedXMLDirectoryReader)reader).report())+""); + reader.close(); + } + if (writer != null) { + writer.close(); + } + } + return dump.toString(); + } } diff --cc services/imports/service/src/main/java/org/collectionspace/services/imports/nuxeo/LoggedXMLDirectoryReader.java index 125976ff2,36f0a3ebe..6d2ed5713 --- a/services/imports/service/src/main/java/org/collectionspace/services/imports/nuxeo/LoggedXMLDirectoryReader.java +++ b/services/imports/service/src/main/java/org/collectionspace/services/imports/nuxeo/LoggedXMLDirectoryReader.java @@@ -1,134 -1,134 +1,133 @@@ - package org.collectionspace.services.imports.nuxeo; - - import java.io.BufferedInputStream; - import java.io.File; - import java.io.FileFilter; - import java.io.FileInputStream; - import java.io.IOException; - import java.util.ArrayList; - import java.util.List; - - import org.dom4j.Document; - import org.dom4j.DocumentException; - import org.dom4j.io.SAXReader; - import org.nuxeo.common.utils.FileTreeIterator; - import org.nuxeo.common.utils.FileUtils; - import org.nuxeo.common.utils.Path; - import org.nuxeo.ecm.core.api.impl.blob.StreamingBlob; - import org.nuxeo.ecm.core.io.ExportConstants; - import org.nuxeo.ecm.core.io.ExportedDocument; - import org.nuxeo.ecm.core.io.impl.AbstractDocumentReader; - import org.nuxeo.ecm.core.io.impl.ExportedDocumentImpl; - import org.nuxeo.ecm.core.io.impl.plugins.XMLDirectoryReader; - import org.nuxeo.runtime.services.streaming.FileSource; - - public class LoggedXMLDirectoryReader extends AbstractDocumentReader { - - protected Document loadXML(File file) throws IOException { - String filename = file.getCanonicalPath(); - System.out.println("~~~~~~~~~~~~~~~~~~~ LoggedXMLDirectoryReader :: "+filename); - BufferedInputStream in = null; - try { - in = new BufferedInputStream(new FileInputStream(file)); - System.out.println("~~~~~~~~~~~~~~~~~~~ LoggedXMLDirectoryReader :: "+filename+" :: DONE"); - reportList.add("READ: "+filename); - return new SAXReader().read(in); - } catch (DocumentException e) { - IOException ioe = new IOException("Failed to read file document " - + file + ": " + e.getMessage()); - ioe.setStackTrace(e.getStackTrace()); - System.out.println("~~~~~~~~~~~~~~~~~~~ LoggedXMLDirectoryReader :: "+filename+" :: ERROR"); - reportList.add("ERROR: "+filename); - throw ioe; - } finally { - if (in != null) { - in.close(); - } - } - } - - private File source; - - private FileTreeIterator iterator; - - public LoggedXMLDirectoryReader(String sourcePath) { - this(new File(sourcePath)); - } - - public LoggedXMLDirectoryReader(File source) { - this.source = source; - iterator = new FileTreeIterator(source); - iterator.setFilter(new FileFilter() { - public boolean accept(File pathname) { - return pathname.isDirectory(); - } - }); - } - - public Object getSource() { - return source; - } - - public void setSource(File source) { - this.source = source; - } - - public void close() { - source = null; - iterator = null; - } - - private List reportList = new ArrayList(); - public String report(){ - StringBuffer result = new StringBuffer(); - for (String s: reportList){ - result.append(s).append("\r\n"); - } - return result.toString(); - } - - - @Override - public ExportedDocument read() throws IOException { - if (iterator.hasNext()) { - File dir = iterator.next(); - if (dir == null) { - return null; - } - // read document files - ExportedDocument xdoc = new ExportedDocumentImpl(); - for (File file : dir.listFiles()) { - if (file.isFile()) { - String name = file.getName(); - if (ExportConstants.DOCUMENT_FILE.equals(name)) { - Document doc = loadXML(file); - xdoc.setDocument(doc); - Path relPath = computeRelativePath(dir); - xdoc.setPath(relPath); - reportList.add(relPath.toString()); - } else if (name.endsWith(".xml")) { - xdoc.putDocument( - FileUtils.getFileNameNoExt(file.getName()), - loadXML(file)); - } else { // presume a blob - xdoc.putBlob(file.getName(), new StreamingBlob( - new FileSource(file))); - } - } - } - return xdoc; - } - return null; - } - - /*NXP-1688 Rux: the path was somehow left over when migrated from - core 1.3.4 to 1.4.0. Pull back.*/ - private Path computeRelativePath(File file) { - /*NXP-2507 Rux: preserve directory structure with slashes instead OS name separator*/ - String subPathS = - file.getAbsolutePath().substring(source.getAbsolutePath().length()); - subPathS = subPathS.replace(File.separatorChar, '/'); - return new Path(subPathS); - } - + package org.collectionspace.services.imports.nuxeo; + + import java.io.BufferedInputStream; + import java.io.File; + import java.io.FileFilter; + import java.io.FileInputStream; + import java.io.IOException; + import java.util.ArrayList; + import java.util.List; + + import org.dom4j.Document; + import org.dom4j.DocumentException; + import org.dom4j.io.SAXReader; + import org.nuxeo.common.utils.FileTreeIterator; + import org.nuxeo.common.utils.FileUtils; + import org.nuxeo.common.utils.Path; + import org.nuxeo.ecm.core.api.impl.blob.StreamingBlob; + import org.nuxeo.ecm.core.io.ExportConstants; + import org.nuxeo.ecm.core.io.ExportedDocument; + import org.nuxeo.ecm.core.io.impl.AbstractDocumentReader; + import org.nuxeo.ecm.core.io.impl.ExportedDocumentImpl; -import org.nuxeo.ecm.core.io.impl.plugins.XMLDirectoryReader; + import org.nuxeo.runtime.services.streaming.FileSource; + + public class LoggedXMLDirectoryReader extends AbstractDocumentReader { + + protected Document loadXML(File file) throws IOException { + String filename = file.getCanonicalPath(); + System.out.println("~~~~~~~~~~~~~~~~~~~ LoggedXMLDirectoryReader :: "+filename); + BufferedInputStream in = null; + try { + in = new BufferedInputStream(new FileInputStream(file)); + System.out.println("~~~~~~~~~~~~~~~~~~~ LoggedXMLDirectoryReader :: "+filename+" :: DONE"); + reportList.add("READ: "+filename); + return new SAXReader().read(in); + } catch (DocumentException e) { + IOException ioe = new IOException("Failed to read file document " + + file + ": " + e.getMessage()); + ioe.setStackTrace(e.getStackTrace()); + System.out.println("~~~~~~~~~~~~~~~~~~~ LoggedXMLDirectoryReader :: "+filename+" :: ERROR"); + reportList.add("ERROR: "+filename); + throw ioe; + } finally { + if (in != null) { + in.close(); + } + } + } + + private File source; + + private FileTreeIterator iterator; + + public LoggedXMLDirectoryReader(String sourcePath) { + this(new File(sourcePath)); + } + + public LoggedXMLDirectoryReader(File source) { + this.source = source; + iterator = new FileTreeIterator(source); + iterator.setFilter(new FileFilter() { + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + } + + public Object getSource() { + return source; + } + + public void setSource(File source) { + this.source = source; + } + + public void close() { + source = null; + iterator = null; + } + + private List reportList = new ArrayList(); + public String report(){ + StringBuffer result = new StringBuffer(); + for (String s: reportList){ + result.append(s).append("\r\n"); + } + return result.toString(); + } + + + @Override + public ExportedDocument read() throws IOException { + if (iterator.hasNext()) { + File dir = iterator.next(); + if (dir == null) { + return null; + } + // read document files + ExportedDocument xdoc = new ExportedDocumentImpl(); + for (File file : dir.listFiles()) { + if (file.isFile()) { + String name = file.getName(); + if (ExportConstants.DOCUMENT_FILE.equals(name)) { + Document doc = loadXML(file); + xdoc.setDocument(doc); + Path relPath = computeRelativePath(dir); + xdoc.setPath(relPath); + reportList.add(relPath.toString()); + } else if (name.endsWith(".xml")) { + xdoc.putDocument( + FileUtils.getFileNameNoExt(file.getName()), + loadXML(file)); + } else { // presume a blob + xdoc.putBlob(file.getName(), new StreamingBlob( + new FileSource(file))); + } + } + } + return xdoc; + } + return null; + } + + /*NXP-1688 Rux: the path was somehow left over when migrated from + core 1.3.4 to 1.4.0. Pull back.*/ + private Path computeRelativePath(File file) { + /*NXP-2507 Rux: preserve directory structure with slashes instead OS name separator*/ + String subPathS = + file.getAbsolutePath().substring(source.getAbsolutePath().length()); + subPathS = subPathS.replace(File.separatorChar, '/'); + return new Path(subPathS); + } + } diff --cc services/movement/client/src/main/java/org/collectionspace/services/client/MovementProxy.java index 3c8ed92ff,3c8ed92ff..3fc883d2a --- a/services/movement/client/src/main/java/org/collectionspace/services/client/MovementProxy.java +++ b/services/movement/client/src/main/java/org/collectionspace/services/client/MovementProxy.java @@@ -55,14 -55,14 +55,14 @@@ public interface MovementProxy extends @GET @Produces({"application/xml"}) ClientResponse readIncludeDeleted( -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @Override @GET @Produces({"application/xml"}) ClientResponse keywordSearchIncludeDeleted( @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @GET @Produces({"application/xml"}) diff --cc services/note/client/src/main/java/org/collectionspace/services/client/NoteProxy.java index f2402c629,f2402c629..d0669f1e8 --- a/services/note/client/src/main/java/org/collectionspace/services/client/NoteProxy.java +++ b/services/note/client/src/main/java/org/collectionspace/services/client/NoteProxy.java @@@ -31,14 -31,14 +31,14 @@@ public interface NoteProxy extends Coll @GET @Produces({"application/xml"}) ClientResponse readIncludeDeleted( -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @Override @GET @Produces({"application/xml"}) ClientResponse keywordSearchIncludeDeleted( @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); /* //(C)reate diff --cc services/relation/client/src/main/java/org/collectionspace/services/client/RelationProxy.java index e642644ec,e642644ec..eeb1cf73d --- a/services/relation/client/src/main/java/org/collectionspace/services/client/RelationProxy.java +++ b/services/relation/client/src/main/java/org/collectionspace/services/client/RelationProxy.java @@@ -28,14 -28,14 +28,14 @@@ public interface RelationProxy extends @GET @Produces({"application/xml"}) ClientResponse readIncludeDeleted( -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @Override @GET @Produces({"application/xml"}) ClientResponse keywordSearchIncludeDeleted( @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords, -- @QueryParam(WorkflowClient.WORKFLOW_QUERY_NONDELETED) String includeDeleted); ++ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState); @GET @Produces({"application/xml"}) diff --cc services/relation/service/src/main/java/org/collectionspace/services/relation/nuxeo/RelationDocumentModelHandler.java index b3614f2f9,0405bbb8e..a14a6294b --- a/services/relation/service/src/main/java/org/collectionspace/services/relation/nuxeo/RelationDocumentModelHandler.java +++ b/services/relation/service/src/main/java/org/collectionspace/services/relation/nuxeo/RelationDocumentModelHandler.java @@@ -29,38 -29,41 +29,34 @@@ import java.util.Iterator import org.collectionspace.services.client.PoxPayloadIn; import org.collectionspace.services.client.PoxPayloadOut; import org.collectionspace.services.common.ResourceBase; --import org.collectionspace.services.common.ResourceMap; import org.collectionspace.services.common.ServiceMain; import org.collectionspace.services.common.api.RefName; import org.collectionspace.services.common.api.Tools; - +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.ServiceBindingUtils; import org.collectionspace.services.common.document.DocumentNotFoundException; ++import org.collectionspace.services.common.document.DocumentWrapper; import org.collectionspace.services.common.document.InvalidDocumentException; import org.collectionspace.services.common.relation.RelationJAXBSchema; import org.collectionspace.services.common.relation.nuxeo.RelationConstants; -import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; -import org.collectionspace.services.common.context.ServiceBindingUtils; import org.collectionspace.services.common.context.ServiceContext; --import org.collectionspace.services.common.repository.RepositoryClient; --import org.collectionspace.services.common.repository.RepositoryClientFactory; - import org.collectionspace.services.common.service.ServiceBindingType; - import org.collectionspace.services.nuxeo.util.NuxeoUtils; - import org.collectionspace.services.relation.RelationsCommon; import org.collectionspace.services.relation.RelationsCommonList; import org.collectionspace.services.relation.RelationsCommonList.RelationListItem; ++import org.collectionspace.services.relation.RelationsDocListItem; // HACK HACK HACK import org.collectionspace.services.client.PersonAuthorityClient; import org.collectionspace.services.client.OrgAuthorityClient; import org.collectionspace.services.client.LocationAuthorityClient; -import org.collectionspace.services.client.PlaceAuthorityClient; import org.collectionspace.services.client.TaxonomyAuthorityClient; +import org.collectionspace.services.client.PlaceAuthorityClient; +import org.collectionspace.services.client.ConceptAuthorityClient; --import org.collectionspace.services.common.document.DocumentWrapper; - import org.collectionspace.services.jaxb.AbstractCommonList; + import org.collectionspace.services.config.service.ServiceBindingType; -import org.collectionspace.services.jaxb.AbstractCommonList; import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl; import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl; --import org.collectionspace.services.relation.RelationsDocListItem; - import org.nuxeo.ecm.core.api.ClientException; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; diff --cc services/workflow/client/src/test/java/org/collectionspace/services/client/test/WorkflowServiceTest.java index 387685ee4,387685ee4..44f115c50 --- a/services/workflow/client/src/test/java/org/collectionspace/services/client/test/WorkflowServiceTest.java +++ b/services/workflow/client/src/test/java/org/collectionspace/services/client/test/WorkflowServiceTest.java @@@ -105,7 -105,7 +105,7 @@@ public class WorkflowServiceTest extend @Override public void update(String testName) throws Exception { setupUpdate(); -- updateLifeCycleState(testName, knownResourceId, WorkflowClient.WORKFLOWSTATE_APPROVED); ++ updateLifeCycleState(testName, knownResourceId, WorkflowClient.WORKFLOWTRANSITION_DELETE, WorkflowClient.WORKFLOWSTATE_DELETED); } @Override