[SYNCOPE-685] Pre: re-organize SyncPoliySpec
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/8fe3c7c2 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/8fe3c7c2 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/8fe3c7c2 Branch: refs/heads/SYNCOPE-156 Commit: 8fe3c7c20105df6112a1ee7b0206cb00e9c1a054 Parents: dbeb620 Author: Francesco Chicchiriccò <[email protected]> Authored: Mon Aug 17 16:54:18 2015 +0200 Committer: Francesco Chicchiriccò <[email protected]> Committed: Mon Aug 17 16:54:18 2015 +0200 ---------------------------------------------------------------------- .../console/panels/BeanReflectionModal.java | 36 -- .../console/panels/BeanReflectionPanel.java | 339 ------------------- .../common/lib/annotation/ClassList.java | 26 -- .../common/lib/annotation/SchemaList.java | 28 -- .../common/lib/types/AbstractPolicySpec.java | 2 - .../common/lib/types/SyncPolicySpec.java | 42 +-- .../common/lib/types/SyncPolicySpecItem.java | 67 ---- .../apache/syncope/core/logic/SyncopeLogic.java | 26 +- .../init/ImplementationClassNamesLoader.java | 7 +- .../core/persistence/jpa/inner/PolicyTest.java | 39 ++- .../test/resources/domains/MasterContent.xml | 8 +- .../java/data/PolicyDataBinderImpl.java | 3 - .../sync/PlainAttrsSyncCorrelationRule.java | 110 ++++++ .../core/provisioning/java/sync/SyncUtils.java | 126 ++----- .../fit/core/reference/PolicyITCase.java | 11 +- .../fit/core/reference/SyncTaskITCase.java | 12 +- 16 files changed, 193 insertions(+), 689 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanReflectionModal.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanReflectionModal.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanReflectionModal.java deleted file mode 100644 index a6859e8..0000000 --- a/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanReflectionModal.java +++ /dev/null @@ -1,36 +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.client.console.panels; - -import java.io.Serializable; -import org.apache.wicket.PageReference; -import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; - -/** - * Modal window with Resource form. - */ -public abstract class BeanReflectionModal extends ModalContent { - - private static final long serialVersionUID = 1734415311027284222L; - - public BeanReflectionModal(final Serializable bean, final ModalWindow window, final PageReference pageRef) { - super(window, pageRef); - add(new BeanReflectionPanel("bean", bean)); - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanReflectionPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanReflectionPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanReflectionPanel.java deleted file mode 100644 index 4f3f1d5..0000000 --- a/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanReflectionPanel.java +++ /dev/null @@ -1,339 +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.client.console.panels; - -import java.beans.PropertyDescriptor; -import java.io.Serializable; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import org.apache.syncope.client.console.commons.Constants; -import org.apache.syncope.client.console.rest.PolicyRestClient; -import org.apache.syncope.client.console.rest.SchemaRestClient; -import org.apache.syncope.client.console.wicket.markup.html.form.AbstractFieldPanel; -import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel; -import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel; -import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel; -import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel; -import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel; -import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel; -import org.apache.syncope.client.console.wicket.markup.html.form.SpinnerFieldPanel; -import org.apache.syncope.client.console.wicket.markup.html.list.AltListView; -import org.apache.syncope.common.lib.annotation.ClassList; -import org.apache.syncope.common.lib.annotation.SchemaList; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.list.ListItem; -import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Panel; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.LoadableDetachableModel; -import org.apache.wicket.model.Model; -import org.apache.wicket.model.PropertyModel; -import org.apache.wicket.model.ResourceModel; -import org.apache.wicket.model.util.ListModel; -import org.apache.wicket.spring.injection.annot.SpringBean; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.ReflectionUtils.FieldCallback; -import org.springframework.util.ReflectionUtils.FieldFilter; - -public class BeanReflectionPanel extends Panel { - - private static final long serialVersionUID = -3035998190456928143L; - - /** - * Logger. - */ - private static final Logger LOG = LoggerFactory.getLogger(BeanReflectionPanel.class); - - @SpringBean - private SchemaRestClient schemaRestClient; - - @SpringBean - private PolicyRestClient policyRestClient; - - private final IModel<List<String>> userSchemas = new LoadableDetachableModel<List<String>>() { - - private static final long serialVersionUID = -2012833443695917883L; - - @Override - protected List<String> load() { - return schemaRestClient.getPlainSchemaNames(); - } - }; - - private final IModel<List<String>> groupSchemas = new LoadableDetachableModel<List<String>>() { - - private static final long serialVersionUID = 5275935387613157437L; - - @Override - protected List<String> load() { - return schemaRestClient.getPlainSchemaNames(); - } - }; - - private final IModel<List<String>> correlationRules = new LoadableDetachableModel<List<String>>() { - - private static final long serialVersionUID = 5275935387613157437L; - - @Override - protected List<String> load() { - return policyRestClient.getCorrelationRuleClasses(); - } - }; - - public BeanReflectionPanel(final String id, final Serializable bean) { - super(id); - - final List<FieldWrapper> items = new ArrayList<>(); - ReflectionUtils.doWithFields(bean.getClass(), - new FieldCallback() { - - @Override - public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException { - FieldWrapper fieldWrapper = new FieldWrapper(); - fieldWrapper.setName(field.getName()); - fieldWrapper.setType(field.getType()); - - final SchemaList schemaList = field.getAnnotation(SchemaList.class); - fieldWrapper.setSchemaList(schemaList); - - final ClassList classList = field.getAnnotation(ClassList.class); - fieldWrapper.setClassList(classList); - - items.add(fieldWrapper); - } - }, - new FieldFilter() { - - @Override - public boolean matches(final Field field) { - return !Modifier.isStatic(field.getModifiers()) && !"serialVersionUID".equals(field.getName()); - } - }); - - final ListView<FieldWrapper> policies = new AltListView<FieldWrapper>("fields", items) { - - private static final long serialVersionUID = 9101744072914090143L; - - @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected void populateItem(final ListItem<FieldWrapper> item) { - final FieldWrapper field = item.getModelObject(); - - final PropertyDescriptor propDesc = BeanUtils.getPropertyDescriptor(bean.getClass(), field.getName()); - - item.add(new Label("label", new ResourceModel(field.getName()))); - - AbstractFieldPanel component; - try { - if (field.getClassList() != null) { - component = new AjaxDropDownChoicePanel("field", field.getName(), new PropertyModel(bean, - field.getName())); - - final List<String> rules = correlationRules.getObject(); - - if (rules != null && !rules.isEmpty()) { - ((AjaxDropDownChoicePanel) component).setChoices(correlationRules.getObject()); - } - - item.add(component); - - item.add(getActivationControl( - component, - propDesc.getReadMethod().invoke(bean, new Object[] {}) != null, - null, - null)); - - } else if (field.getType().isEnum()) { - component = new AjaxDropDownChoicePanel("field", field.getName(), new PropertyModel(bean, - field.getName())); - - final Serializable[] values = (Serializable[]) field.getType().getEnumConstants(); - - if (values != null && values.length > 0) { - ((AjaxDropDownChoicePanel) component).setChoices(Arrays.asList(values)); - } - - item.add(component); - - item.add(getActivationControl( - component, - (Enum<?>) propDesc.getReadMethod().invoke(bean, new Object[] {}) != null, - values[0], - values[0])); - - } else if (ClassUtils.isAssignable(Boolean.class, field.getType())) { - item.add(new AjaxCheckBoxPanel("check", field.getName(), - new PropertyModel<Boolean>(bean, field.getName()))); - - item.add(new Label("field", new Model(null))); - } else if (Collection.class.isAssignableFrom(field.getType())) { - if (field.getSchemaList() != null) { - final List<String> values = new ArrayList<>(); - if (field.getName().charAt(0) == 'r') { - values.addAll(groupSchemas.getObject()); - - if (field.getSchemaList().extended()) { - values.add("name"); - } - } else { - values.addAll(userSchemas.getObject()); - - if (field.getSchemaList().extended()) { - values.add("key"); - values.add("username"); - } - } - - component = new AjaxPalettePanel("field", new PropertyModel(bean, field.getName()), - new ListModel<>(values)); - item.add(component); - - Collection<?> collection = (Collection) propDesc.getReadMethod().invoke(bean); - item.add(getActivationControl(component, - !collection.isEmpty(), new ArrayList<String>(), new ArrayList<String>())); - } else { - final FieldPanel panel = new AjaxTextFieldPanel("panel", field.getName(), - new Model<String>(null)); - panel.setRequired(true); - - component = new MultiFieldPanel<String>("field", - new PropertyModel(bean, field.getName()), panel); - - item.add(component); - - final List<String> reinitializedValue = new ArrayList<String>(); - - reinitializedValue.add(""); - - item.add(getActivationControl(component, - !((Collection) propDesc.getReadMethod().invoke(bean, new Object[] {})).isEmpty(), - new ArrayList<String>(), (Serializable) reinitializedValue)); - } - } else if (ClassUtils.isAssignable(Number.class, field.getType())) { - component = new SpinnerFieldPanel<Number>("field", field.getName(), - (Class<Number>) field.getType(), new PropertyModel<Number>(bean, field.getName()), - null, null); - item.add(component); - - item.add(getActivationControl(component, - (Integer) propDesc.getReadMethod().invoke(bean, new Object[] {}) > 0, 0, 0)); - } else if (field.getType().equals(String.class)) { - component = new AjaxTextFieldPanel("field", field.getName(), - new PropertyModel(bean, field.getName())); - - item.add(component); - - item.add(getActivationControl(component, - propDesc.getReadMethod().invoke(bean, new Object[] {}) != null, null, null)); - } else { - item.add(new AjaxCheckBoxPanel("check", field.getName(), new Model())); - item.add(new Label("field", new Model(null))); - } - } catch (Exception e) { - LOG.error("Error retrieving bean fields", e); - } - } - }; - - add(policies); - } - - private <T extends Serializable> AjaxCheckBoxPanel getActivationControl(final AbstractFieldPanel<T> panel, - final Boolean checked, final T defaultModelObject, final T reinitializedValue) { - - final AjaxCheckBoxPanel check = new AjaxCheckBoxPanel("check", "check", new Model<Boolean>(checked)); - - panel.setEnabled(checked); - - check.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { - - private static final long serialVersionUID = -1107858522700306810L; - - @Override - protected void onUpdate(final AjaxRequestTarget target) { - if (check.getModelObject()) { - panel.setEnabled(true); - panel.setModelObject(reinitializedValue); - } else { - panel.setModelObject(defaultModelObject); - panel.setEnabled(false); - } - - target.add(panel); - } - }); - - return check; - } - - private static class FieldWrapper implements Serializable { - - private static final long serialVersionUID = -6770429509752964215L; - - private Class<?> type; - - private String name; - - private transient SchemaList schemaList; - - private transient ClassList classList; - - public String getName() { - return name; - } - - public void setName(final String name) { - this.name = name; - } - - public Class<?> getType() { - return type; - } - - public void setType(final Class<?> type) { - this.type = type; - } - - public SchemaList getSchemaList() { - return schemaList; - } - - public void setSchemaList(final SchemaList schemaList) { - this.schemaList = schemaList; - } - - public ClassList getClassList() { - return classList; - } - - public void setClassList(final ClassList classList) { - this.classList = classList; - } - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/common/lib/src/main/java/org/apache/syncope/common/lib/annotation/ClassList.java ---------------------------------------------------------------------- diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/annotation/ClassList.java b/common/lib/src/main/java/org/apache/syncope/common/lib/annotation/ClassList.java deleted file mode 100644 index 07528ea..0000000 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/annotation/ClassList.java +++ /dev/null @@ -1,26 +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.common.lib.annotation; - -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Retention(RUNTIME) -public @interface ClassList { -} http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/common/lib/src/main/java/org/apache/syncope/common/lib/annotation/SchemaList.java ---------------------------------------------------------------------- diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/annotation/SchemaList.java b/common/lib/src/main/java/org/apache/syncope/common/lib/annotation/SchemaList.java deleted file mode 100644 index 7469731..0000000 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/annotation/SchemaList.java +++ /dev/null @@ -1,28 +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.common.lib.annotation; - -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Retention(RUNTIME) -public @interface SchemaList { - - boolean extended() default false; -} http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/common/lib/src/main/java/org/apache/syncope/common/lib/types/AbstractPolicySpec.java ---------------------------------------------------------------------- diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/AbstractPolicySpec.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/AbstractPolicySpec.java index e1e7333..33a0c62 100644 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/AbstractPolicySpec.java +++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/AbstractPolicySpec.java @@ -28,7 +28,6 @@ import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; -import org.apache.syncope.common.lib.annotation.SchemaList; @XmlType public abstract class AbstractPolicySpec implements PolicySpec { @@ -43,7 +42,6 @@ public abstract class AbstractPolicySpec implements PolicySpec { /** * User attribute values not permitted. */ - @SchemaList protected final List<String> schemasNotPermitted = new ArrayList<>(); /** http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpec.java ---------------------------------------------------------------------- diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpec.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpec.java index 34f95dd..5a3d309 100644 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpec.java +++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpec.java @@ -18,26 +18,32 @@ */ package org.apache.syncope.common.lib.types; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.ArrayList; -import java.util.List; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; +import java.util.HashMap; +import java.util.Map; import javax.xml.bind.annotation.XmlType; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.Predicate; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import org.apache.syncope.common.lib.jaxb.XmlGenericMapAdapter; @XmlType public class SyncPolicySpec implements PolicySpec { private static final long serialVersionUID = -3144027171719498127L; - private final List<SyncPolicySpecItem> items = new ArrayList<>(); + private ConflictResolutionAction conflictResolutionAction; /** - * Conflict resolution action. + * Associates anyTypeKey to either: + * <ol> + * <li>Java class name, implementing {@code SyncCorrelationRule}</li> + * <li>JSON array containing plain schema names - this will be used to feed + * {@code PlainAttrsSyncCorrelationRule}</li> + * </ol> */ - private ConflictResolutionAction conflictResolutionAction; + @XmlJavaTypeAdapter(XmlGenericMapAdapter.class) + @JsonIgnore + private final Map<String, String> correlationRules = new HashMap<>(); public ConflictResolutionAction getConflictResolutionAction() { return conflictResolutionAction == null @@ -49,20 +55,8 @@ public class SyncPolicySpec implements PolicySpec { this.conflictResolutionAction = conflictResolutionAction; } - public SyncPolicySpecItem getItem(final String anyTypeKey) { - return CollectionUtils.find(items, new Predicate<SyncPolicySpecItem>() { - - @Override - public boolean evaluate(final SyncPolicySpecItem item) { - return anyTypeKey != null && anyTypeKey.equals(item.getAnyTypeKey()); - } - }); - } - - @XmlElementWrapper(name = "items") - @XmlElement(name = "item") - @JsonProperty("items") - public List<SyncPolicySpecItem> getItems() { - return items; + @JsonProperty + public Map<String, String> getCorrelationRules() { + return correlationRules; } } http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpecItem.java ---------------------------------------------------------------------- diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpecItem.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpecItem.java deleted file mode 100644 index 4acb61b..0000000 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/SyncPolicySpecItem.java +++ /dev/null @@ -1,67 +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.common.lib.types; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.ArrayList; -import java.util.List; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; -import javax.xml.bind.annotation.XmlType; -import org.apache.syncope.common.lib.AbstractBaseBean; -import org.apache.syncope.common.lib.annotation.ClassList; -import org.apache.syncope.common.lib.annotation.SchemaList; - -@XmlType -public class SyncPolicySpecItem extends AbstractBaseBean { - - private static final long serialVersionUID = 692466729711976485L; - - private String anyTypeKey; - - @SchemaList(extended = true) - private final List<String> altSearchSchemas = new ArrayList<>(); - - @ClassList - private String javaRule; - - public String getAnyTypeKey() { - return anyTypeKey; - } - - public void setAnyTypeKey(final String anyTypeKey) { - this.anyTypeKey = anyTypeKey; - } - - public String getJavaRule() { - return javaRule; - } - - public void setJavaRule(final String javaRule) { - this.javaRule = javaRule; - } - - @XmlElementWrapper(name = "altSearchSchemas") - @XmlElement(name = "altSearchSchema") - @JsonProperty("altSearchSchemas") - public List<String> getAltSearchSchemas() { - return altSearchSchemas; - } - -} http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java ---------------------------------------------------------------------- diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java index 8dd20a8..d6432e2 100644 --- a/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java +++ b/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java @@ -18,6 +18,8 @@ */ package org.apache.syncope.core.logic; +import static org.apache.syncope.core.logic.init.ImplementationClassNamesLoader.Type; + import java.io.IOException; import java.lang.reflect.Method; import java.net.URI; @@ -128,22 +130,14 @@ public class SyncopeLogic extends AbstractLogic<SyncopeTO> { syncopeTO.setGroupProvisioningManager(gProvisioningManager.getClass().getName()); syncopeTO.setVirAttrCache(virAttrCache.getClass().getName()); - syncopeTO.getReportlets().addAll( - classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.REPORTLET)); - syncopeTO.getTaskJobs().addAll( - classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.TASKJOBDELEGATE)); - syncopeTO.getPropagationActions().addAll( - classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.PROPAGATION_ACTIONS)); - syncopeTO.getSyncActions().addAll( - classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.SYNC_ACTIONS)); - syncopeTO.getPushActions().addAll( - classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.PUSH_ACTIONS)); - syncopeTO.getSyncCorrelationRules().addAll( - classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.SYNC_CORRELATION_RULE)); - syncopeTO.getPushCorrelationRules().addAll( - classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.PUSH_CORRELATION_RULE)); - syncopeTO.getValidators().addAll( - classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.VALIDATOR)); + syncopeTO.getReportlets().addAll(classNamesLoader.getClassNames(Type.REPORTLET)); + syncopeTO.getTaskJobs().addAll(classNamesLoader.getClassNames(Type.TASKJOBDELEGATE)); + syncopeTO.getPropagationActions().addAll(classNamesLoader.getClassNames(Type.PROPAGATION_ACTIONS)); + syncopeTO.getSyncActions().addAll(classNamesLoader.getClassNames(Type.SYNC_ACTIONS)); + syncopeTO.getPushActions().addAll(classNamesLoader.getClassNames(Type.PUSH_ACTIONS)); + syncopeTO.getSyncCorrelationRules().addAll(classNamesLoader.getClassNames(Type.SYNC_CORRELATION_RULE)); + syncopeTO.getPushCorrelationRules().addAll(classNamesLoader.getClassNames(Type.PUSH_CORRELATION_RULE)); + syncopeTO.getValidators().addAll(classNamesLoader.getClassNames(Type.VALIDATOR)); Set<String> htmlTemplates = new HashSet<>(); Set<String> textTemplates = new HashSet<>(); http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/core/logic/src/main/java/org/apache/syncope/core/logic/init/ImplementationClassNamesLoader.java ---------------------------------------------------------------------- diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ImplementationClassNamesLoader.java b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ImplementationClassNamesLoader.java index 2bcd78f..1b53e5c 100644 --- a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ImplementationClassNamesLoader.java +++ b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ImplementationClassNamesLoader.java @@ -62,9 +62,6 @@ public class ImplementationClassNamesLoader implements SyncopeLoader { } - /** - * Logger. - */ private static final Logger LOG = LoggerFactory.getLogger(ImplementationClassNamesLoader.class); private Map<Type, Set<String>> classNames; @@ -87,7 +84,7 @@ public class ImplementationClassNamesLoader implements SyncopeLoader { scanner.addIncludeFilter(new AssignableTypeFilter(SyncActions.class)); scanner.addIncludeFilter(new AssignableTypeFilter(PushActions.class)); scanner.addIncludeFilter(new AssignableTypeFilter(SyncCorrelationRule.class)); - // Remove once SYNCOPE-631 is done + // Remove once SYNCOPE-470 is done //scanner.addIncludeFilter(new AssignableTypeFilter(PushCorrelationRule.class)); scanner.addIncludeFilter(new AssignableTypeFilter(PropagationActions.class)); scanner.addIncludeFilter(new AssignableTypeFilter(Validator.class)); @@ -121,7 +118,7 @@ public class ImplementationClassNamesLoader implements SyncopeLoader { classNames.get(Type.SYNC_CORRELATION_RULE).add(bd.getBeanClassName()); } - // Uncomment when SYNCOPE-631 is done + // Uncomment when SYNCOPE-470 is done /* if (PushCorrelationRule.class.isAssignableFrom(clazz) && !isAbsractClazz) { * classNames.get(Type.PUSH_CORRELATION_RULES).add(metadata.getClassName()); * } */ http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java index c75a148..603cd01 100644 --- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java +++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java @@ -22,12 +22,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.util.List; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.common.lib.types.PasswordPolicySpec; import org.apache.syncope.common.lib.types.PolicyType; import org.apache.syncope.common.lib.types.SyncPolicySpec; -import org.apache.syncope.common.lib.types.SyncPolicySpecItem; +import org.apache.syncope.core.misc.serialization.POJOHelper; import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException; import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO; import org.apache.syncope.core.persistence.api.dao.PolicyDAO; @@ -55,9 +58,20 @@ public class PolicyTest extends AbstractTest { } @Test - public void findById() { - Policy policy = policyDAO.find(1L); + public void findByKey() { + SyncPolicy policy = policyDAO.find(3L); assertNotNull("findById did not work", policy); + + SyncPolicySpec spec = policy.getSpecification(SyncPolicySpec.class); + assertNotNull(spec); + + String rule = spec.getCorrelationRules().get(AnyTypeKind.USER.name()); + assertNotNull(rule); + String[] plainSchemas = POJOHelper.deserialize(rule, String[].class); + assertNotNull(plainSchemas); + assertEquals(2, plainSchemas.length); + assertTrue(ArrayUtils.contains(plainSchemas, "username")); + assertTrue(ArrayUtils.contains(plainSchemas, "firstname")); } @Test @@ -89,15 +103,8 @@ public class PolicyTest extends AbstractTest { SyncPolicySpec syncPolicySpec = new SyncPolicySpec(); - SyncPolicySpecItem item = new SyncPolicySpecItem(); - item.setAnyTypeKey(anyTypeDAO.findUser().getKey()); - item.setJavaRule(syncURuleName); - syncPolicySpec.getItems().add(item); - - item = new SyncPolicySpecItem(); - item.setAnyTypeKey(anyTypeDAO.findGroup().getKey()); - item.setJavaRule(syncGRuleName); - syncPolicySpec.getItems().add(item); + syncPolicySpec.getCorrelationRules().put(anyTypeDAO.findUser().getKey(), syncURuleName); + syncPolicySpec.getCorrelationRules().put(anyTypeDAO.findGroup().getKey(), syncGRuleName); policy.setSpecification(syncPolicySpec); policy.setDescription("Sync policy"); @@ -106,10 +113,10 @@ public class PolicyTest extends AbstractTest { assertNotNull(policy); assertEquals(PolicyType.SYNC, policy.getType()); - assertEquals(syncURuleName, - (policy.getSpecification(SyncPolicySpec.class)).getItem(anyTypeDAO.findUser().getKey()).getJavaRule()); - assertEquals(syncGRuleName, - (policy.getSpecification(SyncPolicySpec.class)).getItem(anyTypeDAO.findGroup().getKey()).getJavaRule()); + assertEquals(syncURuleName, (policy.getSpecification(SyncPolicySpec.class)). + getCorrelationRules().get(anyTypeDAO.findUser().getKey())); + assertEquals(syncGRuleName, (policy.getSpecification(SyncPolicySpec.class)). + getCorrelationRules().get(anyTypeDAO.findGroup().getKey())); } @Test http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/core/persistence-jpa/src/test/resources/domains/MasterContent.xml ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml index 37ff60f..5977c9a 100644 --- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml +++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml @@ -101,11 +101,11 @@ under the License. <!-- sample policies --> <Policy DTYPE="SyncPolicy" id="1" description="a sync policy" type="SYNC" - specification='{"conflictResolutionAction":"IGNORE","items":[]}'/> + specification='{"conflictResolutionAction":"IGNORE"'/> <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='{"conflictResolutionAction":"ALL","items":[{"anyTypeKey":"USER","javaRule":null,"altSearchSchemas":["username","firstname"]}]}'/> + specification='{"conflictResolutionAction":"ALL","correlationRules":{"USER":"[\"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" @@ -113,11 +113,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='{"conflictResolutionAction":"IGNORE","items":[]}'/> + specification='{"conflictResolutionAction":"IGNORE"}'/> <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='{"conflictResolutionAction":"IGNORE","items":[]}'/> + specification='{"conflictResolutionAction":"IGNORE"}'/> <RelationshipType name="inclusion" description="Models the act that an object is included in another"/> <RelationshipType name="neighborhood"/> http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java index fde025d..fa53bbd 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java @@ -45,9 +45,6 @@ import org.springframework.stereotype.Component; @Component public class PolicyDataBinderImpl implements PolicyDataBinder { - /** - * Logger. - */ private static final Logger LOG = LoggerFactory.getLogger(PolicyDataBinder.class); @Autowired http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java new file mode 100644 index 0000000..1af195e --- /dev/null +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java @@ -0,0 +1,110 @@ +/* + * 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.sync; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.syncope.common.lib.types.MappingPurpose; +import org.apache.syncope.core.misc.MappingUtils; +import org.apache.syncope.core.persistence.api.dao.search.AnyCond; +import org.apache.syncope.core.persistence.api.dao.search.AttributeCond; +import org.apache.syncope.core.persistence.api.dao.search.SearchCond; +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.provisioning.api.sync.SyncCorrelationRule; +import org.identityconnectors.framework.common.objects.Attribute; +import org.identityconnectors.framework.common.objects.ConnectorObject; + +public class PlainAttrsSyncCorrelationRule implements SyncCorrelationRule { + + private final List<String> plainSchemaNames; + + private final Provision provision; + + public PlainAttrsSyncCorrelationRule(final String[] plainSchemaNames, final Provision provision) { + this.plainSchemaNames = Arrays.asList(plainSchemaNames); + this.provision = provision; + } + + @Override + public SearchCond getSearchCond(final ConnectorObject connObj) { + // search for external attribute's name/value of each specified name + Map<String, Attribute> extValues = new HashMap<>(); + + for (MappingItem item : MappingUtils.getMappingItems(provision, MappingPurpose.SYNCHRONIZATION)) { + extValues.put(item.getIntAttrName(), connObj.getAttributeByName(item.getExtAttrName())); + } + + // search for user/group by attribute(s) specified in the policy + SearchCond searchCond = null; + + for (String schema : plainSchemaNames) { + Attribute value = extValues.get(schema); + + if (value == null) { + throw new IllegalArgumentException( + "Connector object does not contains the attributes to perform the search: " + schema); + } + + AttributeCond.Type type; + String expression = null; + + if (value.getValue() == null || value.getValue().isEmpty() + || (value.getValue().size() == 1 && value.getValue().get(0) == null)) { + + type = AttributeCond.Type.ISNULL; + } else { + type = AttributeCond.Type.EQ; + expression = value.getValue().size() > 1 + ? value.getValue().toString() + : value.getValue().get(0).toString(); + } + + SearchCond nodeCond; + // users: just id or username can be selected to be used + // groups: just id or name can be selected to be used + if ("key".equalsIgnoreCase(schema) + || "username".equalsIgnoreCase(schema) || "name".equalsIgnoreCase(schema)) { + + AnyCond cond = new AnyCond(); + cond.setSchema(schema); + cond.setType(type); + cond.setExpression(expression); + + nodeCond = SearchCond.getLeafCond(cond); + } else { + AttributeCond cond = new AttributeCond(); + cond.setSchema(schema); + cond.setType(type); + cond.setExpression(expression); + + nodeCond = SearchCond.getLeafCond(cond); + } + + searchCond = searchCond == null + ? nodeCond + : SearchCond.getAndCond(searchCond, nodeCond); + } + + return searchCond; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java index dc5cdf0..7fd244b 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java @@ -20,15 +20,14 @@ package org.apache.syncope.core.provisioning.java.sync; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.SyncopeConstants; import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.common.lib.types.MappingPurpose; import org.apache.syncope.common.lib.types.SyncPolicySpec; import org.apache.syncope.core.misc.MappingUtils; +import org.apache.syncope.core.misc.serialization.POJOHelper; import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException; import org.apache.syncope.core.persistence.api.dao.AnyDAO; import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; @@ -36,10 +35,7 @@ import org.apache.syncope.core.persistence.api.dao.AnySearchDAO; import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO; 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.search.AnyCond; -import org.apache.syncope.core.persistence.api.dao.search.AttributeCond; import org.apache.syncope.core.persistence.api.dao.search.OrderByClause; -import org.apache.syncope.core.persistence.api.dao.search.SearchCond; 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; @@ -230,11 +226,15 @@ public class SyncUtils { return result; } - private List<Long> search(final SearchCond searchCond, final AnyTypeKind type) { - final List<Long> result = new ArrayList<>(); + private List<Long> findByCorrelationRule( + final ConnectorObject connObj, final SyncCorrelationRule rule, final AnyTypeKind type) { + + List<Long> result = new ArrayList<>(); List<Any<?, ?, ?>> anys = searchDAO.search( - SyncopeConstants.FULL_ADMIN_REALMS, searchCond, Collections.<OrderByClause>emptyList(), type); + SyncopeConstants.FULL_ADMIN_REALMS, + rule.getSearchCond(connObj), + Collections.<OrderByClause>emptyList(), type); for (Any<?, ?, ?> any : anys) { result.add(any.getKey()); } @@ -242,101 +242,24 @@ public class SyncUtils { return result; } - private List<Long> findByCorrelationRule( - final ConnectorObject connObj, final SyncCorrelationRule rule, final AnyTypeKind type) { - - return search(rule.getSearchCond(connObj), type); - } - - private List<Long> findByAnySearch( - final ConnectorObject connObj, - final List<String> altSearchSchemas, - final Provision provision, - final AnyTypeKind anyTypeKind) { - - // search for external attribute's name/value of each specified name - Map<String, Attribute> extValues = new HashMap<>(); - - for (MappingItem item : MappingUtils.getMappingItems(provision, MappingPurpose.SYNCHRONIZATION)) { - extValues.put(item.getIntAttrName(), connObj.getAttributeByName(item.getExtAttrName())); - } - - // search for user/group by attribute(s) specified in the policy - SearchCond searchCond = null; - - for (String schema : altSearchSchemas) { - Attribute value = extValues.get(schema); - - if (value == null) { - throw new IllegalArgumentException( - "Connector object does not contains the attributes to perform the search: " + schema); - } - - AttributeCond.Type type; - String expression = null; - - if (value.getValue() == null || value.getValue().isEmpty() - || (value.getValue().size() == 1 && value.getValue().get(0) == null)) { - - type = AttributeCond.Type.ISNULL; - } else { - type = AttributeCond.Type.EQ; - expression = value.getValue().size() > 1 - ? value.getValue().toString() - : value.getValue().get(0).toString(); - } - - SearchCond nodeCond; - // users: just id or username can be selected to be used - // groups: just id or name can be selected to be used - if ("key".equalsIgnoreCase(schema) - || "username".equalsIgnoreCase(schema) || "name".equalsIgnoreCase(schema)) { - - AnyCond cond = new AnyCond(); - cond.setSchema(schema); - cond.setType(type); - cond.setExpression(expression); - - nodeCond = SearchCond.getLeafCond(cond); - } else { - AttributeCond cond = new AttributeCond(); - cond.setSchema(schema); - cond.setType(type); - cond.setExpression(expression); - - nodeCond = SearchCond.getLeafCond(cond); - } - - searchCond = searchCond == null - ? nodeCond - : SearchCond.getAndCond(searchCond, nodeCond); - } - - return search(searchCond, anyTypeKind); - } - private SyncCorrelationRule getCorrelationRule(final Provision provision, final SyncPolicySpec policySpec) { - String clazz = policySpec.getItem(provision.getAnyType().getKey()) == null - ? null - : policySpec.getItem(provision.getAnyType().getKey()).getJavaRule(); - - SyncCorrelationRule res = null; + SyncCorrelationRule result = null; - if (StringUtils.isNotBlank(clazz)) { - try { - res = (SyncCorrelationRule) Class.forName(clazz).newInstance(); - } catch (Exception e) { - LOG.error("Failure instantiating correlation rule class '{}'", clazz, e); + String syncCorrelationRule = policySpec.getCorrelationRules().get(provision.getAnyType().getKey()); + if (StringUtils.isNotBlank(syncCorrelationRule)) { + if (syncCorrelationRule.charAt(0) == '[') { + result = new PlainAttrsSyncCorrelationRule( + POJOHelper.deserialize(syncCorrelationRule, String[].class), provision); + } else { + try { + result = (SyncCorrelationRule) Class.forName(syncCorrelationRule).newInstance(); + } catch (Exception e) { + LOG.error("Failure instantiating correlation rule class '{}'", syncCorrelationRule, e); + } } } - return res; - } - - private List<String> getAltSearchSchemas(final Provision provision, final SyncPolicySpec policySpec) { - return policySpec.getItem(provision.getAnyType().getKey()) == null - ? Collections.<String>emptyList() - : policySpec.getItem(provision.getAnyType().getKey()).getAltSearchSchemas(); + return result; } /** @@ -360,17 +283,12 @@ public class SyncUtils { } SyncCorrelationRule syncRule = null; - List<String> altSearchSchemas = null; - if (syncPolicySpec != null) { syncRule = getCorrelationRule(provision, syncPolicySpec); - altSearchSchemas = getAltSearchSchemas(provision, syncPolicySpec); } return syncRule == null - ? altSearchSchemas == null || altSearchSchemas.isEmpty() - ? findByConnObjectKeyItem(uid, provision, anyUtils) - : findByAnySearch(connObj, altSearchSchemas, provision, anyUtils.getAnyTypeKind()) + ? findByConnObjectKeyItem(uid, provision, anyUtils) : findByCorrelationRule(connObj, syncRule, anyUtils.getAnyTypeKind()); } http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PolicyITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PolicyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PolicyITCase.java index 0098821..95701ae 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PolicyITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PolicyITCase.java @@ -36,7 +36,6 @@ import org.apache.syncope.common.lib.types.ClientExceptionType; import org.apache.syncope.common.lib.types.PasswordPolicySpec; import org.apache.syncope.common.lib.types.PolicyType; import org.apache.syncope.common.lib.types.SyncPolicySpec; -import org.apache.syncope.common.lib.types.SyncPolicySpecItem; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -47,12 +46,8 @@ public class PolicyITCase extends AbstractITCase { private SyncPolicyTO buildSyncPolicyTO() { SyncPolicyTO policy = new SyncPolicyTO(); - SyncPolicySpecItem item = new SyncPolicySpecItem(); - item.setAnyTypeKey(AnyTypeKind.USER.name()); - item.setJavaRule(TestSyncRule.class.getName()); - SyncPolicySpec spec = new SyncPolicySpec(); - spec.getItems().add(item); + spec.getCorrelationRules().put(AnyTypeKind.USER.name(), TestSyncRule.class.getName()); policy.setSpecification(spec); policy.setDescription("Sync policy"); @@ -116,7 +111,7 @@ public class PolicyITCase extends AbstractITCase { assertNotNull(policyTO); assertEquals(PolicyType.SYNC, policyTO.getType()); assertEquals(TestSyncRule.class.getName(), - policyTO.getSpecification().getItem(AnyTypeKind.USER.name()).getJavaRule()); + policyTO.getSpecification().getCorrelationRules().get(AnyTypeKind.USER.name())); } @Test @@ -169,7 +164,7 @@ public class PolicyITCase extends AbstractITCase { @Test public void getCorrelationRules() { - assertEquals(1, syncopeService.info().getSyncCorrelationRules().size()); + assertEquals(2, syncopeService.info().getSyncCorrelationRules().size()); } @Test http://git-wip-us.apache.org/repos/asf/syncope/blob/8fe3c7c2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java index 4313c00..d97eaed 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java @@ -55,7 +55,6 @@ import org.apache.syncope.common.lib.types.CipherAlgorithm; import org.apache.syncope.common.lib.types.ConnConfProperty; import org.apache.syncope.common.lib.types.PropagationTaskExecStatus; import org.apache.syncope.common.lib.types.ResourceDeassociationActionType; -import org.apache.syncope.common.lib.types.SyncPolicySpecItem; import org.apache.syncope.common.lib.types.TaskType; import org.apache.syncope.common.lib.wrap.ResourceKey; import org.apache.syncope.common.rest.api.CollectionWrapper; @@ -505,16 +504,7 @@ public class SyncTaskITCase extends AbstractTaskITCase { // Add a custom correlation rule // ----------------------------- SyncPolicyTO policyTO = policyService.read(9L); - - SyncPolicySpecItem item = policyTO.getSpecification().getItem(AnyTypeKind.USER.name()); - if (item == null) { - item = new SyncPolicySpecItem(); - item.setAnyTypeKey(AnyTypeKind.USER.name()); - - policyTO.getSpecification().getItems().add(item); - } - item.setJavaRule(TestSyncRule.class.getName()); - + policyTO.getSpecification().getCorrelationRules().put(AnyTypeKind.USER.name(), TestSyncRule.class.getName()); policyService.update(policyTO); // -----------------------------
