/*
* 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.policies;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.Constants;
import org.apache.syncope.client.console.pages.BasePage;
import org.apache.syncope.client.console.panels.AbstractModalPanel;
import org.apache.syncope.client.console.rest.AnyTypeRestClient;
import org.apache.syncope.client.console.rest.PolicyRestClient;
import org.apache.syncope.client.console.rest.SchemaRestClient;
import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
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.MultiPanel;
import org.apache.syncope.common.lib.policy.PullPolicyTO;
import org.apache.syncope.common.lib.to.AbstractSchemaTO;
import org.apache.syncope.common.lib.to.AnyTypeTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
public class PolicySpecModalPanel extends AbstractModalPanel<PullPolicyTO> {
private static final long serialVersionUID = 5945391813567245081L;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final IModel<List<CorrelationRule>> model;
private final PolicyRestClient restClient = new PolicyRestClient();
public PolicySpecModalPanel(
final PullPolicyTO policyTO, final BaseModal<PullPolicyTO> modal, final PageReference pageRef) {
super(modal, pageRef);
modal.setFormModel(policyTO);
add(new AjaxDropDownChoicePanel<>(
"conflictResolutionAction",
"conflictResolutionAction",
new PropertyModel<ConflictResolutionAction>(policyTO.getSpecification(), "conflictResolutionAction")).
setChoices(Arrays.asList(ConflictResolutionAction.values())));
model = new PropertyModel<List<CorrelationRule>>(policyTO.getSpecification(), "correlationRules") {
private static final long serialVersionUID = -8168676563540297301L;
private List<CorrelationRule> rules = CollectionUtils.collect(
policyTO.getSpecification().getCorrelationRules() == null
? Collections.<String>emptySet()
: policyTO.getSpecification().getCorrelationRules().keySet(),
new Transformer<String, CorrelationRule>() {
@Override
public CorrelationRule transform(final String input) {
return new CorrelationRule(
input, policyTO.getSpecification().getCorrelationRules().get(input));
}
}, new ArrayList<CorrelationRule>());
@Override
public List<CorrelationRule> getObject() {
return rules;
}
@Override
public void setObject(final List<CorrelationRule> object) {
policyTO.getSpecification().getCorrelationRules().clear();
for (CorrelationRule rule : rules) {
policyTO.getSpecification().getCorrelationRules().put(rule.getAny(), rule.getRule());
}
}
};
add(new MultiPanel<CorrelationRule>("correlationRules", "correlationRules", model) {
private static final long serialVersionUID = -2481579077338205547L;
@Override
protected CorrelationRule newModelObject() {
return new CorrelationRule();
}
@Override
protected CorrelationRulePanel getItemPanel(final ListItem<CorrelationRule> item) {
return new CorrelationRulePanel("panel", Model.of(item.getModelObject()));
}
});
}
@Override
public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
try {
getItem().getSpecification().getCorrelationRules().clear();
for (CorrelationRule rule : model.getObject()) {
getItem().getSpecification().getCorrelationRules().put(rule.getAny(), rule.getRule());
}
restClient.updatePolicy(getItem());
SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
this.modal.close(target);
} catch (Exception e) {
LOG.error("While creating/updating policy", e);
SyncopeConsoleSession.get().error(
StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
}
((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
}
public static class CorrelationRulePanel extends Panel {
private static final long serialVersionUID = -4708008994320210839L;
public CorrelationRulePanel(final String id, final IModel<CorrelationRule> rule) {
super(id);
AjaxDropDownChoicePanel<String> anyType = new AjaxDropDownChoicePanel<>(
"anyType", "any.type", new PropertyModel<String>(rule.getObject(), "any")).
setNullValid(true).
setChoices(CollectionUtils.collect(
new AnyTypeRestClient().list(),
new Transformer<AnyTypeTO, String>() {
@Override
public String transform(final AnyTypeTO input) {
return input.getKey();
}
}, new ArrayList<String>()));
add(anyType);
final AjaxDropDownChoicePanel<String> ruleType = new AjaxDropDownChoicePanel<>(
"ruleType", "rule.type", new PropertyModel<String>(rule.getObject(), "type"), false).
setNullValid(true).
setChoices(Arrays.asList("PLAIN ATTRIBUTES", "JAVA"));
add(ruleType);
// ---------------------------------------------------------------
// Java rule palette
// ---------------------------------------------------------------
final AjaxDropDownChoicePanel<String> javaRule = new AjaxDropDownChoicePanel<>(
"javaRule", "rule.java", new PropertyModel<String>(rule.getObject(), "rule")).setChoices(
new ArrayList<>(SyncopeConsoleSession.get().getPlatformInfo().getPullCorrelationRules()));
javaRule.setOutputMarkupPlaceholderTag(true);
add(javaRule.setVisible("JAVA".equals(rule.getObject().getType())));
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// JSON rule palette
// ---------------------------------------------------------------
AjaxPalettePanel.Builder<String> jsonRuleBuilder =
new AjaxPalettePanel.Builder<String>().setName("rule.json");
final PropertyModel<List<String>> jsonRuleModel =
new PropertyModel<List<String>>(rule.getObject(), "rule") {
private static final long serialVersionUID = 3799387950428254072L;
@Override
public List<String> getObject() {
final List<String> res = new ArrayList<>();
try {
JsonNode obj = OBJECT_MAPPER.readTree(rule.getObject().getRule());
if (obj.isArray()) {
for (final JsonNode objNode : obj) {
res.add(objNode.asText());
}
}
} catch (IOException e) {
LOG.warn("Error deserializing json tree", e);
}
return res;
}
@Override
public void setObject(final List<String> object) {
final StringBuilder bld = new StringBuilder();
bld.append("[");
boolean comma = false;
for (String obj : object) {
if (comma) {
bld.append(",");
} else {
comma = true;
}
bld.append("\"").append(obj).append("\"");
}
bld.append("]");
rule.getObject().setRule(bld.toString());
}
};
final AjaxPalettePanel<String> jsonRule =
jsonRuleBuilder.build("jsonRule", jsonRuleModel, new AjaxPalettePanel.Builder.Query<String>() {
private static final long serialVersionUID = -7223078772249308813L;
@Override
public List<String> execute(final String filter) {
return getPlainSchemas(rule.getObject());
}
});
jsonRule.hideLabel().setOutputMarkupPlaceholderTag(true);
anyType.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
private static final long serialVersionUID = -1107858522700306810L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
if (jsonRule.isVisibleInHierarchy()) {
rule.getObject().setRule("[]");
jsonRule.reload(target);
target.add(jsonRule);
}
}
});
add(jsonRule.setVisible("PLAIN ATTRIBUTES".equals(rule.getObject().getType())));
// ---------------------------------------------------------------
ruleType.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
private static final long serialVersionUID = -1107858522700306810L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
switch (ruleType.getModelObject() == null ? StringUtils.EMPTY : ruleType.getModelObject()) {
case "PLAIN ATTRIBUTES":
jsonRule.setVisible(true);
javaRule.setVisible(false);
jsonRule.reload(target);
break;
case "JAVA":
jsonRule.setVisible(false);
javaRule.setVisible(true);
break;
default:
javaRule.setVisible(false);
jsonRule.setVisible(false);
}
target.add(jsonRule);
target.add(javaRule);
}
});
}
private static List<String> getPlainSchemas(final CorrelationRule rule) {
final List<String> choices = StringUtils.isEmpty(rule.getAny())
? new ArrayList<String>()
: CollectionUtils.collect(
new SchemaRestClient().getSchemas(SchemaType.PLAIN,
rule.getAny().equals(AnyTypeKind.USER.name())
? AnyTypeKind.USER
: rule.getAny().equals(AnyTypeKind.GROUP.name())
? AnyTypeKind.GROUP
: AnyTypeKind.ANY_OBJECT), new Transformer<AbstractSchemaTO, String>() {
@Override
public String transform(final AbstractSchemaTO input) {
return input.getKey();
}
}, new ArrayList<String>());
Collections.sort(choices);
return choices;
}
}
protected static class CorrelationRule implements Serializable {
private static final long serialVersionUID = 5250228867297353011L;
private String any;
private String type;
private String rule;
public CorrelationRule() {
this.any = AnyTypeKind.USER.name();
this.type = "PLAIN ATTRIBUTES";
this.rule = "[]";
}
public CorrelationRule(final String any, final String rule) {
this.any = any;
this.type = StringUtils.isEmpty(rule) || rule.trim().startsWith("[") ? "PLAIN ATTRIBUTES" : "JAVA";
this.rule = rule;
}
public String getAny() {
return any;
}
public String getType() {
return type;
}
public String getRule() {
return rule;
}
public void setAny(final String any) {
this.any = any;
}
public void setType(final String type) {
this.type = type;
}
public void setRule(final String rule) {
this.rule = rule;
}
}
}