http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml index c592c31..a75e4b6 100644 --- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml +++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml @@ -312,6 +312,56 @@ under the License. </attributes> </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADerAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_ADerAttr" strategy="TABLE"/> + <table-generator name="SEQ_ADerAttr" pk-column-value="SEQ_ADerAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUDerAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_UDerAttr" strategy="TABLE"/> + <table-generator name="SEQ_UDerAttr" pk-column-value="SEQ_UDerAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGDerAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_GDerAttr" strategy="TABLE"/> + <table-generator name="SEQ_GDerAttr" pk-column-value="SEQ_GDerAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAVirAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_AVirAttr" strategy="TABLE"/> + <table-generator name="SEQ_AVirAttr" pk-column-value="SEQ_AVirAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_UVirAttr" strategy="TABLE"/> + <table-generator name="SEQ_UVirAttr" pk-column-value="SEQ_UVirAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_GVirAttr" strategy="TABLE"/> + <table-generator name="SEQ_GVirAttr" pk-column-value="SEQ_GVirAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.task.JPAAnyTemplate"> <attributes> <id name="id">
http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml b/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml index 746314c..6f83543 100644 --- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml +++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml @@ -360,6 +360,56 @@ under the License. </attributes> </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADerAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_ADerAttr" strategy="TABLE"/> + <table-generator name="SEQ_ADerAttr" pk-column-value="SEQ_ADerAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUDerAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_UDerAttr" strategy="TABLE"/> + <table-generator name="SEQ_UDerAttr" pk-column-value="SEQ_UDerAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGDerAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_GDerAttr" strategy="TABLE"/> + <table-generator name="SEQ_GDerAttr" pk-column-value="SEQ_GDerAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAVirAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_AVirAttr" strategy="TABLE"/> + <table-generator name="SEQ_AVirAttr" pk-column-value="SEQ_AVirAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_UVirAttr" strategy="TABLE"/> + <table-generator name="SEQ_UVirAttr" pk-column-value="SEQ_UVirAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttr"> + <attributes> + <id name="id"> + <generated-value generator="SEQ_GVirAttr" strategy="TABLE"/> + <table-generator name="SEQ_GVirAttr" pk-column-value="SEQ_GVirAttr" initial-value="1000"/> + </id> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.task.JPAAnyTemplate"> <attributes> <id name="id"> http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/VirAttrTest.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/VirAttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/VirAttrTest.java index e1ffc11..02815b8 100644 --- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/VirAttrTest.java +++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/VirAttrTest.java @@ -60,7 +60,7 @@ public class VirAttrTest extends AbstractTest { @Test public void findById() { - UVirAttr attribute = virAttrDAO.find(1000L, UVirAttr.class); + UVirAttr attribute = virAttrDAO.find(100L, UVirAttr.class); assertNotNull("did not find expected attribute schema", attribute); } @@ -104,7 +104,7 @@ public class VirAttrTest extends AbstractTest { @Test public void delete() { - UVirAttr attribute = virAttrDAO.find(1000L, UVirAttr.class); + UVirAttr attribute = virAttrDAO.find(100L, UVirAttr.class); String attributeSchemaName = attribute.getSchema().getKey(); virAttrDAO.delete(attribute.getKey(), UVirAttr.class); http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/AnyTypeTest.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/AnyTypeTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/AnyTypeTest.java index e6a919d..60ff041 100644 --- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/AnyTypeTest.java +++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/AnyTypeTest.java @@ -52,13 +52,8 @@ public class AnyTypeTest extends AbstractTest { anyTypeClassDAO.delete("other"); - try { anyTypeDAO.flush(); - } catch(Exception e) { - System.err.println("EEEEEEEEEEEE"); - e.printStackTrace(); - } - + userType = anyTypeDAO.findUser(); assertNotNull(userType); assertEquals(before, userType.getClasses().size() + 1); http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/persistence-jpa/src/test/resources/content.xml ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/test/resources/content.xml b/core/persistence-jpa/src/test/resources/content.xml index 8d2ef54..7c123a7 100644 --- a/core/persistence-jpa/src/test/resources/content.xml +++ b/core/persistence-jpa/src/test/resources/content.xml @@ -94,11 +94,11 @@ under the License. <!-- sample policies --> <Policy DTYPE="SyncPolicy" id="1" description="a sync policy" type="SYNC" - specification='{"userJavaRule":null,"groupJavaRule":null,"conflictResolutionAction":"IGNORE","userAltSearchSchemas":[],"groupAltSearchSchemas":[]}'/> + specification='{"conflictResolutionAction":"IGNORE","items":[]}'/> <Policy DTYPE="PasswordPolicy" id="2" description="a password policy" type="PASSWORD" specification='{"historyLength":1,"maxLength":0,"minLength":8,"nonAlphanumericRequired":false,"alphanumericRequired":false,"digitRequired":false,"lowercaseRequired":false,"uppercaseRequired":false,"mustStartWithDigit":false,"mustntStartWithDigit":false,"mustEndWithDigit":false,"mustntEndWithDigit":false,"mustStartWithNonAlpha":false,"mustStartWithAlpha":false,"mustntStartWithNonAlpha":false,"mustntStartWithAlpha":false,"mustEndWithNonAlpha":false,"mustEndWithAlpha":false,"mustntEndWithNonAlpha":false,"mustntEndWithAlpha":false,"wordsNotPermitted":[],"schemasNotPermitted":[],"prefixesNotPermitted":["notpermitted1","notpermitted2"],"suffixesNotPermitted":[],"allowNullPassword":true}'/> <Policy DTYPE="SyncPolicy" id="3" description="sync policy 2" type="SYNC" - specification='{"userJavaRule":null,"groupJavaRule":null,"conflictResolutionAction":"ALL","userAltSearchSchemas":["username","firstname"],"groupAltSearchSchemas":[]}'/> + specification='{"conflictResolutionAction":"ALL","items":[{"anyTypeKey":"USER","javaRule":null,"altSearchSchemas":["username","firstname"]}]}'/> <Policy DTYPE="PasswordPolicy" id="4" description="sample password policy" type="PASSWORD" specification='{"historyLength":0,"maxLength":0,"minLength":10,"nonAlphanumericRequired":false,"alphanumericRequired":false,"digitRequired":true,"lowercaseRequired":false,"uppercaseRequired":false,"mustStartWithDigit":false,"mustntStartWithDigit":false,"mustEndWithDigit":false,"mustntEndWithDigit":false,"mustStartWithNonAlpha":false,"mustStartWithAlpha":false,"mustntStartWithNonAlpha":false,"mustntStartWithAlpha":false,"mustEndWithNonAlpha":false,"mustEndWithAlpha":false,"mustntEndWithNonAlpha":false,"mustntEndWithAlpha":false,"wordsNotPermitted":[],"schemasNotPermitted":[],"prefixesNotPermitted":["notpermitted1","notpermitted2"],"suffixesNotPermitted":[], "allowNullPassword":true}'/> <Policy DTYPE="AccountPolicy" id="5" description="an account policy" type="ACCOUNT" @@ -106,11 +106,11 @@ under the License. <Policy DTYPE="AccountPolicy" id="6" description="sample account policy" type="ACCOUNT" specification='{"maxLength":0,"minLength":4,"pattern":null,"allUpperCase":false,"allLowerCase":false,"propagateSuspension":false,"maxAuthenticationAttempts":3,"wordsNotPermitted":[],"schemasNotPermitted":[],"prefixesNotPermitted":["notpermitted1","notpermitted2"],"suffixesNotPermitted":[]}'/> <Policy DTYPE="SyncPolicy" id="7" description="sync policy 1" type="SYNC" - specification='{"userJavaRule":null,"groupJavaRule":null,"conflictResolutionAction":"IGNORE","userAltSearchSchemas":[],"groupAltSearchSchemas":[]}'/> + specification='{"conflictResolutionAction":"IGNORE","items":[]}'/> <Policy DTYPE="PasswordPolicy" id="8" description="sample password policy" type="PASSWORD" specification='{"historyLength":0,"maxLength":0,"minLength":10,"nonAlphanumericRequired":true,"alphanumericRequired":false,"digitRequired":true,"lowercaseRequired":true,"uppercaseRequired":true,"mustStartWithDigit":true,"mustntStartWithDigit":false,"mustEndWithDigit":true,"mustntEndWithDigit":false,"mustStartWithNonAlpha":false,"mustStartWithAlpha":false,"mustntStartWithNonAlpha":false,"mustntStartWithAlpha":false,"mustEndWithNonAlpha":false,"mustEndWithAlpha":false,"mustntEndWithNonAlpha":false,"mustntEndWithAlpha":false,"wordsNotPermitted":[],"schemasNotPermitted":[],"prefixesNotPermitted":["notpermitted1","notpermitted2"],"suffixesNotPermitted":[],"allowNullPassword":false}'/> <Policy DTYPE="SyncPolicy" id="9" description="sync policy for java rule" type="SYNC" - specification='{"userJavaRule":null,"groupJavaRule":null,"conflictResolutionAction":"IGNORE","userAltSearchSchemas":[],"groupAltSearchSchemas":[]}'/> + specification='{"conflictResolutionAction":"IGNORE","items":[]}'/> <AnyTypeClass name="generic membership"/> @@ -307,6 +307,7 @@ under the License. <DerSchema name="noschema" expression="surname + ', ' + notfound" anyTypeClass_name="other"/> <VirSchema name="virtualdata" anyTypeClass_name="minimal user"/> + <VirSchema name="virtualReadOnly" READONLY="1" anyTypeClass_name="minimal user"/> <PlainSchema name="icon" type="String" anyTypeClass_name="minimal group" mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/> @@ -328,7 +329,7 @@ under the License. <VirSchema name="rvirtualdata" anyTypeClass_name="minimal group"/> - <DerSchema name="rderivedschema" expression="rderived_sx + '-' + rderived_dx"/> + <DerSchema name="rderivedschema" expression="rderived_sx + '-' + rderived_dx" anyTypeClass_name="minimal group"/> <PlainSchema name="subscriptionDate" type="Date" anyTypeClass_name="generic membership" mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0" @@ -412,9 +413,7 @@ under the License. <UPlainAttr id="126" owner_id="3" schema_name="type"/> <UPlainAttrValue id="37" attribute_id="126" stringValue="F"/> - <UVirAttr id="1000" schema_name="virtualdata" owner_id="3"/> - - <VirSchema name="virtualReadOnly" READONLY="1"/> + <UVirAttr id="100" schema_name="virtualdata" owner_id="3"/> <UDerAttr id="100" schema_name="cn" owner_id="3"/> <UDerAttr id="101" schema_name="cn" owner_id="1"/> @@ -446,13 +445,13 @@ under the License. <GPlainAttr id="995" owner_id="13" schema_name="title"/> <GPlainAttrValue attribute_id="995" id="95" stringValue="r13"/> - <GDerAttr id="1000" owner_id="1" schema_name="rderiveddata"/> + <GDerAttr id="100" owner_id="1" schema_name="rderiveddata"/> - <GDerAttr id="1001" owner_id="1" schema_name="displayProperty"/> + <GDerAttr id="101" owner_id="1" schema_name="displayProperty"/> - <GDerAttr id="1002" owner_id="4" schema_name="displayProperty"/> + <GDerAttr id="102" owner_id="4" schema_name="displayProperty"/> - <GDerAttr id="1003" owner_id="1" schema_name="rderToBePropagated"/> + <GDerAttr id="103" owner_id="1" schema_name="rderToBePropagated"/> <GVirAttr id="98" owner_id="4" schema_name="rvirtualdata"/> @@ -816,10 +815,10 @@ under the License. connObjectKey="1" password="0" purpose="BOTH"/> <MappingItem id="208" extAttrName="theirgroup" mapping_id="9" intAttrName="rderToBePropagated" intMappingType="GroupDerivedSchema" mandatoryCondition="false" - connObjectKey="0" password="0" purpose="BOTH"/> + connObjectKey="0" password="0" purpose="PROPAGATION"/> <MappingItem id="209" extAttrName="membership" mapping_id="9" intAttrName="mderToBePropagated" intMappingType="AnyDerivedSchema" mandatoryCondition="false" - connObjectKey="0" password="0" purpose="BOTH"/> + connObjectKey="0" password="0" purpose="PROPAGATION"/> <Provision id="10" resource_name="ws-target-resource-update-resetsynctoken" anyType_name="USER" objectClass="__ACCOUNT__" serializedSyncToken='{"value":null}'/> @@ -853,7 +852,7 @@ under the License. extAttrName="title" intAttrName="title" intMappingType="GroupPlainSchema" mandatoryCondition="false" purpose="BOTH"/> <MappingItem id="317" connObjectKey="0" password="0" mapping_id="11" - extAttrName="postalAddress" intAttrName="postalAddress" intMappingType="AnyPlainSchema" + extAttrName="postalAddress" intAttrName="postalAddress" intMappingType="UserPlainSchema" mandatoryCondition="false" purpose="BOTH"/> <MappingItem id="318" connObjectKey="0" password="0" mapping_id="11" extAttrName="mail" intAttrName="userId" intMappingType="UserPlainSchema" @@ -940,9 +939,9 @@ under the License. destinationRealm_id="1" performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" fullReconciliation="0" jobClassName="org.apache.syncope.core.provisioning.api.job.SyncJob" unmatchingRule="ASSIGN" matchingRule="UPDATE"/> <AnyTemplate id="41" syncTask_id="4" anyType_name="USER" - template='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"plainAttrs":[{"schema":"type","readonly":false,"values":["email == '[email protected]'? 'TYPE_8': 'TYPE_OTHER'"]}],"derAttrs":[{"schema":"cn","readonly":false,"values":[null]}],"virAttrs":[],"resources":["resource-testdb"],"propagationStatuses":[],"memberships":[{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"groupKey":8,"groupName":null,"plainAttrs":[{"schema":"subscriptionDate","readonly":false,"values":["'2009-08-18T16:33:12.203+0200'"]}],"derAttrs":[],"virAttrs":[]}]}'/> + template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":["csv"],"derAttrs":[{"schema":"cn","readonly":false,"values":[""]}],"virAttrs":[],"resources":["resource-testdb"],"propagationStatuses":[],"relationships":[],"memberships":[{"leftType":null,"leftKey":0,"rightType":"GROUP","rightKey":8,"groupName":null}],"dynGroups":[],"roles":[],"dynRoles":[],"plainAttrs":[{"schema":"type","readonly":false,"values":["email == '[email protected]'? 'TYPE_8': 'TYPE_OTHER'"]}]}'/> <AnyTemplate id="42" syncTask_id="4" anyType_name="GROUP" - template='{"creator": null,"creationDate": null,"lastModifier": null,"lastChangeDate": null,"key": 0,"name": null,"userOwner": null,"groupOwner": null,"plainAttrs": [], "derAttrs": [],"virAttrs": [],"resources": [],"propagationStatuses": []}'/> + template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"adynMembershipCond":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"propagationStatuses":[],"plainAttrs":[]}'/> <Task DTYPE="SchedTask" type="SCHEDULED" id="5" name="SampleJob Task" jobClassName="org.apache.syncope.core.provisioning.java.job.SampleJob" cronExpression="0 0 0 1 * ?"/> <Task DTYPE="PropagationTask" type="PROPAGATION" id="6" propagationMode="TWO_PHASES" propagationOperation="UPDATE" objectClassName="__ACCOUNT__" resource_name="ws-target-resource-nopropagation" anyTypeKind="USER" anyKey="1" @@ -951,10 +950,10 @@ under the License. <Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="7" name="TestDB Task" resource_name="resource-testdb" destinationRealm_id="1" performCreate="1" performUpdate="1" performDelete="0" syncStatus="1" fullReconciliation="1" jobClassName="org.apache.syncope.core.provisioning.api.job.SyncJob" unmatchingRule="PROVISION" matchingRule="UPDATE"/> - <AnyTemplate id="61" syncTask_id="7" anyType_name="USER" - template='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"plainAttrs":[{"schema":"type","readonly":false,"values":["email == '[email protected]'? 'TYPE_8': 'TYPE_OTHER'"]}],"derAttrs":[{"schema":"cn","readonly":false,"values":[null]}],"virAttrs":[],"resources":["resource-testdb"],"propagationStatuses":[],"memberships":[{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"groupKey":8,"groupName":null,"plainAttrs":[{"schema":"subscriptionDate","readonly":false,"values":["'2009-08-18T16:33:12.203+0200'"]}],"derAttrs":[],"virAttrs":[]}]}'/> - <AnyTemplate id="62" syncTask_id="7" anyType_name="GROUP" - template='{"creator": null,"creationDate": null,"lastModifier": null,"lastChangeDate": null,"key": 0,"name": null,"userOwner": null,"groupOwner": null,"plainAttrs": [], "derAttrs": [],"virAttrs": [],"resources": [],"propagationStatuses": []}'/> + <AnyTemplate id="71" syncTask_id="7" anyType_name="USER" + template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"propagationStatuses":[],"relationships":[],"memberships":[],"dynGroups":[],"roles":[],"dynRoles":[],"plainAttrs":[{"schema":"type","readonly":false,"values":["'type a'"]},{"schema":"userId","readonly":false,"values":["'[email protected]'"]},{"schema":"fullname","readonly":false,"values":["'reconciled fullname'"]},{"schema":"surname","readonly":false,"values":["'surname'"]}]}'/> + <AnyTemplate id="72" syncTask_id="7" anyType_name="GROUP" + template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"adynMembershipCond":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"propagationStatuses":[],"plainAttrs":[]}'/> <Task DTYPE="NotificationTask" type="NOTIFICATION" id="8" sender="[email protected]" subject="Notification for SYNCOPE-81" textBody="NOTIFICATION-81" htmlBody="NOTIFICATION-81" traceLevel="ALL"/> <Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="9" name="TestDB2 Task" resource_name="resource-testdb2" @@ -967,9 +966,9 @@ under the License. destinationRealm_id="1" fullReconciliation="1" performCreate="1" performDelete="1" performUpdate="1" syncStatus="0" jobClassName="org.apache.syncope.core.provisioning.api.job.SyncJob" unmatchingRule="PROVISION" matchingRule="UPDATE"/> <AnyTemplate id="1" syncTask_id="11" anyType_name="USER" - template='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"plainAttrs":[{"schema":"type","readonly":false,"values":["email == '[email protected]'? 'TYPE_8': 'TYPE_OTHER'"]}],"derAttrs":[{"schema":"cn","readonly":false,"values":[null]}],"virAttrs":[],"resources":["resource-testdb"],"propagationStatuses":[],"memberships":[{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"groupKey":8,"groupName":null,"plainAttrs":[{"schema":"subscriptionDate","readonly":false,"values":["'2009-08-18T16:33:12.203+0200'"]}],"derAttrs":[],"virAttrs":[]}]}'/> + template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":[],"derAttrs":[],"virAttrs":[{"schema":"virtualReadOnly","readonly":true,"values":[""]}],"resources":["resource-ldap"],"propagationStatuses":[],"roles":[],"dynRoles":[],"relationships":[],"memberships":[],"dynGroups":[],"plainAttrs":[]}'/> <AnyTemplate id="2" syncTask_id="11" anyType_name="GROUP" - template='{"creator": null,"creationDate": null,"lastModifier": null,"lastChangeDate": null,"key": 0,"name": null,"userOwner": null,"groupOwner": null,"plainAttrs": [], "derAttrs": [],"virAttrs": [],"resources": [],"propagationStatuses": []}'/> + template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"adynMembershipCond":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"propagationStatuses":[],"plainAttrs":[{"schema":"show","readonly":false,"values":["true"]}]}'/> <SyncTask_actionsClassNames SyncTask_id="11" actionClassName="org.apache.syncope.core.provisioning.java.sync.LDAPMembershipSyncActions"/> <Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="12" name="VirAttrCache test" resource_name="resource-csv" destinationRealm_id="1" performCreate="0" performUpdate="1" performDelete="0" syncStatus="0" fullReconciliation="1" @@ -1044,9 +1043,9 @@ under the License. destinationRealm_id="1" performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" fullReconciliation="0" jobClassName="org.apache.syncope.core.provisioning.api.job.SyncJob" unmatchingRule="PROVISION" matchingRule="UPDATE"/> <AnyTemplate id="3" syncTask_id="24" anyType_name="USER" - template='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"plainAttrs":[{"schema":"type","readonly":false,"values":["email == '[email protected]'? 'TYPE_8': 'TYPE_OTHER'"]}],"derAttrs":[{"schema":"cn","readonly":false,"values":[null]}],"virAttrs":[],"resources":["resource-testdb"],"propagationStatuses":[],"memberships":[{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"groupKey":8,"groupName":null,"plainAttrs":[{"schema":"subscriptionDate","readonly":false,"values":["'2009-08-18T16:33:12.203+0200'"]}],"derAttrs":[],"virAttrs":[]}]}'/> + template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":["resource-testdb"],"propagationStatuses":[],"roles":[],"dynRoles":[],"relationships":[],"memberships":[],"dynGroups":[],"plainAttrs":[{"schema":"firstname","readonly":false,"values":[""]},{"schema":"userId","readonly":false,"values":["'test'"]},{"schema":"fullname","readonly":false,"values":["'test'"]},{"schema":"surname","readonly":false,"values":["'test'"]}]}'/> <AnyTemplate id="4" syncTask_id="24" anyType_name="GROUP" - template='{"creator": null,"creationDate": null,"lastModifier": null,"lastChangeDate": null,"key": 0,"name": null,"userOwner": null,"groupOwner": null,"plainAttrs": [], "derAttrs": [],"virAttrs": [],"resources": [],"propagationStatuses": []}'/> + template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"adynMembershipCond":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"propagationStatuses":[],"plainAttrs":[]}'/> <Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="25" name="CSV (unlink matching; ignore unmatching)" resource_name="resource-csv" destinationRealm_id="1" performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" fullReconciliation="0" jobClassName="org.apache.syncope.core.provisioning.api.job.SyncJob" unmatchingRule="IGNORE" matchingRule="UNLINK"/> http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java ---------------------------------------------------------------------- diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java new file mode 100644 index 0000000..4cec074 --- /dev/null +++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.apache.syncope.core.provisioning.api; + +import java.util.Collection; +import java.util.Set; +import org.apache.syncope.common.lib.mod.AttrMod; +import org.apache.syncope.common.lib.to.AttrTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; +import org.apache.syncope.common.lib.types.IntMappingType; +import org.apache.syncope.common.lib.types.PropagationByResource; +import org.apache.syncope.core.persistence.api.entity.Any; +import org.apache.syncope.core.persistence.api.entity.AnyUtils; +import org.apache.syncope.core.persistence.api.entity.VirSchema; +import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; + +public interface VirAttrHandler { + + PropagationByResource fillVirtual(Any any, Set<String> vAttrsToBeRemoved, Set<AttrMod> vAttrsToBeUpdated); + + /** + * Add virtual attributes and specify values to be propagated. + * + * @param any any. + * @param vAttrs virtual attributes to be added. + */ + void fillVirtual(Any any, Collection<AttrTO> vAttrs); + + /** + * SYNCOPE-459: build virtual attribute changes in case no other changes were made. + * + * @param key any key + * @param anyTypeKind type kind + * @param vAttrsToBeRemoved virtual attributes to be removed. + * @param vAttrsToBeUpdated virtual attributes to be updated. + * @return operations to be performed on external resources for virtual attributes changes + */ + PropagationByResource fillVirtual( + Long key, AnyTypeKind anyTypeKind, Set<String> vAttrsToBeRemoved, Set<AttrMod> vAttrsToBeUpdated); + + VirSchema getVirSchema(String virSchemaName); + + /** + * Query connected external resources for values to populated virtual attributes associated with the given owner. + * + * @param any any object + */ + void retrieveVirAttrValues(Any<?, ?, ?> any); + + void updateOnResourcesIfMappingMatches( + Any<?, ?, ?> any, AnyUtils anyUtils, String schemaKey, + Iterable<? extends ExternalResource> resources, IntMappingType mappingType, + PropagationByResource propByRes); + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AnyTypeClassDataBinder.java ---------------------------------------------------------------------- diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AnyTypeClassDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AnyTypeClassDataBinder.java new file mode 100644 index 0000000..18187be --- /dev/null +++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AnyTypeClassDataBinder.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.apache.syncope.core.provisioning.api.data; + +import org.apache.syncope.common.lib.to.AnyTypeClassTO; +import org.apache.syncope.core.persistence.api.entity.AnyTypeClass; + +public interface AnyTypeClassDataBinder { + + AnyTypeClass create(AnyTypeClassTO anyTypeClassTO); + + void update(AnyTypeClass anyTypeClass, AnyTypeClassTO anyTypeClassTO); + + AnyTypeClassTO getAnyTypeClassTO(AnyTypeClass anyTypeClass); +} http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AnyTypeDataBinder.java ---------------------------------------------------------------------- diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AnyTypeDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AnyTypeDataBinder.java new file mode 100644 index 0000000..c29c2ac --- /dev/null +++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AnyTypeDataBinder.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.apache.syncope.core.provisioning.api.data; + +import org.apache.syncope.common.lib.to.AnyTypeTO; +import org.apache.syncope.core.persistence.api.entity.AnyType; + +public interface AnyTypeDataBinder { + + AnyType create(AnyTypeTO anyTypeTO); + + void update(AnyType anyType, AnyTypeTO anyTypeTO); + + AnyTypeTO getAnyTypeTO(AnyType anyType); +} http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java index 1bd2638..fd6bcf1 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java @@ -30,6 +30,8 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.common.lib.mod.AnyObjectMod; import org.apache.syncope.common.lib.to.PropagationStatus; import org.apache.syncope.common.lib.to.AnyObjectTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; +import org.apache.syncope.common.lib.types.PropagationByResource; import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; import org.apache.syncope.core.persistence.api.entity.task.PropagationTask; import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager; @@ -40,6 +42,7 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter; import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor; import org.apache.syncope.core.misc.spring.ApplicationContextProvider; import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; +import org.apache.syncope.core.provisioning.api.VirAttrHandler; import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -102,6 +105,18 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin List<PropagationTask> tasks = propagationManager.getAnyObjectUpdateTasks(updated, anyObjectMod.getVirAttrsToRemove(), anyObjectMod.getVirAttrsToUpdate(), null); + if (tasks.isEmpty()) { + // SYNCOPE-459: take care of user virtual attributes ... + PropagationByResource propByResVirAttr = virtAttrHandler.fillVirtual( + updated.getResult(), + AnyTypeKind.ANY_OBJECT, + anyObjectMod.getVirAttrsToRemove(), + anyObjectMod.getVirAttrsToUpdate()); + tasks.addAll(!propByResVirAttr.isEmpty() + ? propagationManager.getAnyObjectUpdateTasks(updated, null, null, null) + : Collections.<PropagationTask>emptyList()); + } + PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class); try { http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java index c7bc1c4..5661df4 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java @@ -36,6 +36,7 @@ import org.apache.syncope.common.lib.mod.GroupMod; import org.apache.syncope.common.lib.to.AttrTO; import org.apache.syncope.common.lib.to.PropagationStatus; import org.apache.syncope.common.lib.to.GroupTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.common.lib.types.PropagationByResource; import org.apache.syncope.core.persistence.api.dao.GroupDAO; import org.apache.syncope.core.persistence.api.entity.group.Group; @@ -47,6 +48,7 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationManager; import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter; import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor; import org.apache.syncope.core.misc.spring.ApplicationContextProvider; +import org.apache.syncope.core.provisioning.api.VirAttrHandler; import org.apache.syncope.core.workflow.api.GroupWorkflowAdapter; public class DefaultGroupProvisioningManager implements GroupProvisioningManager { @@ -65,6 +67,9 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager @Autowired protected GroupDAO groupDAO; + @Autowired + protected VirAttrHandler virtAttrHandler; + @Override public Pair<Long, List<PropagationStatus>> create(final GroupTO group) { return create(group, Collections.<String>emptySet()); @@ -119,6 +124,18 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager List<PropagationTask> tasks = propagationManager.getGroupUpdateTasks(updated, groupMod.getVirAttrsToRemove(), groupMod.getVirAttrsToUpdate(), excludedResources); + if (tasks.isEmpty()) { + // SYNCOPE-459: take care of user virtual attributes ... + PropagationByResource propByResVirAttr = virtAttrHandler.fillVirtual( + updated.getResult(), + AnyTypeKind.GROUP, + groupMod.getVirAttrsToRemove(), + groupMod.getVirAttrsToUpdate()); + tasks.addAll(!propByResVirAttr.isEmpty() + ? propagationManager.getGroupUpdateTasks(updated, null, null, null) + : Collections.<PropagationTask>emptyList()); + } + PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class); try { http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java index 88d3094..656bc75 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java @@ -30,6 +30,7 @@ import org.apache.syncope.common.lib.mod.StatusMod; import org.apache.syncope.common.lib.mod.UserMod; import org.apache.syncope.common.lib.to.PropagationStatus; import org.apache.syncope.common.lib.to.UserTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.core.persistence.api.dao.UserDAO; import org.apache.syncope.core.persistence.api.entity.task.PropagationTask; import org.apache.syncope.core.persistence.api.entity.user.User; @@ -42,6 +43,7 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter; import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor; import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult; import org.apache.syncope.core.misc.spring.ApplicationContextProvider; +import org.apache.syncope.core.provisioning.api.VirAttrHandler; import org.apache.syncope.core.workflow.api.UserWorkflowAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -120,6 +122,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager { // SYNCOPE-459: take care of user virtual attributes ... PropagationByResource propByResVirAttr = virtAttrHandler.fillVirtual( updated.getResult().getKey().getKey(), + AnyTypeKind.USER, userMod.getVirAttrsToRemove(), userMod.getVirAttrsToUpdate()); tasks.addAll(!propByResVirAttr.isEmpty() http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java deleted file mode 100644 index 6c11f8a..0000000 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.apache.syncope.core.provisioning.java; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.apache.commons.lang3.StringUtils; -import org.apache.syncope.common.lib.mod.AttrMod; -import org.apache.syncope.common.lib.to.AttrTO; -import org.apache.syncope.common.lib.types.AnyTypeKind; -import org.apache.syncope.common.lib.types.IntMappingType; -import org.apache.syncope.common.lib.types.MappingPurpose; -import org.apache.syncope.common.lib.types.PropagationByResource; -import org.apache.syncope.common.lib.types.ResourceOperation; -import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; -import org.apache.syncope.core.persistence.api.dao.UserDAO; -import org.apache.syncope.core.persistence.api.dao.VirAttrDAO; -import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; -import org.apache.syncope.core.persistence.api.entity.Any; -import org.apache.syncope.core.persistence.api.entity.AnyUtils; -import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; -import org.apache.syncope.core.persistence.api.entity.VirAttr; -import org.apache.syncope.core.persistence.api.entity.VirSchema; -import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; -import org.apache.syncope.core.persistence.api.entity.group.Group; -import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; -import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; -import org.apache.syncope.core.persistence.api.entity.user.User; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -@Component -@Transactional(rollbackFor = { Throwable.class }) -public class VirAttrHandler { - - private static final Logger LOG = LoggerFactory.getLogger(VirAttrHandler.class); - - @Autowired - private VirSchemaDAO virSchemaDAO; - - @Autowired - private VirAttrDAO virAttrDAO; - - @Autowired - private AnyObjectDAO anyObjectDAO; - - @Autowired - private UserDAO userDAO; - - @Autowired - private AnyUtilsFactory anyUtilsFactory; - - public VirSchema getVirSchema(final String virSchemaName) { - VirSchema virtualSchema = null; - if (StringUtils.isNotBlank(virSchemaName)) { - virtualSchema = virSchemaDAO.find(virSchemaName); - - if (virtualSchema == null) { - LOG.debug("Ignoring invalid virtual schema {}", virSchemaName); - } - } - - return virtualSchema; - } - - public void updateOnResourcesIfMappingMatches(final Any<?, ?, ?> any, final AnyUtils anyUtils, - final String schemaKey, final Set<ExternalResource> resources, final IntMappingType mappingType, - final PropagationByResource propByRes) { - - for (ExternalResource resource : resources) { - for (MappingItem mapItem : anyUtils.getMappingItems( - resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) { - - if (schemaKey.equals(mapItem.getIntAttrName()) && mapItem.getIntMappingType() == mappingType) { - propByRes.add(ResourceOperation.UPDATE, resource.getKey()); - } - } - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public PropagationByResource fillVirtual(final Any any, - final Set<String> vAttrsToBeRemoved, final Set<AttrMod> vAttrsToBeUpdated, final AnyUtils anyUtils) { - - PropagationByResource propByRes = new PropagationByResource(); - - Set<ExternalResource> externalResources = new HashSet<>(); - if (any instanceof User) { - externalResources.addAll(userDAO.findAllResources((User) any)); - } else if (any instanceof Group) { - externalResources.addAll(((Group) any).getResources()); - } else if (any instanceof AnyObject) { - externalResources.addAll(anyObjectDAO.findAllResources((AnyObject) any)); - } - - // 1. virtual attributes to be removed - for (String vAttrToBeRemoved : vAttrsToBeRemoved) { - VirSchema virSchema = getVirSchema(vAttrToBeRemoved); - if (virSchema != null) { - VirAttr virAttr = any.getVirAttr(virSchema.getKey()); - if (virAttr == null) { - LOG.debug("No virtual attribute found for schema {}", virSchema.getKey()); - } else { - any.remove(virAttr); - virAttrDAO.delete(virAttr); - } - - for (ExternalResource resource : externalResources) { - for (MappingItem mapItem : anyUtils.getMappingItems( - resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) { - - if (virSchema.getKey().equals(mapItem.getIntAttrName()) - && mapItem.getIntMappingType() == anyUtils.virIntMappingType()) { - - propByRes.add(ResourceOperation.UPDATE, resource.getKey()); - - // Using virtual attribute as ConnObjectKey must be avoided - if (mapItem.isConnObjectKey() && virAttr != null && !virAttr.getValues().isEmpty()) { - propByRes.addOldConnObjectKey(resource.getKey(), virAttr.getValues().get(0).toString()); - } - } - } - } - } - } - - LOG.debug("Virtual attributes to be removed:\n{}", propByRes); - - // 2. virtual attributes to be updated - for (AttrMod vAttrToBeUpdated : vAttrsToBeUpdated) { - VirSchema virSchema = getVirSchema(vAttrToBeUpdated.getSchema()); - VirAttr virAttr = null; - if (virSchema != null) { - virAttr = any.getVirAttr(virSchema.getKey()); - if (virAttr == null) { - virAttr = anyUtils.newVirAttr(); - virAttr.setSchema(virSchema); - if (virAttr.getSchema() == null) { - LOG.debug("Ignoring {} because no valid schema was found", vAttrToBeUpdated); - } else { - any.add(virAttr); - } - } - } - - if (virSchema != null && virAttr != null && virAttr.getSchema() != null) { - updateOnResourcesIfMappingMatches(any, anyUtils, virSchema.getKey(), - externalResources, anyUtils.derIntMappingType(), propByRes); - - List<String> values = new ArrayList<>(virAttr.getValues()); - values.removeAll(vAttrToBeUpdated.getValuesToBeRemoved()); - values.addAll(vAttrToBeUpdated.getValuesToBeAdded()); - - virAttr.getValues().clear(); - virAttr.getValues().addAll(values); - - // Owner cannot be specified before otherwise a virtual attribute remove will be invalidated. - virAttr.setOwner(any); - } - } - - LOG.debug("Virtual attributes to be added:\n{}", propByRes); - - return propByRes; - } - - /** - * Add virtual attributes and specify values to be propagated. - * - * @param any any. - * @param vAttrs virtual attributes to be added. - * @param anyUtils utils - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public void fillVirtual(final Any any, final Collection<AttrTO> vAttrs, final AnyUtils anyUtils) { - for (AttrTO attrTO : vAttrs) { - VirAttr virAttr = any.getVirAttr(attrTO.getSchema()); - if (virAttr == null) { - VirSchema virSchema = getVirSchema(attrTO.getSchema()); - if (virSchema != null) { - virAttr = anyUtils.newVirAttr(); - virAttr.setSchema(virSchema); - if (virAttr.getSchema() == null) { - LOG.debug("Ignoring {} because no valid schema was found", attrTO); - } else { - virAttr.setOwner(any); - any.add(virAttr); - virAttr.getValues().clear(); - virAttr.getValues().addAll(attrTO.getValues()); - } - } - } else { - virAttr.getValues().clear(); - virAttr.getValues().addAll(attrTO.getValues()); - } - } - } - - /** - * SYNCOPE-459: build virtual attribute changes in case no other changes were made. - * - * @param key user id - * @param vAttrsToBeRemoved virtual attributes to be removed. - * @param vAttrsToBeUpdated virtual attributes to be updated. - * @return operations to be performed on external resources for virtual attributes changes - */ - public PropagationByResource fillVirtual( - final Long key, final Set<String> vAttrsToBeRemoved, final Set<AttrMod> vAttrsToBeUpdated) { - - return fillVirtual( - anyObjectDAO.authFind(key), - vAttrsToBeRemoved, - vAttrsToBeUpdated, - anyUtilsFactory.getInstance(AnyTypeKind.USER)); - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/dd88efbd/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java new file mode 100644 index 0000000..21626f5 --- /dev/null +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java @@ -0,0 +1,411 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.apache.syncope.core.provisioning.java; + +import org.apache.syncope.core.provisioning.api.VirAttrHandler; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.common.lib.mod.AttrMod; +import org.apache.syncope.common.lib.to.AttrTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; +import org.apache.syncope.common.lib.types.IntMappingType; +import org.apache.syncope.common.lib.types.MappingPurpose; +import org.apache.syncope.common.lib.types.PropagationByResource; +import org.apache.syncope.common.lib.types.ResourceOperation; +import org.apache.syncope.core.misc.MappingUtils; +import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; +import org.apache.syncope.core.persistence.api.dao.GroupDAO; +import org.apache.syncope.core.persistence.api.dao.UserDAO; +import org.apache.syncope.core.persistence.api.dao.VirAttrDAO; +import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; +import org.apache.syncope.core.persistence.api.entity.Any; +import org.apache.syncope.core.persistence.api.entity.AnyType; +import org.apache.syncope.core.persistence.api.entity.AnyUtils; +import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; +import org.apache.syncope.core.persistence.api.entity.VirAttr; +import org.apache.syncope.core.persistence.api.entity.VirSchema; +import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; +import org.apache.syncope.core.persistence.api.entity.group.Group; +import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; +import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; +import org.apache.syncope.core.persistence.api.entity.resource.Provision; +import org.apache.syncope.core.persistence.api.entity.user.User; +import org.apache.syncope.core.provisioning.api.Connector; +import org.apache.syncope.core.provisioning.api.ConnectorFactory; +import org.apache.syncope.core.provisioning.api.cache.VirAttrCache; +import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue; +import org.identityconnectors.framework.common.objects.Attribute; +import org.identityconnectors.framework.common.objects.ConnectorObject; +import org.identityconnectors.framework.common.objects.OperationOptions; +import org.identityconnectors.framework.common.objects.Uid; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Transactional(rollbackFor = { Throwable.class }) +public class VirAttrHandlerImpl implements VirAttrHandler { + + private static final Logger LOG = LoggerFactory.getLogger(VirAttrHandler.class); + + @Autowired + private VirSchemaDAO virSchemaDAO; + + @Autowired + private VirAttrDAO virAttrDAO; + + @Autowired + private AnyObjectDAO anyObjectDAO; + + @Autowired + private UserDAO userDAO; + + @Autowired + private GroupDAO groupDAO; + + @Autowired + private AnyUtilsFactory anyUtilsFactory; + + @Autowired + private ConnectorFactory connFactory; + + /** + * Virtual attribute cache. + */ + @Autowired + private VirAttrCache virAttrCache; + + @Override + public VirSchema getVirSchema(final String virSchemaName) { + VirSchema virtualSchema = null; + if (StringUtils.isNotBlank(virSchemaName)) { + virtualSchema = virSchemaDAO.find(virSchemaName); + + if (virtualSchema == null) { + LOG.debug("Ignoring invalid virtual schema {}", virSchemaName); + } + } + + return virtualSchema; + } + + @Override + public void updateOnResourcesIfMappingMatches(final Any<?, ?, ?> any, final AnyUtils anyUtils, + final String schemaKey, final Iterable<? extends ExternalResource> resources, + final IntMappingType mappingType, final PropagationByResource propByRes) { + + for (ExternalResource resource : resources) { + for (MappingItem mapItem : anyUtils.getMappingItems( + resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) { + + if (schemaKey.equals(mapItem.getIntAttrName()) && mapItem.getIntMappingType() == mappingType) { + propByRes.add(ResourceOperation.UPDATE, resource.getKey()); + } + } + } + } + + private Iterable<? extends ExternalResource> getAllResources(final Any<?, ?, ?> any) { + return any instanceof User + ? userDAO.findAllResources((User) any) + : any instanceof AnyObject + ? anyObjectDAO.findAllResources((AnyObject) any) + : any instanceof Group + ? ((Group) any).getResources() + : Collections.<ExternalResource>emptySet(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public PropagationByResource fillVirtual(final Any any, + final Set<String> vAttrsToBeRemoved, final Set<AttrMod> vAttrsToBeUpdated) { + + AnyUtils anyUtils = anyUtilsFactory.getInstance(any); + + PropagationByResource propByRes = new PropagationByResource(); + + Iterable<? extends ExternalResource> externalResources = getAllResources(any); + + // 1. virtual attributes to be removed + for (String vAttrToBeRemoved : vAttrsToBeRemoved) { + VirSchema virSchema = getVirSchema(vAttrToBeRemoved); + if (virSchema != null) { + VirAttr virAttr = any.getVirAttr(virSchema.getKey()); + if (virAttr == null) { + LOG.debug("No virtual attribute found for schema {}", virSchema.getKey()); + } else { + any.remove(virAttr); + virAttrDAO.delete(virAttr); + } + + for (ExternalResource resource : externalResources) { + for (MappingItem mapItem : anyUtils.getMappingItems( + resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) { + + if (virSchema.getKey().equals(mapItem.getIntAttrName()) + && mapItem.getIntMappingType() == anyUtils.virIntMappingType()) { + + propByRes.add(ResourceOperation.UPDATE, resource.getKey()); + + // Using virtual attribute as ConnObjectKey must be avoided + if (mapItem.isConnObjectKey() && virAttr != null && !virAttr.getValues().isEmpty()) { + propByRes.addOldConnObjectKey(resource.getKey(), virAttr.getValues().get(0).toString()); + } + } + } + } + } + } + + LOG.debug("Virtual attributes to be removed:\n{}", propByRes); + + // 2. virtual attributes to be updated + for (AttrMod vAttrToBeUpdated : vAttrsToBeUpdated) { + VirSchema virSchema = getVirSchema(vAttrToBeUpdated.getSchema()); + if (virSchema != null) { + VirAttr virAttr = any.getVirAttr(virSchema.getKey()); + if (virAttr == null) { + virAttr = anyUtils.newVirAttr(); + virAttr.setOwner(any); + virAttr.setSchema(virSchema); + + any.add(virAttr); + } + + updateOnResourcesIfMappingMatches(any, anyUtils, virSchema.getKey(), + externalResources, anyUtils.derIntMappingType(), propByRes); + + List<String> values = new ArrayList<>(virAttr.getValues()); + values.removeAll(vAttrToBeUpdated.getValuesToBeRemoved()); + values.addAll(vAttrToBeUpdated.getValuesToBeAdded()); + + virAttr.getValues().clear(); + virAttr.getValues().addAll(values); + } + } + + LOG.debug("Virtual attributes to be added:\n{}", propByRes); + + return propByRes; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void fillVirtual(final Any any, final Collection<AttrTO> vAttrs) { + AnyUtils anyUtils = anyUtilsFactory.getInstance(any); + + for (AttrTO attrTO : vAttrs) { + VirAttr virAttr = any.getVirAttr(attrTO.getSchema()); + if (virAttr == null) { + VirSchema virSchema = getVirSchema(attrTO.getSchema()); + if (virSchema != null) { + virAttr = anyUtils.newVirAttr(); + virAttr.setSchema(virSchema); + if (virAttr.getSchema() == null) { + LOG.debug("Ignoring {} because no valid schema was found", attrTO); + } else { + virAttr.setOwner(any); + any.add(virAttr); + virAttr.getValues().clear(); + virAttr.getValues().addAll(attrTO.getValues()); + } + } + } else { + virAttr.getValues().clear(); + virAttr.getValues().addAll(attrTO.getValues()); + } + } + } + + private Any<?, ?, ?> find(final Long key, final AnyTypeKind anyTypeKind) { + Any<?, ?, ?> result; + + switch (anyTypeKind) { + case USER: + result = userDAO.authFind(key); + break; + + case GROUP: + result = groupDAO.authFind(key); + break; + + case ANY_OBJECT: + default: + result = anyObjectDAO.authFind(key); + } + + return result; + } + + @Transactional + @Override + public PropagationByResource fillVirtual( + final Long key, final AnyTypeKind anyTypeKind, + final Set<String> vAttrsToBeRemoved, final Set<AttrMod> vAttrsToBeUpdated) { + + return fillVirtual( + find(key, anyTypeKind), + vAttrsToBeRemoved, + vAttrsToBeUpdated); + } + + @Override + public void retrieveVirAttrValues(final Any<?, ?, ?> any) { + IntMappingType type = any.getType().getKind() == AnyTypeKind.USER + ? IntMappingType.UserVirtualSchema + : any.getType().getKind() == AnyTypeKind.GROUP + ? IntMappingType.GroupVirtualSchema + : IntMappingType.AnyVirtualSchema; + + Map<String, ConnectorObject> resources = new HashMap<>(); + + // ----------------------- + // Retrieve virtual attribute values if and only if they have not been retrieved yet + // ----------------------- + for (VirAttr<?> virAttr : any.getVirAttrs()) { + // reset value set + if (virAttr.getValues().isEmpty()) { + retrieveVirAttrValue(any, virAttr, type, resources); + } + } + // ----------------------- + } + + private void retrieveVirAttrValue( + final Any<?, ?, ?> any, + final VirAttr<?> virAttr, + final IntMappingType type, + final Map<String, ConnectorObject> externalResources) { + + String schemaName = virAttr.getSchema().getKey(); + VirAttrCacheValue virAttrCacheValue = virAttrCache.get(any.getType().getKey(), any.getKey(), schemaName); + + LOG.debug("Retrieve values for virtual attribute {} ({})", schemaName, type); + + if (virAttrCache.isValidEntry(virAttrCacheValue)) { + // cached ... + LOG.debug("Values found in cache {}", virAttrCacheValue); + virAttr.getValues().clear(); + virAttr.getValues().addAll(new ArrayList<>(virAttrCacheValue.getValues())); + } else { + // not cached ... + LOG.debug("Need one or more remote connections"); + + VirAttrCacheValue toBeCached = new VirAttrCacheValue(); + + AnyUtils anyUtils = anyUtilsFactory.getInstance(any); + + for (ExternalResource resource : getTargetResources(virAttr, type, anyUtils, any.getType())) { + Provision provision = resource.getProvision(any.getType()); + LOG.debug("Search values into {},{}", resource, provision); + + try { + List<MappingItem> mappings = anyUtils.getMappingItems(provision, MappingPurpose.BOTH); + + ConnectorObject connectorObject; + if (externalResources.containsKey(resource.getKey())) { + connectorObject = externalResources.get(resource.getKey()); + } else { + LOG.debug("Perform connection to {}", resource.getKey()); + String connObjectKey = anyUtils.getConnObjectKeyItem(provision) == null + ? null + : MappingUtils.getConnObjectKeyValue(any, provision); + + if (StringUtils.isBlank(connObjectKey)) { + throw new IllegalArgumentException("No ConnObjectKey found for " + resource.getKey()); + } + + Connector connector = connFactory.getConnector(resource); + + OperationOptions oo = + connector.getOperationOptions(MappingUtils.getMatchingMappingItems(mappings, type)); + + connectorObject = + connector.getObject(provision.getObjectClass(), new Uid(connObjectKey), oo); + externalResources.put(resource.getKey(), connectorObject); + } + + if (connectorObject != null) { + // ask for searched virtual attribute value + Collection<MappingItem> virAttrMappings = + MappingUtils.getMatchingMappingItems(mappings, schemaName, type); + + // the same virtual attribute could be mapped with one or more external attribute + for (MappingItem mapping : virAttrMappings) { + Attribute attribute = connectorObject.getAttributeByName(mapping.getExtAttrName()); + + if (attribute != null && attribute.getValue() != null) { + for (Object obj : attribute.getValue()) { + if (obj != null) { + virAttr.getValues().add(obj.toString()); + } + } + } + } + + toBeCached.setResourceValues(resource.getKey(), new HashSet<>(virAttr.getValues())); + + LOG.debug("Retrieved values {}", virAttr.getValues()); + } + } catch (Exception e) { + LOG.error("Error reading connector object from {}", resource.getKey(), e); + + if (virAttrCacheValue != null) { + toBeCached.forceExpiring(); + LOG.debug("Search for a cached value (even expired!) ..."); + final Set<String> cachedValues = virAttrCacheValue.getValues(resource.getKey()); + if (cachedValues != null) { + LOG.debug("Use cached value {}", cachedValues); + virAttr.getValues().addAll(cachedValues); + toBeCached.setResourceValues(resource.getKey(), new HashSet<>(cachedValues)); + } + } + } + } + + virAttrCache.put(any.getType().getKey(), any.getKey(), schemaName, toBeCached); + } + } + + private Collection<ExternalResource> getTargetResources( + final VirAttr<?> attr, final IntMappingType type, final AnyUtils anyUtils, final AnyType anyType) { + + return CollectionUtils.select(getAllResources(attr.getOwner()), new Predicate<ExternalResource>() { + + @Override + public boolean evaluate(final ExternalResource resource) { + return resource.getProvision(anyType) != null + && !MappingUtils.getMatchingMappingItems( + anyUtils.getMappingItems(resource.getProvision(anyType), MappingPurpose.BOTH), + attr.getSchema().getKey(), type).isEmpty(); + } + }); + } +}
