You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2013/02/13 12:51:21 UTC
svn commit: r1445561 - in /syncope/trunk: ./
core/src/main/java/org/apache/syncope/core/connid/
core/src/main/java/org/apache/syncope/core/propagation/impl/
core/src/main/java/org/apache/syncope/core/util/ core/src/main/resources/
core/src/test/java/or...
Author: fmartelli
Date: Wed Feb 13 11:51:21 2013
New Revision: 1445561
URL: http://svn.apache.org/r1445561
Log:
SYNCOPE-154 merged from the branch 1_0_X and fixed
Added:
syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java
- copied, changed from r1445543, syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java
- copied, changed from r1445543, syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheValue.java
- copied unchanged from r1445543, syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheValue.java
Modified:
syncope/trunk/ (props changed)
syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java
syncope/trunk/core/src/main/resources/syncopeContext.xml
syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
Propchange: syncope/trunk/
------------------------------------------------------------------------------
Merged /syncope/branches/1_0_X:r1444851-1445543
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java?rev=1445561&r1=1445560&r2=1445561&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java Wed Feb 13 11:51:21 2013
@@ -60,6 +60,7 @@ import org.apache.syncope.core.util.Attr
import org.apache.syncope.core.util.InvalidPasswordPolicySpecException;
import org.apache.syncope.core.util.JexlUtil;
import org.apache.syncope.core.util.MappingUtil;
+import org.apache.syncope.core.util.VirAttrCache;
import org.identityconnectors.common.security.GuardedByteArray;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.objects.Attribute;
@@ -106,6 +107,12 @@ public class ConnObjectUtil {
@Autowired
private PasswordGenerator pwdGen;
+ /**
+ * Virtual attribute cache.
+ */
+ @Autowired
+ private VirAttrCache virAttrCache;
+
public ObjectClass fromAttributable(final AbstractAttributable attributable) {
if (attributable == null
|| (!(attributable instanceof SyncopeUser) && !(attributable instanceof SyncopeRole))) {
@@ -467,70 +474,106 @@ public class ConnObjectUtil {
final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
final ConnectorFactory connInstanceLoader = context.getBean(ConnectorFactory.class);
- final Map<ConnectorObject, Set<AbstractMappingItem>> connObj2MapItems =
- new HashMap<ConnectorObject, Set<AbstractMappingItem>>();
+ final IntMappingType type = owner instanceof SyncopeUser
+ ? IntMappingType.UserVirtualSchema : IntMappingType.RoleVirtualSchema;
- for (ExternalResource resource : owner.getResources()) {
- LOG.debug("Retrieve remote object from '{}'", resource.getName());
- try {
- final String accountId = attrUtil.getAccountIdItem(resource) == null
- ? null : MappingUtil.getAccountIdValue(owner, resource, attrUtil.getAccountIdItem(resource));
+ final Map<String, ConnectorObject> externalResources = new HashMap<String, ConnectorObject>();
- LOG.debug("Search for object with accountId '{}'", accountId);
+ // -----------------------
+ // Retrieve virtual attribute values
+ // -----------------------
+ for (AbstractVirAttr virAttr : owner.getVirtualAttributes()) {
+ final String schemaName = virAttr.getVirtualSchema().getName();
+ final List<String> values = virAttrCache.get(attrUtil.getType(), owner.getId(), schemaName);
- if (StringUtils.isNotBlank(accountId)) {
- // Retrieve attributes to get
- final Set<AbstractMappingItem> virMapItems = new HashSet<AbstractMappingItem>();
- final Set<String> extAttrNames = new HashSet<String>();
-
- for (AbstractMappingItem item : attrUtil.getMappingItems(resource)) {
- if ((AttributableType.USER == attrUtil.getType()
- && item.getIntMappingType() == IntMappingType.UserVirtualSchema)
- || (AttributableType.ROLE == attrUtil.getType()
- && item.getIntMappingType() == IntMappingType.RoleVirtualSchema)) {
+ LOG.debug("Retrieve values for virtual attribute {}", schemaName);
- virMapItems.add(item);
- extAttrNames.add(item.getExtAttrName());
- }
- }
+ if (values == null) {
+ // non cached ...
+ LOG.debug("Need one or more remote connections");
+ for (ExternalResource resource : getTargetResource(virAttr, type, attrUtil)) {
+ LOG.debug("Seach values into {}", resource.getName());
+ try {
+ final ConnectorObject connectorObject;
- // Search for remote object
- final OperationOptionsBuilder oob = new OperationOptionsBuilder();
- oob.setAttributesToGet(extAttrNames);
+ if (externalResources.containsKey(resource.getName())) {
+ connectorObject = externalResources.get(resource.getName());
+ } else {
+ LOG.debug("Perform connection to {}", resource.getName());
+ final String accountId = attrUtil.getAccountIdItem(resource) == null
+ ? null
+ : MappingUtil.getAccountIdValue(
+ owner, resource, attrUtil.getAccountIdItem(resource));
- final SyncopeConnector connector = connInstanceLoader.getConnector(resource);
- final ConnectorObject connObj =
- connector.getObject(fromAttributable(owner), new Uid(accountId), oob.build());
- if (connObj != null) {
- connObj2MapItems.put(connObj, virMapItems);
- }
+ if (StringUtils.isBlank(accountId)) {
+ throw new IllegalArgumentException("No AccountId found for " + resource.getName());
+ }
- LOG.debug("Retrieved remote object {}", connObj);
- }
- } catch (Exception e) {
- LOG.error("Unable to retrieve virtual attribute values on '{}'", resource.getName(), e);
- }
- }
+ final Set<String> extAttrNames = new HashSet<String>();
- for (AbstractVirAttr virAttr : owner.getVirtualAttributes()) {
- LOG.debug("Provide value for virtual attribute '{}'", virAttr.getVirtualSchema().getName());
+ // retrieve all mapped virtual attribute values
+ for (AbstractMappingItem item :
+ MappingUtil.getMatchingMappingItems(attrUtil.getMappingItems(resource), type)) {
+ extAttrNames.add(item.getExtAttrName());
+ }
+
+ LOG.debug("External attribute ({}) names to get '{}'", type, extAttrNames);
- for (Map.Entry<ConnectorObject, Set<AbstractMappingItem>> entry : connObj2MapItems.entrySet()) {
- for (AbstractMappingItem vAttrMapItem : entry.getValue()) {
- final String extAttrName = vAttrMapItem.getExtAttrName();
- final Attribute extAttr = entry.getKey().getAttributeByName(extAttrName);
- if (extAttr != null && extAttr.getValue() != null && !extAttr.getValue().isEmpty()) {
- for (Object obj : extAttr.getValue()) {
- if (obj != null) {
- virAttr.addValue(obj.toString());
+ final OperationOptionsBuilder oob = new OperationOptionsBuilder();
+ oob.setAttributesToGet(extAttrNames);
+
+ final SyncopeConnector connector = connInstanceLoader.getConnector(resource);
+ connectorObject = connector.getObject(ObjectClass.ACCOUNT, new Uid(accountId), oob.build());
+ externalResources.put(resource.getName(), connectorObject);
+ }
+
+ // ask for searched virtual attribute value
+ final List<AbstractMappingItem> mappings = MappingUtil.getMatchingMappingItems(
+ attrUtil.getMappingItems(resource), schemaName, type);
+
+ // the same virtual attribute could be mapped with one or more external attribute
+ for (AbstractMappingItem mapping : mappings) {
+ final Attribute attribute = connectorObject.getAttributeByName(mapping.getExtAttrName());
+
+ if (attribute != null && attribute.getValue() != null) {
+ for (Object obj : attribute.getValue()) {
+ if (obj != null) {
+ virAttr.addValue(obj.toString());
+ }
+ }
}
}
+
+ LOG.debug("Retrieved values {}", virAttr.getValues());
+ } catch (Exception e) {
+ LOG.error("Error reading connector object from {}", resource.getName(), e);
}
}
+
+ virAttrCache.put(attrUtil.getType(), owner.getId(), schemaName, virAttr.getValues());
+ } else {
+ // cached ...
+ LOG.debug("Values found in cache {}", values);
+ virAttr.setValues(values);
+ }
+ }
+ // -----------------------
+ }
+
+ private Set<ExternalResource> getTargetResource(
+ final AbstractVirAttr attr, final IntMappingType type, final AttributableUtil attrUtil) {
+
+ final Set<ExternalResource> resources = new HashSet<ExternalResource>();
+
+ for (ExternalResource res : attr.getOwner().getResources()) {
+ if (!MappingUtil.getMatchingMappingItems(
+ attrUtil.getMappingItems(res), attr.getVirtualSchema().getName(), type).isEmpty()) {
+
+ resources.add(res);
}
}
- LOG.debug("Virtual attribute evaluation ended");
+ return resources;
}
private void fillFromTemplate(final AbstractAttributableTO attributableTO, final AbstractAttributableTO template) {
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java?rev=1445561&r1=1445560&r2=1445561&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java Wed Feb 13 11:51:21 2013
@@ -29,6 +29,7 @@ import java.util.Set;
import org.apache.syncope.common.mod.AttributeMod;
import org.apache.syncope.common.to.AttributeTO;
import org.apache.syncope.common.types.AttributableType;
+import org.apache.syncope.common.types.IntMappingType;
import org.apache.syncope.common.types.ResourceOperation;
import org.apache.syncope.core.connid.ConnObjectUtil;
import org.apache.syncope.core.connid.PasswordGenerator;
@@ -47,6 +48,7 @@ import org.apache.syncope.core.rest.data
import org.apache.syncope.core.rest.data.UserDataBinder;
import org.apache.syncope.core.util.AttributableUtil;
import org.apache.syncope.core.util.MappingUtil;
+import org.apache.syncope.core.util.VirAttrCache;
import org.apache.syncope.core.workflow.WorkflowResult;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
@@ -95,6 +97,12 @@ public class PropagationManager {
private PasswordGenerator passwordGenerator;
/**
+ * Virtual attribute cache.
+ */
+ @Autowired
+ private VirAttrCache virAttrCache;
+
+ /**
* Create the user on every associated resource.
*
* @param wfResult user to be propagated (and info associated), as per result from workflow
@@ -445,6 +453,14 @@ public class PropagationManager {
LOG.debug("Processing schema {}", mapping.getIntAttrName());
try {
+ if ((attrUtil.getType() == AttributableType.USER
+ && mapping.getIntMappingType() == IntMappingType.UserVirtualSchema)
+ || (attrUtil.getType() == AttributableType.ROLE
+ && mapping.getIntMappingType() == IntMappingType.RoleVirtualSchema)) {
+ LOG.debug("Expire entry cache {}-{}", subject.getId(), mapping.getIntAttrName());
+ virAttrCache.expire(attrUtil.getType(), subject.getId(), mapping.getIntAttrName());
+ }
+
Map.Entry<String, Attribute> preparedAttribute = MappingUtil.prepareAttribute(
resource, mapping, subject, password, passwordGenerator, vAttrsToBeRemoved, vAttrsToBeUpdated);
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java?rev=1445561&r1=1445560&r2=1445561&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java Wed Feb 13 11:51:21 2013
@@ -71,6 +71,20 @@ public final class MappingUtil {
*/
private static final Logger LOG = LoggerFactory.getLogger(MappingUtil.class);
+ public static <T extends AbstractMappingItem> List<T> getMatchingMappingItems(
+ final Collection<T> items, final IntMappingType type) {
+
+ final List<T> result = new ArrayList<T>();
+
+ for (T mapItem : items) {
+ if (mapItem.getIntMappingType() == type) {
+ result.add(mapItem);
+ }
+ }
+
+ return result;
+ }
+
public static <T extends AbstractMappingItem> List<T> getMatchingMappingItems(final Collection<T> items,
final String intAttrName, final IntMappingType type) {
Copied: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java (from r1445543, syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java)
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java?p2=syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java&p1=syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java&r1=1445543&r2=1445561&rev=1445561&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCache.java Wed Feb 13 11:51:21 2013
@@ -26,6 +26,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import org.apache.syncope.common.types.AttributableType;
/**
* Virtual Attribute Value cache.
@@ -76,7 +77,8 @@ public final class VirAttrCache {
* @param schemaName virtual attribute name.
* @param values virtual attribute values.
*/
- public void put(final Long userId, final String schemaName, final List<String> values) {
+ public void put(
+ final AttributableType type, final Long userId, final String schemaName, final List<String> values) {
synchronized (cache) {
// this operations (retrieve cache space and put entry on) have to be thread safe.
@@ -84,7 +86,7 @@ public final class VirAttrCache {
freeCacheSpace(true);
}
- cache.put(new VirAttrCacheKey(userId, schemaName), new VirAttrCacheValue(values));
+ cache.put(new VirAttrCacheKey(type, userId, schemaName), new VirAttrCacheValue(values));
}
}
@@ -95,8 +97,8 @@ public final class VirAttrCache {
* @param schemaName virtual attribute schema name.
* @return cached values or null in case of virtual attribute not found.
*/
- public List<String> get(final Long userId, final String schemaName) {
- final VirAttrCacheValue value = cache.get(new VirAttrCacheKey(userId, schemaName));
+ public List<String> get(final AttributableType type, final Long userId, final String schemaName) {
+ final VirAttrCacheValue value = cache.get(new VirAttrCacheKey(type, userId, schemaName));
return isValidEntry(value) ? value.getValues() : null;
}
@@ -106,8 +108,8 @@ public final class VirAttrCache {
* @param userId user id.
* @param schemaName virtual attribute schema name.
*/
- public void expire(final Long userId, final String schemaName) {
- final VirAttrCacheValue value = cache.get(new VirAttrCacheKey(userId, schemaName));
+ public void expire(final AttributableType type, final Long userId, final String schemaName) {
+ final VirAttrCacheValue value = cache.get(new VirAttrCacheKey(type, userId, schemaName));
if (isValidEntry(value)) {
synchronized (cache) {
value.forceExpiring();
Copied: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java (from r1445543, syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java)
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java?p2=syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java&p1=syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java&r1=1445543&r2=1445561&rev=1445561&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/VirAttrCacheKey.java Wed Feb 13 11:51:21 2013
@@ -18,28 +18,36 @@
*/
package org.apache.syncope.core.util;
+import org.apache.syncope.common.types.AttributableType;
+
/**
* Ccahe entry key.
*/
public class VirAttrCacheKey {
/**
- * User ID.
+ * Subject type.
+ */
+ private final AttributableType type;
+
+ /**
+ * Subject ID.
*/
- private final transient Long userId;
+ private final transient Long id;
/**
* Virtual attribute schema name.
*/
private final transient String virAttrSchema;
- public VirAttrCacheKey(final Long userId, final String virAttrSchema) {
- this.userId = userId;
+ public VirAttrCacheKey(final AttributableType type, final Long id, final String virAttrSchema) {
+ this.type = type;
+ this.id = id;
this.virAttrSchema = virAttrSchema;
}
- public Long getUserId() {
- return userId;
+ public Long getId() {
+ return id;
}
public String getVirAttrSchema() {
@@ -48,16 +56,17 @@ public class VirAttrCacheKey {
@Override
public int hashCode() {
- return 31 * (31
- + (userId == null ? 0 : userId.hashCode()))
- + virAttrSchema == null ? 0 : virAttrSchema.hashCode();
+ return 31 * (31 * (31
+ + (id == null ? 0 : id.hashCode()))
+ + (virAttrSchema == null ? 0 : virAttrSchema.hashCode()))
+ + (type == null ? 0 : type.hashCode());
}
@Override
public boolean equals(Object o) {
return o != null && o instanceof VirAttrCacheKey
- && ((userId == null && ((VirAttrCacheKey) o).getUserId() == null)
- || userId.equals(((VirAttrCacheKey) o).getUserId()))
+ && ((id == null && ((VirAttrCacheKey) o).getId() == null)
+ || id.equals(((VirAttrCacheKey) o).getId()))
&& ((virAttrSchema == null && ((VirAttrCacheKey) o).getVirAttrSchema() == null)
|| virAttrSchema.equals(((VirAttrCacheKey) o).getVirAttrSchema()));
}
Modified: syncope/trunk/core/src/main/resources/syncopeContext.xml
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/resources/syncopeContext.xml?rev=1445561&r1=1445560&r2=1445561&view=diff
==============================================================================
--- syncope/trunk/core/src/main/resources/syncopeContext.xml (original)
+++ syncope/trunk/core/src/main/resources/syncopeContext.xml Wed Feb 13 11:51:21 2013
@@ -88,5 +88,12 @@ under the License.
<property name="lenient" value="true"/>
<property name="silent" value="false"/>
</bean>
+
<bean id="jexlUtil" class="org.apache.syncope.core.util.JexlUtil"/>
+
+ <bean id="virAttrCache" class="org.apache.syncope.core.util.VirAttrCache" scope="singleton">
+ <constructor-arg value="60"/>
+ <constructor-arg value="5000"/>
+ <constructor-arg value="5"/>
+ </bean>
</beans>
Modified: syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java?rev=1445561&r1=1445560&r2=1445561&view=diff
==============================================================================
--- syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java (original)
+++ syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java Wed Feb 13 11:51:21 2013
@@ -1958,6 +1958,71 @@ public class UserTestITCase extends Abst
assertEquals(PropagationTaskExecStatus.SUCCESS, prop.getStatus());
}
+ @Test
+ public void virAttrCache() {
+ UserTO userTO = getUniqueSampleTO("virattrcache@apache.org");
+ userTO.getVirtualAttributes().clear();
+
+ AttributeTO virAttrTO = new AttributeTO();
+ virAttrTO.setSchema("virtualdata");
+ virAttrTO.addValue("virattrcache");
+ userTO.addVirtualAttribute(virAttrTO);
+
+ userTO.getMemberships().clear();
+ userTO.getResources().clear();
+ userTO.addResource("resource-db-virattr");
+
+ // 1. create user
+ UserTO actual = createUser(userTO);
+ assertNotNull(actual);
+
+ // 2. check for virtual attribute value
+ actual = userService.read(actual.getId());
+ assertEquals("virattrcache", actual.getVirtualAttributeMap().get("virtualdata").getValues().get(0));
+
+ Exception exception = null;
+ try {
+ final JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+
+ String value = jdbcTemplate.queryForObject(
+ "SELECT USERNAME FROM testsync WHERE ID=?", String.class, actual.getId());
+ assertEquals("virattrcache", value);
+
+ jdbcTemplate.update("UPDATE testsync set USERNAME='virattrcache2' WHERE ID=?", userTO.getId());
+
+ value = jdbcTemplate.queryForObject(
+ "SELECT USERNAME FROM testsync WHERE ID=?", String.class, userTO.getId());
+ assertEquals("virattrcache2", value);
+
+ } catch (EmptyResultDataAccessException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+
+ // 2. check for cached attribute value
+ actual = userService.read(actual.getId());
+ assertEquals("virattrcache", actual.getVirtualAttributeMap().get("virtualdata").getValues().get(0));
+
+ UserMod userMod = new UserMod();
+ userMod.setId(actual.getId());
+
+ AttributeMod virtualdata = new AttributeMod();
+ virtualdata.setSchema("virtualdata");
+ virtualdata.addValueToBeAdded("virtualupdated");
+
+ userMod.addVirtualAttributeToBeRemoved("virtualdata");
+ userMod.addVirtualAttributeToBeUpdated(virtualdata);
+
+ // 3. update virtual attribute
+ actual = userService.update(actual.getId(), userMod);
+ assertNotNull(actual);
+
+ // 4. check for virtual attribute value
+ actual = userService.read(actual.getId());
+ assertNotNull(actual);
+ assertEquals("virtualupdated", actual.getVirtualAttributeMap().get("virtualdata").getValues().get(0));
+ }
+
private boolean getBooleanAttribute(ConnObjectTO connObjectTO, String attrName) {
return Boolean.parseBoolean(getStringAttribute(connObjectTO, attrName));
}