[SYNCOPE-1295] New structured wizard to edit SCIM 2.0 configuration
authorskylark17 <matteo.alessandroni@tirasa.net>
Wed, 2 May 2018 14:56:24 +0000 (16:56 +0200)
committerskylark17 <matteo.alessandroni@tirasa.net>
Thu, 7 Jun 2018 08:15:33 +0000 (10:15 +0200)
33 files changed:
client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractMappingPanel.java
client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderMappingPanel.java
ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConf.java [deleted file]
ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConfPage.java [new file with mode: 0644]
ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.java [new file with mode: 0644]
ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.java [new file with mode: 0644]
ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.java [new file with mode: 0644]
ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfPanel.java [new file with mode: 0644]
ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfTabPanel.java [new file with mode: 0644]
ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfUserPanel.java [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.html [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.properties [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_it.properties [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_pt_BR.properties [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_ru.properties [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.html [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.html [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.html [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel.html [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel.properties [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_it.properties [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_pt_BR.properties [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_ru.properties [new file with mode: 0644]
ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfUserPanel.html [new file with mode: 0644]
ext/scimv2/common-lib/src/main/java/org/apache/syncope/common/lib/scim/SCIMConf.java
ext/scimv2/common-lib/src/main/java/org/apache/syncope/common/lib/scim/SCIMGeneralConf.java [new file with mode: 0644]
ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java
ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMLogic.java
ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/scim/SCIMConfManager.java
ext/scimv2/scim-rest-cxf/src/main/java/org/apache/syncope/ext/scimv2/cxf/service/AbstractService.java

index 415e7c4..22ac2f4 100644 (file)
  */
 package org.apache.syncope.client.console.init;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 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.lang3.ArrayUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.syncope.client.console.pages.BaseExtPage;
@@ -38,6 +42,9 @@ import org.apache.syncope.common.lib.policy.AccountRuleConf;
 import org.apache.syncope.common.lib.policy.PasswordRuleConf;
 import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
 import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
@@ -50,6 +57,33 @@ public class ClassPathScanImplementationLookup {
 
     private static final String DEFAULT_BASE_PACKAGE = "org.apache.syncope";
 
+    public static final Set<String> USER_FIELD_NAMES = new HashSet<>();
+
+    public static final Set<String> GROUP_FIELD_NAMES = new HashSet<>();
+
+    public static final Set<String> ANY_OBJECT_FIELD_NAMES = new HashSet<>();
+
+    static {
+        initFieldNames(UserTO.class, USER_FIELD_NAMES);
+        initFieldNames(GroupTO.class, GROUP_FIELD_NAMES);
+        initFieldNames(AnyObjectTO.class, ANY_OBJECT_FIELD_NAMES);
+    }
+
+    private static void initFieldNames(final Class<?> entityClass, final Set<String> keys) {
+        List<Class<?>> classes = org.apache.commons.lang3.ClassUtils.getAllSuperclasses(entityClass);
+        classes.add(entityClass);
+        for (Class<?> clazz : classes) {
+            for (Field field : clazz.getDeclaredFields()) {
+                if (!Modifier.isStatic(field.getModifiers())
+                        && !Collection.class.isAssignableFrom(field.getType())
+                        && !Map.class.isAssignableFrom(field.getType())) {
+
+                    keys.add(field.getName());
+                }
+            }
+        }
+    }
+
     private List<Class<? extends BasePage>> pages;
 
     private List<Class<? extends AbstractBinaryPreviewer>> previewers;
index ad63013..1d1dc2d 100644 (file)
@@ -22,16 +22,9 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverBehavi
 import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverConfig;
 import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
 import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.apache.commons.lang3.ClassUtils;
 import org.apache.syncope.client.console.commons.ConnIdSpecialName;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
@@ -46,10 +39,7 @@ import org.apache.syncope.client.console.widgets.JEXLTransformerWidget;
 import org.apache.syncope.client.console.widgets.ItemTransformerWidget;
 import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
 import org.apache.syncope.client.console.wizards.resources.ItemTransformersTogglePanel;
-import org.apache.syncope.common.lib.to.AnyObjectTO;
-import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.ItemTO;
-import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -70,33 +60,6 @@ public abstract class AbstractMappingPanel extends Panel {
 
     private static final long serialVersionUID = -8295587900937040104L;
 
-    protected static final Set<String> USER_FIELD_NAMES = new HashSet<>();
-
-    protected static final Set<String> GROUP_FIELD_NAMES = new HashSet<>();
-
-    protected static final Set<String> ANY_OBJECT_FIELD_NAMES = new HashSet<>();
-
-    static {
-        initFieldNames(UserTO.class, USER_FIELD_NAMES);
-        initFieldNames(GroupTO.class, GROUP_FIELD_NAMES);
-        initFieldNames(AnyObjectTO.class, ANY_OBJECT_FIELD_NAMES);
-    }
-
-    private static void initFieldNames(final Class<?> entityClass, final Set<String> keys) {
-        List<Class<?>> classes = ClassUtils.getAllSuperclasses(entityClass);
-        classes.add(entityClass);
-        classes.forEach(clazz -> {
-            for (Field field : clazz.getDeclaredFields()) {
-                if (!Modifier.isStatic(field.getModifiers())
-                        && !Collection.class.isAssignableFrom(field.getType())
-                        && !Map.class.isAssignableFrom(field.getType())) {
-
-                    keys.add(field.getName());
-                }
-            }
-        });
-    }
-
     /**
      * Any type rest client.
      */
index 270f32d..655f462 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
 import org.apache.syncope.client.console.rest.ConnectorRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wizards.AbstractMappingPanel;
@@ -152,15 +153,15 @@ public class ResourceMappingPanel extends AbstractMappingPanel {
 
             switch (provision.getAnyType()) {
                 case "USER":
-                    choices.addAll(USER_FIELD_NAMES);
+                    choices.addAll(ClassPathScanImplementationLookup.USER_FIELD_NAMES);
                     break;
 
                 case "GROUP":
-                    choices.addAll(GROUP_FIELD_NAMES);
+                    choices.addAll(ClassPathScanImplementationLookup.GROUP_FIELD_NAMES);
                     break;
 
                 default:
-                    choices.addAll(ANY_OBJECT_FIELD_NAMES);
+                    choices.addAll(ClassPathScanImplementationLookup.ANY_OBJECT_FIELD_NAMES);
             }
 
             anyTypeClassTOs.forEach(anyTypeClassTO -> {
index d12965e..3308992 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.syncope.client.console.wizards;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wizards.resources.ItemTransformersTogglePanel;
 import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
@@ -87,7 +88,7 @@ public class OIDCProviderMappingPanel extends AbstractMappingPanel {
         toBeUpdated.setRequired(true);
         toBeUpdated.setEnabled(true);
 
-        List<String> choices = new ArrayList<>(USER_FIELD_NAMES);
+        List<String> choices = new ArrayList<>(ClassPathScanImplementationLookup.USER_FIELD_NAMES);
 
         for (AnyTypeClassTO anyTypeClassTO : anyTypeClassRestClient.list(
                 anyTypeRestClient.read(AnyTypeKind.USER.name()).getClasses())) {
index af13d8f..21e80a6 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.syncope.client.console.wizards;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
 import org.apache.syncope.client.console.wizards.resources.ItemTransformersTogglePanel;
@@ -70,7 +71,7 @@ public class SAML2IdPMappingPanel extends AbstractMappingPanel {
         toBeUpdated.setRequired(true);
         toBeUpdated.setEnabled(true);
 
-        List<String> choices = new ArrayList<>(USER_FIELD_NAMES);
+        List<String> choices = new ArrayList<>(ClassPathScanImplementationLookup.USER_FIELD_NAMES);
 
         for (AnyTypeClassTO anyTypeClassTO : anyTypeClassRestClient.list(
                 anyTypeRestClient.read(AnyTypeKind.USER.name()).getClasses())) {
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConf.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConf.java
deleted file mode 100644 (file)
index ac5a375..0000000
+++ /dev/null
@@ -1,137 +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.pages;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.annotations.ExtPage;
-import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.rest.SCIMConfRestClient;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.client.console.wicket.markup.html.form.JsonEditorPanel;
-import org.apache.syncope.common.lib.scim.SCIMComplexConf;
-import org.apache.syncope.common.lib.scim.SCIMEnterpriseUserConf;
-import org.apache.syncope.common.lib.scim.SCIMUserConf;
-import org.apache.syncope.common.lib.scim.SCIMUserNameConf;
-import org.apache.syncope.common.lib.scim.types.EmailCanonicalType;
-import org.apache.syncope.common.lib.scim.types.SCIMEntitlement;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.markup.html.AjaxLink;
-import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.model.ResourceModel;
-import org.apache.wicket.request.mapper.parameter.PageParameters;
-
-@ExtPage(label = "SCIM 2.0", icon = "fa-cloud", listEntitlement = SCIMEntitlement.SCIM_CONF_GET, priority = 400)
-public class SCIMConf extends BaseExtPage {
-
-    private static final long serialVersionUID = 9128779230455599119L;
-
-    private static final ObjectMapper MAPPER = new ObjectMapper();
-
-    private final SCIMConfRestClient restClient = new SCIMConfRestClient();
-
-    public SCIMConf(final PageParameters parameters) {
-        super(parameters);
-
-        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
-
-        final BaseModal<String> modal = new BaseModal<>("modal");
-        modal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
-
-            private static final long serialVersionUID = 8804221891699487139L;
-
-            @Override
-            public void onClose(final AjaxRequestTarget target) {
-                modal.show(false);
-            }
-        });
-        modal.size(Modal.Size.Large);
-        modal.addSubmitButton();
-        body.add(modal);
-
-        WebMarkupContainer content = new WebMarkupContainer("content");
-        content.setOutputMarkupId(true);
-        body.add(content);
-
-        String confString = "";
-        try {
-            org.apache.syncope.common.lib.scim.SCIMConf conf = restClient.get();
-            if (conf.getUserConf() == null) {
-                conf.setUserConf(new SCIMUserConf());
-            }
-            if (conf.getUserConf().getName() == null) {
-                conf.getUserConf().setName(new SCIMUserNameConf());
-            }
-            if (conf.getUserConf().getEmails().isEmpty()) {
-                conf.getUserConf().getEmails().add(new SCIMComplexConf<EmailCanonicalType>());
-            }
-
-            if (conf.getEnterpriseUserConf() == null) {
-                conf.setEnterpriseUserConf(new SCIMEnterpriseUserConf());
-            }
-
-            confString = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(conf);
-        } catch (Exception e) {
-            LOG.error("While reading SCIM configuration", e);
-            SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
-                    ? e.getClass().getName() : e.getMessage());
-        }
-        final Model<String> confModel = Model.of(confString);
-
-        content.add(new AjaxLink<Void>("edit") {
-
-            private static final long serialVersionUID = -4331619903296515985L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target) {
-                modal.header(new ResourceModel("editConf"));
-                modal.setContent(new JsonEditorPanel(modal, confModel, false, getPageReference()) {
-
-                    private static final long serialVersionUID = -8927036362466990179L;
-
-                    @Override
-                    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
-                        try {
-                            restClient.set(MAPPER.readValue(
-                                    confModel.getObject(), org.apache.syncope.common.lib.scim.SCIMConf.class));
-
-                            SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
-                            modal.show(false);
-                            modal.close(target);
-                        } catch (Exception e) {
-                            LOG.error("While setting SCIM configuration", e);
-                            SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
-                                    ? e.getClass().getName() : e.getMessage());
-                        }
-                        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
-                    }
-                });
-                modal.show(true);
-                target.add(modal);
-            }
-        });
-    }
-
-}
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConfPage.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConfPage.java
new file mode 100644 (file)
index 0000000..4eded72
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.pages;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.Serializable;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.annotations.ExtPage;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.SCIMConfPanel;
+import org.apache.syncope.client.console.rest.SCIMConfRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wizards.any.ResultPage;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.types.SCIMEntitlement;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@ExtPage(label = "SCIM 2.0", icon = "fa-cloud", listEntitlement = SCIMEntitlement.SCIM_CONF_GET, priority = 100)
+public class SCIMConfPage extends BaseExtPage {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SCIMConfPage.class);
+
+    private static final long serialVersionUID = -8156063343062111770L;
+
+    private final SCIMConfRestClient restClient = new SCIMConfRestClient();
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    private final WebMarkupContainer content;
+
+    public SCIMConfPage(final PageParameters parameters) {
+        super(parameters);
+
+        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
+
+        content = new WebMarkupContainer("content");
+
+        content.add(new Label("body", "General"));
+        content.setOutputMarkupId(true);
+        body.add(content);
+
+        updateSCIMGeneralConfContent(restClient.get());
+    }
+
+    private WebMarkupContainer updateSCIMGeneralConfContent(final SCIMConf scimConf) {
+        if (scimConf == null) {
+            return content;
+        }
+        content.addOrReplace(new SCIMConfPanel("body", scimConf, SCIMConfPage.this.getPageReference()) {
+
+            private static final long serialVersionUID = 8221398624379357183L;
+
+            @Override
+            protected void setWindowClosedReloadCallback(final BaseModal<?> modal) {
+                modal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+                    private static final long serialVersionUID = 8804221891699487139L;
+
+                    @Override
+                    public void onClose(final AjaxRequestTarget target) {
+                        if (modal.getContent() instanceof ResultPage) {
+                            Serializable result = ResultPage.class.cast(modal.getContent()).getResult();
+                            try {
+                                restClient.set(MAPPER.readValue(result.toString(), SCIMConf.class));
+
+                                SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                                modal.show(false);
+                                target.add(content);
+                            } catch (Exception e) {
+                                LOG.error("While setting SCIM configuration", e);
+                                SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
+                                        ? e.getClass().getName() : e.getMessage());
+                            }
+                            ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+                        }
+                    }
+                });
+            }
+
+        });
+
+        return content;
+    }
+
+}
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.java
new file mode 100644 (file)
index 0000000..1a2d687
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.util.List;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class SCIMConfAccordionContainer extends Panel {
+
+    private static final long serialVersionUID = 8186681102688613299L;
+
+    SCIMConfAccordionContainer(final String id, final List<AjaxTextFieldPanel> fieldPanels) {
+        super(id);
+
+        add(new ListView<AjaxTextFieldPanel>("accordionContainer", fieldPanels) {
+
+            private static final long serialVersionUID = 4949588177564901031L;
+
+            @Override
+            protected void populateItem(final ListItem<AjaxTextFieldPanel> item) {
+                item.add(item.getModelObject());
+            }
+        });
+    }
+}
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.java
new file mode 100644 (file)
index 0000000..e127bbc
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.tabs.Accordion;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.SCIMEnterpriseUserConf;
+import org.apache.syncope.common.lib.scim.SCIMManagerConf;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SCIMConfEnterpriseUserPanel extends SCIMConfTabPanel {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SCIMConfEnterpriseUserPanel.class);
+
+    private static final long serialVersionUID = -4183306437598820588L;
+
+    private final SCIMEnterpriseUserConf scimEnterpriseUserConf;
+
+    public SCIMConfEnterpriseUserPanel(
+            final String id,
+            final SCIMConf scimConf) {
+        super(id, scimConf);
+
+        if (scimConf.getEnterpriseUserConf() == null) {
+            scimConf.setEnterpriseUserConf(new SCIMEnterpriseUserConf());
+        }
+        if (scimConf.getEnterpriseUserConf().getManager() == null) {
+            scimConf.getEnterpriseUserConf().setManager(new SCIMManagerConf());
+        }
+        scimEnterpriseUserConf = scimConf.getEnterpriseUserConf();
+
+        AjaxTextFieldPanel costCenterPanel =
+                new AjaxTextFieldPanel("costCenter", "costCenter",
+                        new PropertyModel<String>("costCenter", "costCenter") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getCostCenter();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setCostCenter(object);
+                    }
+
+                });
+        costCenterPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel departmentPanel =
+                new AjaxTextFieldPanel("department", "department",
+                        new PropertyModel<String>("department", "department") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getDepartment();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setDepartment(object);
+                    }
+
+                });
+        departmentPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel divisionPanel =
+                new AjaxTextFieldPanel("division", "division",
+                        new PropertyModel<String>("division", "division") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getDivision();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setDivision(object);
+                    }
+
+                });
+        divisionPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel employeeNumberPanel =
+                new AjaxTextFieldPanel("employeeNumber", "employeeNumber",
+                        new PropertyModel<String>("employeeNumber", "employeeNumber") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getEmployeeNumber();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setEmployeeNumber(object);
+                    }
+
+                });
+        employeeNumberPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel organizationPanel =
+                new AjaxTextFieldPanel("organization", "organization",
+                        new PropertyModel<String>("organization", "organization") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getOrganization();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setOrganization(object);
+                    }
+
+                });
+        organizationPanel.setChoices(plainSchemaNames);
+
+        // manager
+        buildManagerAccordion();
+
+        add(costCenterPanel);
+        add(departmentPanel);
+        add(divisionPanel);
+        add(employeeNumberPanel);
+        add(organizationPanel);
+    }
+
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        super.onEvent(event);
+    }
+
+    private void buildManagerAccordion() {
+        final Accordion accordion = new Accordion("managerAccordion",
+                Collections.<ITab>singletonList(new AbstractTab(Model.of("manager")) {
+
+                    private static final long serialVersionUID = -5861786415855103549L;
+
+                    @Override
+                    public WebMarkupContainer getPanel(final String panelId) {
+                        return buildNameAccordionContent(panelId);
+                    }
+
+                }), Model.of(-1)); // accordion closed at beginning
+        add(accordion.setOutputMarkupId(true));
+
+    }
+
+    private SCIMConfAccordionContainer buildNameAccordionContent(final String panelId) {
+        final List<AjaxTextFieldPanel> panelList = new ArrayList<>();
+
+        AjaxTextFieldPanel managerKeyPanel =
+                new AjaxTextFieldPanel("accordionContent", "manager.key",
+                        new PropertyModel<String>(scimEnterpriseUserConf.getManager(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getManager().getKey();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.getManager().setKey(object);
+                    }
+
+                });
+        managerKeyPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel managerDisplaNamePanel =
+                new AjaxTextFieldPanel("accordionContent", "manager.displayName",
+                        new PropertyModel<String>(scimEnterpriseUserConf.getManager(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getManager().getDisplayName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.getManager().setDisplayName(object);
+                    }
+
+                });
+        managerDisplaNamePanel.setChoices(plainSchemaNames);
+
+        panelList.add(managerKeyPanel);
+        panelList.add(managerDisplaNamePanel);
+        
+        add(new Label("managerLabel", Model.of("manager")));
+
+        return new SCIMConfAccordionContainer(panelId, panelList);
+    }
+
+}
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.java
new file mode 100644 (file)
index 0000000..29f457c
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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.util.Date;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDateTimeFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.SCIMGeneralConf;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+public class SCIMConfGeneralPanel extends SCIMConfTabPanel {
+
+    private static final long serialVersionUID = 2765863608539154422L;
+
+    public SCIMConfGeneralPanel(
+            final String id,
+            final SCIMConf scimConf) {
+        super(id, scimConf);
+
+        final SCIMGeneralConf scimGeneralConf = scimConf.getGeneralConf();
+
+        AjaxDateTimeFieldPanel creationDatePanel =
+                new AjaxDateTimeFieldPanel("creationDate", "creationDate", new Model<Date>() {
+
+                    private static final long serialVersionUID = 7075312408615929880L;
+
+                    @Override
+                    public Date getObject() {
+                        return scimGeneralConf.getCreationDate();
+                    }
+
+                    @Override
+                    public void setObject(final Date object) {
+                        scimGeneralConf.setCreationDate(object);
+                    }
+
+                }, SyncopeConstants.DEFAULT_DATE_PATTERN);
+        creationDatePanel.setEnabled(false);
+
+        AjaxDateTimeFieldPanel lastChangeDatePanel =
+                new AjaxDateTimeFieldPanel("lastChangeDate", "lastChangeDate", new Model<Date>() {
+
+                    private static final long serialVersionUID = 7075312408615929880L;
+
+                    @Override
+                    public Date getObject() {
+                        return scimGeneralConf.getLastChangeDate();
+                    }
+
+                    @Override
+                    public void setObject(final Date object) {
+                        scimGeneralConf.setLastChangeDate(object);
+                    }
+
+                }, SyncopeConstants.DEFAULT_DATE_PATTERN);
+        lastChangeDatePanel.setEnabled(false);
+
+        AjaxTextFieldPanel bulkMaxOperationsPanel =
+                new AjaxTextFieldPanel("bulkMaxOperations", "bulkMaxOperations",
+                        new PropertyModel<String>("bulkMaxOperations", "bulkMaxOperations") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(scimGeneralConf.getBulkMaxOperations());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimGeneralConf.setBulkMaxOperations(Integer.parseInt(object));
+                    }
+
+                });
+        bulkMaxOperationsPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel bulkMaxMaxPayloadSizePanel =
+                new AjaxTextFieldPanel("bulkMaxMaxPayloadSize", "bulkMaxMaxPayloadSize",
+                        new PropertyModel<String>("bulkMaxMaxPayloadSize", "bulkMaxMaxPayloadSize") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(scimGeneralConf.getBulkMaxPayloadSize());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimGeneralConf.setBulkMaxPayloadSize(Integer.parseInt(object));
+                    }
+
+                });
+        bulkMaxMaxPayloadSizePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel filterMaxResultsPanel =
+                new AjaxTextFieldPanel("filterMaxResults", "filterMaxResults",
+                        new PropertyModel<String>("filterMaxResults", "filterMaxResults") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(scimGeneralConf.getFilterMaxResults());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimGeneralConf.setFilterMaxResults(Integer.parseInt(object));
+                    }
+
+                });
+        filterMaxResultsPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel eTagValuePanel =
+                new AjaxTextFieldPanel("eTagValue", "eTagValue",
+                        new PropertyModel<String>("eTagValue", "eTagValue") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimGeneralConf.getETagValue();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+
+                    }
+
+                });
+        eTagValuePanel.setEnabled(false);
+
+        add(creationDatePanel);
+        add(lastChangeDatePanel);
+        add(bulkMaxOperationsPanel);
+        add(bulkMaxMaxPayloadSizePanel);
+        add(filterMaxResultsPanel);
+        add(eTagValuePanel);
+    }
+
+}
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfPanel.java
new file mode 100644 (file)
index 0000000..d006bb1
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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 de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.client.console.commons.ITabComponent;
+import org.apache.syncope.client.console.rest.SCIMConfRestClient;
+import org.apache.syncope.client.console.wizards.WizardMgtPanel;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class SCIMConfPanel extends WizardMgtPanel<SCIMConf> {
+
+    private static final long serialVersionUID = -1100228004207271270L;
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SCIMConfPanel.class);
+
+    private final SCIMConf scimConfTO;
+
+    private final SCIMConfRestClient scimConfRestClient = new SCIMConfRestClient();
+
+    public SCIMConfPanel(
+            final String id,
+            final SCIMConf scimConfTO,
+            final PageReference pageRef) {
+        super(id, true);
+
+        this.scimConfTO = scimConfTO;
+        this.pageRef = pageRef;
+
+        setPageRef(pageRef);
+
+        AjaxBootstrapTabbedPanel<ITab> tabbedPanel =
+                new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList());
+        tabbedPanel.setSelectedTab(0);
+        addInnerObject(tabbedPanel);
+
+        AjaxLink<String> saveButton = new AjaxLink<String>("saveButton") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                scimConfRestClient.set(SCIMConfPanel.this.scimConfTO);
+            }
+        };
+        addInnerObject(saveButton);
+
+        setShowResultPage(true);
+
+        modal.size(Modal.Size.Large);
+        setWindowClosedReloadCallback(modal);
+    }
+
+    private List<ITab> buildTabList() {
+        List<ITab> tabs = new ArrayList<>();
+
+        tabs.add(new ITabComponent(new Model<>(getString("tab1"))) {
+
+            private static final long serialVersionUID = -5861786415855103549L;
+
+            @Override
+            public Panel getPanel(final String panelId) {
+                return new SCIMConfGeneralPanel(panelId, scimConfTO);
+            }
+
+            @Override
+            public boolean isVisible() {
+                return true;
+            }
+        });
+
+        tabs.add(new ITabComponent(
+                new Model<>(getString("tab2")), getString("tab2")) {
+
+            private static final long serialVersionUID = 1998052474181916792L;
+
+            @Override
+            public WebMarkupContainer getPanel(final String panelId) {
+                return new SCIMConfUserPanel(panelId, scimConfTO);
+            }
+
+            @Override
+            public boolean isVisible() {
+                return true;
+            }
+        });
+
+        tabs.add(new ITabComponent(
+                new Model<>(getString("tab3")), getString("tab3")) {
+
+            private static final long serialVersionUID = 1998052474181916792L;
+
+            @Override
+            public WebMarkupContainer getPanel(final String panelId) {
+                return new SCIMConfEnterpriseUserPanel(panelId, scimConfTO);
+            }
+
+            @Override
+            public boolean isVisible() {
+                return true;
+            }
+        });
+
+        return tabs;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected Panel customResultBody(final String panelId, final SCIMConf item, final Serializable result) {
+
+        return null;
+    }
+
+}
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfTabPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfTabPanel.java
new file mode 100644 (file)
index 0000000..12acbb2
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
+import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.to.SchemaTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class SCIMConfTabPanel extends Panel implements ModalPanel {
+
+    private static final long serialVersionUID = -4482885585790492795L;
+
+    protected final List<String> plainSchemaNames = getPlainSchemas();
+
+    public SCIMConfTabPanel(
+            final String id,
+            final SCIMConf scimConf) {
+        super(id);
+    }
+
+    private static List<String> getPlainSchemas() {
+        final List<String> names = new ArrayList<>(ClassPathScanImplementationLookup.USER_FIELD_NAMES);
+        names.addAll(CollectionUtils.collect(new SchemaRestClient().getSchemas(SchemaType.PLAIN, AnyTypeKind.USER),
+                new Transformer<SchemaTO, String>() {
+
+            @Override
+            public String transform(final SchemaTO input) {
+                return input.getKey();
+            }
+        }, new ArrayList<String>()));
+        names.remove("password");
+        Collections.sort(names);
+
+        return names;
+    }
+
+}
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfUserPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfUserPanel.java
new file mode 100644 (file)
index 0000000..ab5fbdb
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.tabs.Accordion;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
+import org.apache.syncope.common.lib.scim.SCIMComplexConf;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.SCIMUserAddressConf;
+import org.apache.syncope.common.lib.scim.SCIMUserConf;
+import org.apache.syncope.common.lib.scim.SCIMUserNameConf;
+import org.apache.syncope.common.lib.scim.types.AddressCanonicalType;
+import org.apache.syncope.common.lib.scim.types.EmailCanonicalType;
+import org.apache.syncope.common.lib.scim.types.IMCanonicalType;
+import org.apache.syncope.common.lib.scim.types.PhoneNumberCanonicalType;
+import org.apache.syncope.common.lib.scim.types.PhotoCanonicalType;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SCIMConfUserPanel extends SCIMConfTabPanel {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SCIMConfUserPanel.class);
+
+    private static final long serialVersionUID = 8747864142447220523L;
+
+    private final SCIMUserConf scimUserConf;
+
+    public SCIMConfUserPanel(
+            final String id,
+            final SCIMConf scimConf) {
+        super(id, scimConf);
+
+        if (scimConf.getUserConf() == null) {
+            scimConf.setUserConf(new SCIMUserConf());
+        }
+        if (scimConf.getUserConf().getName() == null) {
+            scimConf.getUserConf().setName(new SCIMUserNameConf());
+        }
+        scimUserConf = scimConf.getUserConf();
+
+        final AutoCompleteSettings settings = new AutoCompleteSettings();
+        settings.setShowCompleteListOnFocusGain(true);
+        settings.setShowListOnEmptyInput(true);
+        settings.setCssClassName("custom-autocomplete-box");
+
+        AjaxTextFieldPanel displayNamePanel =
+                new AjaxTextFieldPanel("displayName", "displayName",
+                        new PropertyModel<String>("displayName", "displayName") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getDisplayName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setDisplayName(object);
+                    }
+
+                });
+        displayNamePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel localePanel =
+                new AjaxTextFieldPanel("locale", "locale",
+                        new PropertyModel<String>("locale", "locale") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getLocale();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setLocale(object);
+                    }
+
+                });
+        localePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nickNamePanel =
+                new AjaxTextFieldPanel("nickName", "nickName",
+                        new PropertyModel<String>("nickName", "nickName") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getNickName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setNickName(object);
+                    }
+
+                });
+        nickNamePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel preferredLanguagePanel =
+                new AjaxTextFieldPanel("preferredLanguage", "preferredLanguage",
+                        new PropertyModel<String>("preferredLanguage", "preferredLanguage") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getPreferredLanguage();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setPreferredLanguage(object);
+                    }
+
+                });
+        preferredLanguagePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel profileUrlPanel =
+                new AjaxTextFieldPanel("profileUrl", "profileUrl",
+                        new PropertyModel<String>("profileUrl", "profileUrl") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getProfileUrl();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setProfileUrl(object);
+                    }
+
+                });
+        profileUrlPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel timezonePanel =
+                new AjaxTextFieldPanel("timezone", "timezone",
+                        new PropertyModel<String>("timezone", "timezone") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getTimezone();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setTimezone(object);
+                    }
+
+                });
+        timezonePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel titlePanel =
+                new AjaxTextFieldPanel("title", "title",
+                        new PropertyModel<String>("title", "title") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getTitle();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setTitle(object);
+                    }
+
+                });
+        titlePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel userTypePanel =
+                new AjaxTextFieldPanel("userType", "userType",
+                        new PropertyModel<String>("userType", "userType") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getUserType();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setUserType(object);
+                    }
+
+                });
+        userTypePanel.setChoices(plainSchemaNames);
+
+        // name
+        buildNameAccordion();
+
+        // x509certificates
+        final AjaxTextFieldPanel x509CertificatesPanel = new AjaxTextFieldPanel("panel", "x509CertificatesPanel",
+                new Model<String>(null));
+        x509CertificatesPanel.setChoices(plainSchemaNames);
+        MultiFieldPanel<String> x509CertificatesMultiPanel = new MultiFieldPanel.Builder<>(
+                new ListModel<>(scimUserConf.getX509Certificates())).build(
+                "x509Certificates",
+                "x509Certificates",
+                x509CertificatesPanel);
+
+        // addresses
+        List<SCIMUserAddressConf> addresses = new ArrayList<>();
+        for (final AddressCanonicalType canonicalType : AddressCanonicalType.values()) {
+            SCIMUserAddressConf address = IterableUtils.find(scimUserConf.getAddresses(),
+                    new Predicate<SCIMUserAddressConf>() {
+
+                @Override
+                public boolean evaluate(final SCIMUserAddressConf object) {
+                    return object.getType().equals(canonicalType);
+                }
+            });
+
+            if (address == null) {
+                address = new SCIMUserAddressConf();
+                address.setType(canonicalType);
+            }
+            buildAddressAccordion(address, canonicalType);
+            addresses.add(address);
+        }
+        scimUserConf.getAddresses().clear();
+        scimUserConf.getAddresses().addAll(addresses);
+
+        // complex objects
+        buildComplexPanels(scimUserConf.getEmails(), "emailsAccordion", "emails", EmailCanonicalType.values());
+        buildComplexPanels(scimUserConf.getPhoneNumbers(), "phoneNumbersAccordion", "phoneNumbers",
+                PhoneNumberCanonicalType.values());
+        buildComplexPanels(scimUserConf.getIms(), "imsAccordion", "ims", IMCanonicalType.values());
+        buildComplexPanels(scimUserConf.getPhotos(), "photosAccordion", "photos", PhotoCanonicalType.values());
+
+        add(displayNamePanel);
+        add(localePanel);
+        add(nickNamePanel);
+        add(preferredLanguagePanel);
+        add(profileUrlPanel);
+        add(timezonePanel);
+        add(titlePanel);
+        add(userTypePanel);
+
+        add(x509CertificatesMultiPanel);
+
+        add(new Label("nameLabel", Model.of("name")));
+        add(new Label("addressesLabel", Model.of("addresses")));
+        add(new Label("emailsLabel", Model.of("emails")));
+        add(new Label("phoneNumbersLabel", Model.of("phoneNumbers")));
+        add(new Label("imsLabel", Model.of("ims")));
+        add(new Label("photosLabel", Model.of("photos")));
+
+    }
+
+    private <T extends Enum<?>> void buildComplexPanels(final List<SCIMComplexConf<T>> complexes,
+            final String basePanelId,
+            final String baseTabId,
+            final T[] canonicalTypes) {
+        List<SCIMComplexConf<T>> newElems = new ArrayList<>();
+        for (final T canonicalType : canonicalTypes) {
+            SCIMComplexConf<T> complex = IterableUtils.find(complexes,
+                    new Predicate<SCIMComplexConf<T>>() {
+
+                @Override
+                public boolean evaluate(final SCIMComplexConf<T> object) {
+                    return object.getType().equals(canonicalType);
+                }
+            });
+            if (complex == null) {
+                complex = new SCIMComplexConf<>();
+                complex.setType(canonicalType);
+            }
+            buildComplexAccordion(complex, basePanelId, baseTabId, canonicalType);
+            newElems.add(complex);
+        }
+        complexes.clear();
+        complexes.addAll(newElems);
+    }
+
+    private void buildNameAccordion() {
+        final Accordion accordion = new Accordion("nameAccordion",
+                Collections.<ITab>singletonList(new AbstractTab(Model.of("name")) {
+
+                    private static final long serialVersionUID = -5861786415855103549L;
+
+                    @Override
+                    public WebMarkupContainer getPanel(final String panelId) {
+                        return buildNameAccordionContent(panelId);
+                    }
+
+                }), Model.of(-1)); // accordion closed at beginning
+        add(accordion.setOutputMarkupId(true));
+    }
+
+    private void buildAddressAccordion(final SCIMUserAddressConf address,
+            final AddressCanonicalType canonicalType) {
+        final Accordion accordion = new Accordion("addressesAccordion_" + address.getType().name(),
+                Collections.<ITab>singletonList(new AbstractTab(Model.of("address." + address.getType().name())) {
+
+                    private static final long serialVersionUID = -5861786415855103549L;
+
+                    @Override
+                    public WebMarkupContainer getPanel(final String panelId) {
+                        return buildAddressAccordionContent(address, canonicalType, panelId);
+                    }
+
+                }), Model.of(-1)); // accordion closed at beginning
+        add(accordion.setOutputMarkupId(true));
+    }
+
+    private <T extends Enum<?>> void buildComplexAccordion(final SCIMComplexConf<T> complex,
+            final String basePanelId,
+            final String baseTabId,
+            final T canonicalType) {
+        final Accordion accordion = new Accordion(basePanelId + "_" + complex.getType().name(),
+                Collections.<ITab>singletonList(
+                        new AbstractTab(Model.of(baseTabId + "." + complex.getType().name())) {
+
+                    private static final long serialVersionUID = -5861786415855103549L;
+
+                    @Override
+                    public WebMarkupContainer getPanel(final String panelId) {
+                        return buildComplexAccordionContent(complex, canonicalType, panelId);
+                    }
+
+                }), Model.of(-1)); // accordion closed at beginning
+        add(accordion.setOutputMarkupId(true));
+    }
+
+    private SCIMConfAccordionContainer buildNameAccordionContent(final String panelId) {
+        final List<AjaxTextFieldPanel> panelList = new ArrayList<>();
+
+        AjaxTextFieldPanel nameFamilyNamePanel =
+                new AjaxTextFieldPanel("accordionContent", "name.familyName",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getFamilyName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setFamilyName(object);
+                    }
+
+                });
+        nameFamilyNamePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameFormattedPanel =
+                new AjaxTextFieldPanel("accordionContent", "name.formatted",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getFormatted();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setFormatted(object);
+                    }
+
+                });
+        nameFormattedPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameGivenNamePanel =
+                new AjaxTextFieldPanel("accordionContent", "name.givenName",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getGivenName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setGivenName(object);
+                    }
+
+                });
+        nameGivenNamePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameHonorificPrefixPanel =
+                new AjaxTextFieldPanel("accordionContent", "name.honorificPrefix",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getHonorificPrefix();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setHonorificPrefix(object);
+                    }
+
+                });
+        nameHonorificPrefixPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameHonorificSuffixPanel =
+                new AjaxTextFieldPanel("accordionContent", "name.honorificSuffix",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getHonorificSuffix();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setHonorificSuffix(object);
+                    }
+
+                });
+        nameHonorificSuffixPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameMiddleNamePanel =
+                new AjaxTextFieldPanel("accordionContent", "name.middleName",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getMiddleName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setMiddleName(object);
+                    }
+
+                });
+        nameMiddleNamePanel.setChoices(plainSchemaNames);
+
+        panelList.add(nameFamilyNamePanel);
+        panelList.add(nameFormattedPanel);
+        panelList.add(nameGivenNamePanel);
+        panelList.add(nameHonorificPrefixPanel);
+        panelList.add(nameHonorificSuffixPanel);
+        panelList.add(nameMiddleNamePanel);
+
+        return new SCIMConfAccordionContainer(panelId, panelList);
+    }
+
+    private <T extends Enum<?>> SCIMConfAccordionContainer buildComplexAccordionContent(
+            final SCIMComplexConf<T> complex,
+            final T canonicalType,
+            final String panelId) {
+        final List<AjaxTextFieldPanel> panelList = new ArrayList<>();
+        final String fieldName = panelId + "." + canonicalType.name();
+
+        AjaxTextFieldPanel displayPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".display",
+                        new PropertyModel<String>(complex, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return complex.getDisplay();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        complex.setDisplay(object);
+                    }
+
+                });
+        displayPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel valuePanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".value",
+                        new PropertyModel<String>(complex, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return complex.getValue();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        complex.setValue(object);
+                    }
+
+                });
+        valuePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel primaryPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".primary",
+                        new PropertyModel<String>(complex, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(complex.isPrimary());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        complex.setPrimary(Boolean.valueOf(object));
+                    }
+
+                });
+        primaryPanel.setChoices(Arrays.asList("true", "false"));
+
+        panelList.add(displayPanel);
+        panelList.add(valuePanel);
+        panelList.add(primaryPanel);
+
+        return new SCIMConfAccordionContainer(panelId, panelList);
+    }
+
+    private SCIMConfAccordionContainer buildAddressAccordionContent(final SCIMUserAddressConf address,
+            final AddressCanonicalType canonicalType,
+            final String panelId) {
+        final List<AjaxTextFieldPanel> panelList = new ArrayList<>();
+        final String fieldName = "addresses." + canonicalType.name();
+
+        AjaxTextFieldPanel addressCountryPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".country",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getCountry();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setCountry(object);
+                    }
+
+                });
+        addressCountryPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressFormattedPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".formatted",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getFormatted();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setFormatted(object);
+                    }
+
+                });
+        addressFormattedPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressLocalityPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".locality",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getLocality();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setLocality(object);
+                    }
+
+                });
+        addressLocalityPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressRegionPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".region",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getRegion();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setRegion(object);
+                    }
+
+                });
+        addressRegionPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressPostalCodePanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".postalCode",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getPostalCode();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setPostalCode(object);
+                    }
+
+                });
+        addressPostalCodePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressPrimaryPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".primary",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(address.isPrimary());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setPrimary(Boolean.valueOf(object));
+                    }
+
+                });
+        addressPrimaryPanel.setChoices(Arrays.asList("true", "false"));
+
+        panelList.add(addressCountryPanel);
+        panelList.add(addressFormattedPanel);
+        panelList.add(addressLocalityPanel);
+        panelList.add(addressRegionPanel);
+        panelList.add(addressPostalCodePanel);
+        panelList.add(addressPrimaryPanel);
+
+        return new SCIMConfAccordionContainer(panelId, panelList);
+    }
+
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        super.onEvent(event);
+    }
+
+}
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.html b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.html
new file mode 100644 (file)
index 0000000..25a5a93
--- /dev/null
@@ -0,0 +1,37 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <section class="content-header">
+      <h1>&nbsp;</h1>
+      <ol class="breadcrumb">
+        <li><a wicket:id="dashboardBr"><i class="fa fa-dashboard"></i> <wicket:message key="dashboard"></wicket:message></a></li>
+        <li class="active"><wicket:message key="scimConfGeneral"></wicket:message></li>
+      </ol>
+    </section>
+
+    <section class="content" wicket:id="content">
+      <div class="box">
+        <div class="box-body">
+          <wicket:container wicket:id="body"/>
+        </div>
+      </div>
+    </section>
+  </wicket:extend>
+</html>
\ No newline at end of file
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.properties
new file mode 100644 (file)
index 0000000..cbcf4a3
--- /dev/null
@@ -0,0 +1,17 @@
+# 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.
+scimConfGeneral=General
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_it.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_it.properties
new file mode 100644 (file)
index 0000000..cbcf4a3
--- /dev/null
@@ -0,0 +1,17 @@
+# 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.
+scimConfGeneral=General
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_pt_BR.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_pt_BR.properties
new file mode 100644 (file)
index 0000000..cbcf4a3
--- /dev/null
@@ -0,0 +1,17 @@
+# 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.
+scimConfGeneral=General
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_ru.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_ru.properties
new file mode 100644 (file)
index 0000000..cbcf4a3
--- /dev/null
@@ -0,0 +1,17 @@
+# 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.
+scimConfGeneral=General
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.html b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.html
new file mode 100644 (file)
index 0000000..265a138
--- /dev/null
@@ -0,0 +1,29 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div wicket:id="accordionContainer">
+      <div class="form-group">
+        <span wicket:id="accordionContent">
+          [accordionContent]
+        </span>
+      </div>
+    </div>
+  </wicket:panel>
+</html>
\ No newline at end of file
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.html b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.html
new file mode 100644 (file)
index 0000000..8892d4c
--- /dev/null
@@ -0,0 +1,32 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div wicket:id="costCenter"/>
+    <div wicket:id="department"/>
+    <div wicket:id="division"/>
+    <div wicket:id="employeeNumber"/>
+    <div wicket:id="organization"/>
+
+    <div style="margin-top: 15px;">
+      <label wicket:id="managerLabel"/>
+      <div wicket:id="managerAccordion"></div>
+    </div>
+  </wicket:panel>
+</html>
\ No newline at end of file
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.html b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.html
new file mode 100644 (file)
index 0000000..dba5865
--- /dev/null
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div wicket:id="creationDate"></div>
+    <div wicket:id="lastChangeDate"></div>
+    <div wicket:id="bulkMaxOperations"></div>
+    <div wicket:id="bulkMaxMaxPayloadSize"></div>
+    <div wicket:id="filterMaxResults"></div>
+    <div wicket:id="eTagValue"></div>
+  </wicket:panel>
+</html>
\ No newline at end of file
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel.html b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel.html
new file mode 100644 (file)
index 0000000..27194af
--- /dev/null
@@ -0,0 +1,32 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <div wicket:id="tabbedPanel"></div>
+    <div class="modal-footer">
+      <a href="#" 
+         class="btn btn-primary" 
+         wicket:id="saveButton"
+         alt="Save" 
+         title="Save">
+        <wicket:message key="saveButton"/>
+      </a>
+    </div>
+  </wicket:extend>
+</html>
\ No newline at end of file
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel.properties
new file mode 100644 (file)
index 0000000..40063bd
--- /dev/null
@@ -0,0 +1,21 @@
+# 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.
+tab1=General
+tab2=User
+tab3=EnterpriseUser
+
+saveButton=Save
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_it.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_it.properties
new file mode 100644 (file)
index 0000000..40063bd
--- /dev/null
@@ -0,0 +1,21 @@
+# 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.
+tab1=General
+tab2=User
+tab3=EnterpriseUser
+
+saveButton=Save
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_pt_BR.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_pt_BR.properties
new file mode 100644 (file)
index 0000000..40063bd
--- /dev/null
@@ -0,0 +1,21 @@
+# 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.
+tab1=General
+tab2=User
+tab3=EnterpriseUser
+
+saveButton=Save
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_ru.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfPanel_ru.properties
new file mode 100644 (file)
index 0000000..40063bd
--- /dev/null
@@ -0,0 +1,21 @@
+# 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.
+tab1=General
+tab2=User
+tab3=EnterpriseUser
+
+saveButton=Save
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfUserPanel.html b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/panels/SCIMConfUserPanel.html
new file mode 100644 (file)
index 0000000..5208aca
--- /dev/null
@@ -0,0 +1,81 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div wicket:id="displayName"/>
+    <div wicket:id="locale"/>
+    <div wicket:id="nickName"/>
+    <div wicket:id="preferredLanguage"/>
+    <div wicket:id="profileUrl"/>
+    <div wicket:id="timezone"/>
+    <div wicket:id="title"/>
+    <div wicket:id="userType"/>
+
+    <div style="margin-top: 15px;">
+      <label wicket:id="nameLabel"/>
+      <div wicket:id="nameAccordion"/>
+    </div>
+
+    <span wicket:id="x509Certificates">
+      [x509Certificates]
+    </span>
+
+    <div style="margin-top: 15px;">
+      <label wicket:id="addressesLabel"/>
+      <div wicket:id="addressesAccordion_work"/>
+      <div wicket:id="addressesAccordion_home"/>
+      <div wicket:id="addressesAccordion_other"/>
+    </div>
+
+    <div style="margin-top: 15px;">
+      <label wicket:id="emailsLabel"/>
+      <div wicket:id="emailsAccordion_work"/>
+      <div wicket:id="emailsAccordion_home"/>
+      <div wicket:id="emailsAccordion_other"/>      
+    </div>
+
+    <div style="margin-top: 15px;">
+      <label wicket:id="phoneNumbersLabel"/>
+      <div wicket:id="phoneNumbersAccordion_work"/>
+      <div wicket:id="phoneNumbersAccordion_home"/>
+      <div wicket:id="phoneNumbersAccordion_other"/>
+      <div wicket:id="phoneNumbersAccordion_mobile"/>
+      <div wicket:id="phoneNumbersAccordion_fax"/>
+      <div wicket:id="phoneNumbersAccordion_pager"/>
+    </div>
+
+    <div style="margin-top: 15px;">
+      <label wicket:id="imsLabel"/>
+      <div wicket:id="imsAccordion_aim"/>
+      <div wicket:id="imsAccordion_gtalk"/>
+      <div wicket:id="imsAccordion_icq"/>
+      <div wicket:id="imsAccordion_xmpp"/>
+      <div wicket:id="imsAccordion_msn"/>
+      <div wicket:id="imsAccordion_skype"/>
+      <div wicket:id="imsAccordion_qq"/>
+      <div wicket:id="imsAccordion_yahoo"/>
+    </div>
+
+    <div style="margin-top: 15px;">
+      <label wicket:id="photosLabel"/>
+      <div wicket:id="photosAccordion_photo"/>
+      <div wicket:id="photosAccordion_thumbnail"/>
+    </div>
+  </wicket:panel>
+</html>
\ No newline at end of file
index e7cc2a4..1875eba 100644 (file)
  */
 package org.apache.syncope.common.lib.scim;
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import java.io.Serializable;
-import java.util.Date;
-import org.apache.commons.lang3.StringUtils;
 
 public class SCIMConf implements Serializable {
 
@@ -29,82 +26,18 @@ public class SCIMConf implements Serializable {
 
     public static final String KEY = "scimv2.conf";
 
-    private Date creationDate = new Date();
-
-    private Date lastChangeDate = new Date();
-
-    private int bulkMaxOperations = 1000;
-
-    private int bulkMaxPayloadSize = 1048576;
-
-    private int filterMaxResults = 200;
+    private SCIMGeneralConf generalConf;
 
     private SCIMUserConf userConf;
 
     private SCIMEnterpriseUserConf enterpriseUserConf;
 
-    public Date getCreationDate() {
-        if (creationDate != null) {
-            return new Date(creationDate.getTime());
-        }
-        return null;
-    }
-
-    public void setCreationDate(final Date creationDate) {
-        if (creationDate != null) {
-            this.creationDate = new Date(creationDate.getTime());
-        } else {
-            this.creationDate = null;
-        }
-    }
-
-    public Date getLastChangeDate() {
-        if (lastChangeDate != null) {
-            return new Date(lastChangeDate.getTime());
-        }
-        return null;
-    }
-
-    public void setLastChangeDate(final Date lastChangeDate) {
-        if (lastChangeDate != null) {
-            this.lastChangeDate = new Date(lastChangeDate.getTime());
-        } else {
-            this.lastChangeDate = null;
-        }
-    }
-
-    @JsonIgnore
-    public String getETagValue() {
-        Date etagDate = getLastChangeDate() == null
-                ? getCreationDate() : getLastChangeDate();
-        return etagDate == null
-                ? StringUtils.EMPTY
-                : String.valueOf(etagDate.getTime());
-
-    }
-
-    public int getBulkMaxOperations() {
-        return bulkMaxOperations;
-    }
-
-    public void setBulkMaxOperations(final int bulkMaxOperations) {
-        this.bulkMaxOperations = bulkMaxOperations;
-    }
-
-    public int getBulkMaxPayloadSize() {
-        return bulkMaxPayloadSize;
-    }
-
-    public void setBulkMaxPayloadSize(final int bulkMaxPayloadSize) {
-        this.bulkMaxPayloadSize = bulkMaxPayloadSize;
-    }
-
-    public int getFilterMaxResults() {
-        return filterMaxResults;
+    public SCIMGeneralConf getGeneralConf() {
+        return generalConf;
     }
 
-    public void setFilterMaxResults(final int filterMaxResults) {
-        this.filterMaxResults = filterMaxResults;
+    public void setGeneralConf(final SCIMGeneralConf generalConf) {
+        this.generalConf = generalConf;
     }
 
     public SCIMUserConf getUserConf() {
diff --git a/ext/scimv2/common-lib/src/main/java/org/apache/syncope/common/lib/scim/SCIMGeneralConf.java b/ext/scimv2/common-lib/src/main/java/org/apache/syncope/common/lib/scim/SCIMGeneralConf.java
new file mode 100644 (file)
index 0000000..cf9bc71
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.scim;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.io.Serializable;
+import java.util.Date;
+import org.apache.commons.lang3.StringUtils;
+
+public class SCIMGeneralConf implements Serializable {
+
+    private static final long serialVersionUID = 3228349133950736647L;
+
+    private Date creationDate = new Date();
+
+    private Date lastChangeDate = new Date();
+
+    private int bulkMaxOperations = 1000;
+
+    private int bulkMaxPayloadSize = 1048576;
+
+    private int filterMaxResults = 200;
+
+    public Date getCreationDate() {
+        if (creationDate != null) {
+            return new Date(creationDate.getTime());
+        }
+        return null;
+    }
+
+    public void setCreationDate(final Date creationDate) {
+        if (creationDate != null) {
+            this.creationDate = new Date(creationDate.getTime());
+        } else {
+            this.creationDate = null;
+        }
+    }
+
+    public Date getLastChangeDate() {
+        if (lastChangeDate != null) {
+            return new Date(lastChangeDate.getTime());
+        }
+        return null;
+    }
+
+    public void setLastChangeDate(final Date lastChangeDate) {
+        if (lastChangeDate != null) {
+            this.lastChangeDate = new Date(lastChangeDate.getTime());
+        } else {
+            this.lastChangeDate = null;
+        }
+    }
+
+    @JsonIgnore
+    public String getETagValue() {
+        Date etagDate = getLastChangeDate() == null
+                ? getCreationDate() : getLastChangeDate();
+        return etagDate == null
+                ? StringUtils.EMPTY
+                : String.valueOf(etagDate.getTime());
+
+    }
+
+    public int getBulkMaxOperations() {
+        return bulkMaxOperations;
+    }
+
+    public void setBulkMaxOperations(final int bulkMaxOperations) {
+        this.bulkMaxOperations = bulkMaxOperations;
+    }
+
+    public int getBulkMaxPayloadSize() {
+        return bulkMaxPayloadSize;
+    }
+
+    public void setBulkMaxPayloadSize(final int bulkMaxPayloadSize) {
+        this.bulkMaxPayloadSize = bulkMaxPayloadSize;
+    }
+
+    public int getFilterMaxResults() {
+        return filterMaxResults;
+    }
+
+    public void setFilterMaxResults(final int filterMaxResults) {
+        this.filterMaxResults = filterMaxResults;
+    }
+
+}
index 8c43c6c..efb1b33 100644 (file)
@@ -161,6 +161,7 @@ public class SCIMDataBinder {
         attrs.putAll(EntityTOUtils.buildAttrMap(userTO.getPlainAttrs()));
         attrs.putAll(EntityTOUtils.buildAttrMap(userTO.getDerAttrs()));
         attrs.putAll(EntityTOUtils.buildAttrMap(userTO.getVirAttrs()));
+        attrs.put("username", new AttrTO.Builder().schema("username").value(userTO.getUsername()).build());
 
         if (conf.getUserConf() != null) {
             if (output(attributes, excludedAttributes, "name") && conf.getUserConf().getName() != null) {
@@ -454,78 +455,72 @@ public class SCIMDataBinder {
                 if (conf.getUserConf().getName().getFamilyName() != null
                         && user.getName().getFamilyName() != null) {
 
-                    userTO.getPlainAttrs().add(new AttrTO.Builder().
-                            schema(conf.getUserConf().getName().getFamilyName()).
-                            value(user.getName().getFamilyName()).build());
+                    setAttribute(userTO, conf.getUserConf().getName().getFamilyName(),
+                            user.getName().getFamilyName());
                 }
                 if (conf.getUserConf().getName().getFormatted() != null
                         && user.getName().getFormatted() != null) {
 
-                    userTO.getPlainAttrs().add(new AttrTO.Builder().
-                            schema(conf.getUserConf().getName().getFormatted()).
-                            value(user.getName().getFormatted()).build());
+                    setAttribute(userTO, conf.getUserConf().getName().getFormatted(),
+                            user.getName().getFormatted());
                 }
                 if (conf.getUserConf().getName().getGivenName() != null
                         && user.getName().getGivenName() != null) {
 
-                    userTO.getPlainAttrs().add(new AttrTO.Builder().
-                            schema(conf.getUserConf().getName().getGivenName()).
-                            value(user.getName().getGivenName()).build());
+                    setAttribute(userTO, conf.getUserConf().getName().getGivenName(),
+                            user.getName().getGivenName());
                 }
                 if (conf.getUserConf().getName().getHonorificPrefix() != null
                         && user.getName().getHonorificPrefix() != null) {
 
-                    userTO.getPlainAttrs().add(new AttrTO.Builder().
-                            schema(conf.getUserConf().getName().getHonorificPrefix()).
-                            value(user.getName().getHonorificPrefix()).build());
+                    setAttribute(userTO, conf.getUserConf().getName().getHonorificPrefix(),
+                            user.getName().getHonorificPrefix());
                 }
                 if (conf.getUserConf().getName().getHonorificSuffix() != null
                         && user.getName().getHonorificSuffix() != null) {
 
-                    userTO.getPlainAttrs().add(new AttrTO.Builder().
-                            schema(conf.getUserConf().getName().getHonorificSuffix()).
-                            value(user.getName().getHonorificSuffix()).build());
+                    setAttribute(userTO, conf.getUserConf().getName().getHonorificSuffix(),
+                            user.getName().getHonorificSuffix());
                 }
                 if (conf.getUserConf().getName().getMiddleName() != null
                         && user.getName().getMiddleName() != null) {
 
-                    userTO.getPlainAttrs().add(new AttrTO.Builder().
-                            schema(conf.getUserConf().getName().getMiddleName()).
-                            value(user.getName().getMiddleName()).build());
+                    setAttribute(userTO, conf.getUserConf().getName().getMiddleName(),
+                            user.getName().getMiddleName());
                 }
             }
 
             if (conf.getUserConf().getDisplayName() != null && user.getDisplayName() != null) {
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getUserConf().getDisplayName()).value(user.getDisplayName()).build());
+                setAttribute(userTO, conf.getUserConf().getDisplayName(),
+                        user.getDisplayName());
             }
             if (conf.getUserConf().getNickName() != null && user.getNickName() != null) {
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getUserConf().getNickName()).value(user.getNickName()).build());
+                setAttribute(userTO, conf.getUserConf().getNickName(),
+                        user.getNickName());
             }
             if (conf.getUserConf().getProfileUrl() != null && user.getProfileUrl() != null) {
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getUserConf().getProfileUrl()).value(user.getProfileUrl()).build());
+                setAttribute(userTO, conf.getUserConf().getProfileUrl(),
+                        user.getProfileUrl());
             }
             if (conf.getUserConf().getTitle() != null && user.getTitle() != null) {
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getUserConf().getTitle()).value(user.getTitle()).build());
+                setAttribute(userTO, conf.getUserConf().getTitle(),
+                        user.getTitle());
             }
             if (conf.getUserConf().getUserType() != null && user.getUserType() != null) {
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getUserConf().getUserType()).value(user.getUserType()).build());
+                setAttribute(userTO, conf.getUserConf().getUserType(),
+                        user.getUserType());
             }
             if (conf.getUserConf().getPreferredLanguage() != null && user.getPreferredLanguage() != null) {
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getUserConf().getPreferredLanguage()).value(user.getPreferredLanguage()).build());
+                setAttribute(userTO, conf.getUserConf().getPreferredLanguage(),
+                        user.getPreferredLanguage());
             }
             if (conf.getUserConf().getLocale() != null && user.getLocale() != null) {
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getUserConf().getLocale()).value(user.getLocale()).build());
+                setAttribute(userTO, conf.getUserConf().getLocale(),
+                        user.getLocale());
             }
             if (conf.getUserConf().getTimezone() != null && user.getTimezone() != null) {
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getUserConf().getTimezone()).value(user.getTimezone()).build());
+                setAttribute(userTO, conf.getUserConf().getTimezone(),
+                        user.getTimezone());
             }
 
             fill(userTO.getPlainAttrs(), conf.getUserConf().getEmails(), user.getEmails());
@@ -538,28 +533,28 @@ public class SCIMDataBinder {
                         filter(object -> address.getType().equals(object.getType().name())).findFirst();
                 if (addressConf.isPresent()) {
                     if (addressConf.get().getFormatted() != null && address.getFormatted() != null) {
-                        userTO.getPlainAttrs().add(new AttrTO.Builder().
-                                schema(addressConf.get().getFormatted()).value(address.getFormatted()).build());
+                        setAttribute(userTO, addressConf.get().getFormatted(),
+                                address.getFormatted());
                     }
                     if (addressConf.get().getStreetAddress() != null && address.getStreetAddress() != null) {
-                        userTO.getPlainAttrs().add(new AttrTO.Builder().
-                                schema(addressConf.get().getStreetAddress()).value(address.getStreetAddress()).build());
+                        setAttribute(userTO, addressConf.get().getStreetAddress(),
+                                address.getStreetAddress());
                     }
                     if (addressConf.get().getLocality() != null && address.getLocality() != null) {
-                        userTO.getPlainAttrs().add(new AttrTO.Builder().
-                                schema(addressConf.get().getLocality()).value(address.getLocality()).build());
+                        setAttribute(userTO, addressConf.get().getLocality(),
+                                address.getLocality());
                     }
-                    if (addressConf.get().getRegion() != null && address.getFormatted() != null) {
-                        userTO.getPlainAttrs().add(new AttrTO.Builder().
-                                schema(addressConf.get().getFormatted()).value(address.getFormatted()).build());
+                    if (addressConf.get().getRegion() != null && address.getRegion() != null) {
+                        setAttribute(userTO, addressConf.get().getRegion(),
+                                address.getRegion());
                     }
                     if (addressConf.get().getPostalCode() != null && address.getPostalCode() != null) {
-                        userTO.getPlainAttrs().add(new AttrTO.Builder().
-                                schema(addressConf.get().getPostalCode()).value(address.getPostalCode()).build());
+                        setAttribute(userTO, addressConf.get().getPostalCode(),
+                                address.getPostalCode());
                     }
                     if (addressConf.get().getCountry() != null && address.getCountry() != null) {
-                        userTO.getPlainAttrs().add(new AttrTO.Builder().
-                                schema(addressConf.get().getCountry()).value(address.getCountry()).build());
+                        setAttribute(userTO, addressConf.get().getCountry(),
+                                address.getCountry());
                     }
                 }
             });
@@ -567,9 +562,8 @@ public class SCIMDataBinder {
             for (int i = 0; i < user.getX509Certificates().size(); i++) {
                 Value certificate = user.getX509Certificates().get(i);
                 if (conf.getUserConf().getX509Certificates().size() > i) {
-                    userTO.getPlainAttrs().add(new AttrTO.Builder().
-                            schema(conf.getUserConf().getX509Certificates().get(i)).
-                            value(certificate.getValue()).build());
+                    setAttribute(userTO, conf.getUserConf().getX509Certificates().get(i),
+                            certificate.getValue());
                 }
             }
         }
@@ -578,46 +572,40 @@ public class SCIMDataBinder {
             if (conf.getEnterpriseUserConf().getEmployeeNumber() != null
                     && user.getEnterpriseInfo().getEmployeeNumber() != null) {
 
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getEnterpriseUserConf().getEmployeeNumber()).
-                        value(user.getEnterpriseInfo().getEmployeeNumber()).build());
+                setAttribute(userTO, conf.getEnterpriseUserConf().getEmployeeNumber(),
+                        user.getEnterpriseInfo().getEmployeeNumber());
             }
             if (conf.getEnterpriseUserConf().getCostCenter() != null
                     && user.getEnterpriseInfo().getCostCenter() != null) {
 
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getEnterpriseUserConf().getCostCenter()).
-                        value(user.getEnterpriseInfo().getCostCenter()).build());
+                setAttribute(userTO, conf.getEnterpriseUserConf().getCostCenter(),
+                        user.getEnterpriseInfo().getCostCenter());
             }
             if (conf.getEnterpriseUserConf().getOrganization() != null
                     && user.getEnterpriseInfo().getOrganization() != null) {
 
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getEnterpriseUserConf().getOrganization()).
-                        value(user.getEnterpriseInfo().getOrganization()).build());
+                setAttribute(userTO, conf.getEnterpriseUserConf().getOrganization(),
+                        user.getEnterpriseInfo().getOrganization());
             }
             if (conf.getEnterpriseUserConf().getDivision() != null
                     && user.getEnterpriseInfo().getDivision() != null) {
 
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getEnterpriseUserConf().getDivision()).
-                        value(user.getEnterpriseInfo().getDivision()).build());
+                setAttribute(userTO, conf.getEnterpriseUserConf().getDivision(),
+                        user.getEnterpriseInfo().getDivision());
             }
             if (conf.getEnterpriseUserConf().getDepartment() != null
                     && user.getEnterpriseInfo().getDepartment() != null) {
 
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getEnterpriseUserConf().getDepartment()).
-                        value(user.getEnterpriseInfo().getDepartment()).build());
+                setAttribute(userTO, conf.getEnterpriseUserConf().getDepartment(),
+                        user.getEnterpriseInfo().getDepartment());
             }
             if (conf.getEnterpriseUserConf().getManager() != null
                     && conf.getEnterpriseUserConf().getManager().getKey() != null
                     && user.getEnterpriseInfo().getManager() != null
                     && user.getEnterpriseInfo().getManager().getValue() != null) {
 
-                userTO.getPlainAttrs().add(new AttrTO.Builder().
-                        schema(conf.getEnterpriseUserConf().getManager().getKey()).
-                        value(user.getEnterpriseInfo().getManager().getValue()).build());
+                setAttribute(userTO, conf.getEnterpriseUserConf().getManager().getKey(),
+                        user.getEnterpriseInfo().getManager().getValue());
             }
         }
 
@@ -632,6 +620,17 @@ public class SCIMDataBinder {
         return userTO;
     }
 
+    private void setAttribute(final UserTO userTO, final String schema, final String value) {
+        switch (schema) {
+            case "username":
+                userTO.setUsername(value);
+                break;
+
+            default:
+                userTO.getPlainAttrs().add(new AttrTO.Builder().schema(schema).value(value).build());
+        }
+    }
+
     public SCIMGroup toSCIMGroup(
             final GroupTO groupTO,
             final String location,
index 04757f2..f09bdeb 100644 (file)
@@ -98,13 +98,15 @@ public class SCIMLogic extends AbstractLogic<AbstractBaseBean> {
                 SERVICE_PROVIDER_CONFIG = new ServiceProviderConfig(
                         new Meta(
                                 Resource.ServiceProviderConfig,
-                                conf.getCreationDate(),
-                                conf.getLastChangeDate(),
-                                conf.getETagValue(),
+                                conf.getGeneralConf().getCreationDate(),
+                                conf.getGeneralConf().getLastChangeDate(),
+                                conf.getGeneralConf().getETagValue(),
                                 uriBuilder.build().toASCIIString()),
                         new ConfigurationOption(false),
-                        new BulkConfigurationOption(false, conf.getBulkMaxOperations(), conf.getBulkMaxPayloadSize()),
-                        new FilterConfigurationOption(true, conf.getFilterMaxResults()),
+                        new BulkConfigurationOption(false,
+                                conf.getGeneralConf().getBulkMaxOperations(),
+                                conf.getGeneralConf().getBulkMaxPayloadSize()),
+                        new FilterConfigurationOption(true, conf.getGeneralConf().getFilterMaxResults()),
                         new ConfigurationOption(true),
                         new ConfigurationOption(true),
                         new ConfigurationOption(true));
index ede870b..2804d78 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.syncope.core.logic.scim;
 import java.util.Date;
 import javax.ws.rs.core.MediaType;
 import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.SCIMGeneralConf;
 import org.apache.syncope.common.lib.scim.types.SCIMEntitlement;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.PlainSchemaTO;
@@ -84,7 +85,8 @@ public class SCIMConfManager {
             scimConf.setMimeType(MediaType.APPLICATION_JSON);
             schemaLogic.create(SchemaType.PLAIN, scimConf);
         }
-        conf.setLastChangeDate(new Date());
+        conf.setGeneralConf(new SCIMGeneralConf());
+        conf.getGeneralConf().setLastChangeDate(new Date());
 
         configurationLogic.set(new AttrTO.Builder().
                 schema(SCIMConf.KEY).value(Base64.encode(POJOHelper.serialize(conf).getBytes())).build());
index cb8bb5f..6bec6e2 100644 (file)
@@ -189,7 +189,7 @@ abstract class AbstractService<R extends SCIMResource> {
             throw new UnsupportedOperationException();
         }
 
-        if (request.getCount() > confManager().get().getFilterMaxResults()) {
+        if (request.getCount() > confManager().get().getGeneralConf().getFilterMaxResults()) {
             throw new BadRequestException(ErrorType.tooMany, "Too many results requested");
         }
 
@@ -223,7 +223,7 @@ abstract class AbstractService<R extends SCIMResource> {
                 SyncopeConstants.ROOT_REALM,
                 false);
 
-        if (result.getLeft() > confManager().get().getFilterMaxResults()) {
+        if (result.getLeft() > confManager().get().getGeneralConf().getFilterMaxResults()) {
             throw new BadRequestException(ErrorType.tooMany, "Too many results found");
         }