http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/DateTimeFieldPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/DateTimeFieldPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/DateTimeFieldPanel.java
new file mode 100644
index 0000000..d8014f6
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/DateTimeFieldPanel.java
@@ -0,0 +1,195 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import java.util.Calendar;
+import java.util.Date;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.extensions.yui.calendar.DateTimeField;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.FormComponent;
+import org.apache.wicket.markup.html.form.validation.AbstractFormValidator;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.validation.IValidationError;
+import org.apache.wicket.validation.ValidationError;
+
+public class DateTimeFieldPanel extends DateFieldPanel {
+
+    private static final long serialVersionUID = -428975732068281726L;
+
+    private Form form = null;
+
+    public DateTimeFieldPanel(final String id, final String name, final 
IModel<Date> model, final String datePattern) {
+        super(id, name, model, datePattern);
+
+        field = new DateTimeField("field", model);
+
+        final Calendar cal = Calendar.getInstance();
+
+        field.get("hours").add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                final Integer hours = ((DateTimeField) field).getHours();
+                if (hours != null) {
+                    cal.set(hours > 12 ? Calendar.HOUR_OF_DAY : Calendar.HOUR, 
hours);
+                    field.setModelObject(cal.getTime());
+                }
+            }
+        });
+
+        field.get("minutes").add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                final Integer minutes = ((DateTimeField) field).getMinutes();
+                if (minutes != null) {
+                    cal.set(Calendar.MINUTE, minutes);
+                    field.setModelObject(cal.getTime());
+                }
+            }
+        });
+
+        field.get("date").add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                final Date date = ((DateTimeField) field).getDate();
+                if (date == null) {
+                    field.setModelObject(null);
+                } else {
+                    cal.setTime(date);
+                    cal.set(Calendar.AM_PM, "PM".equals("" + ((DateTimeField) 
field).getAmOrPm()) ? Calendar.PM
+                            : Calendar.AM);
+                    field.setModelObject(cal.getTime());
+                }
+            }
+        });
+
+        field.get("amOrPmChoice").add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                cal.set(Calendar.AM_PM, "PM".equals("" + ((DateTimeField) 
field).getAmOrPm()) ? Calendar.PM
+                        : Calendar.AM);
+                field.setModelObject(cal.getTime());
+            }
+        });
+
+        add(field.setLabel(new Model<String>(name)).setOutputMarkupId(true));
+    }
+
+    /**
+     * Custom form validator for registering and handling DateTimeField 
components that are in it.
+     */
+    private class DateTimeFormValidator extends AbstractFormValidator {
+
+        private static final long serialVersionUID = 6842264694946633582L;
+
+        private FormComponent[] dateTimeComponents;
+
+        public DateTimeFormValidator(final DateTimeField dateTimeComponent) {
+            if (dateTimeComponent == null) {
+                throw new IllegalArgumentException("argument dateTimeComponent 
cannot be null");
+            }
+
+            dateTimeComponents = new FormComponent[] { dateTimeComponent };
+        }
+
+        @Override
+        public FormComponent[] getDependentFormComponents() {
+            return dateTimeComponents;
+        }
+
+        /**
+         * Validation rule : all 3 fields (date,hours,minutes) must be 
not-null.
+         *
+         * @param form
+         */
+        @Override
+        public void validate(final Form form) {
+            final DateTimeField dateTimeField = (DateTimeField) 
dateTimeComponents[0];
+
+            if (!(dateTimeField.getDate() != null && dateTimeField.getHours() 
!= null
+                    && dateTimeField.getMinutes() != null)) {
+
+                ValidationError ve = new ValidationError();
+                ve.setVariables(DateTimeFormValidator.this.variablesMap());
+                ve.addKey(resourceKey());
+                dateTimeComponents[0].error((IValidationError) ve);
+            }
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    public FieldPanel<Date> setFormValidator(final Form form) {
+        if (field == null) {
+            LOG.error("Error setting form validator");
+        } else {
+            form.add(new DateTimeFormValidator(((DateTimeField) field)));
+            this.form = form;
+        }
+
+        return this;
+    }
+
+    @Override
+    public FieldPanel<Date> setStyleSheet(final String classes) {
+        field.get("date").add(AttributeModifier.replace("class", (classes == 
null ? "" : classes) + " date_size"));
+
+        field.get("hours").add(AttributeModifier.replace("class", classes == 
null ? "" : classes));
+
+        field.get("minutes").add(AttributeModifier.replace("class", classes == 
null ? "" : classes));
+
+        field.get("amOrPmChoice").add(AttributeModifier.replace("class", 
classes == null ? "" : classes));
+
+        return this;
+    }
+
+    @Override
+    public FieldPanel<Date> clone() {
+        final FieldPanel<Date> panel = new DateTimeFieldPanel(getId(), name, 
new Model<Date>(null), datePattern);
+
+        panel.setRequired(isRequired());
+        panel.setReadOnly(isReadOnly());
+        panel.setTitle(title);
+
+        if (isRequiredLabelAdded) {
+            panel.addRequiredLabel();
+        }
+
+        if (form != null && isRequired()) {
+            ((DateTimeFieldPanel) panel).setFormValidator(form);
+        }
+
+        return panel;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java
new file mode 100644
index 0000000..8dbc434
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java
@@ -0,0 +1,199 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import java.io.Serializable;
+import java.util.List;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.FormComponent;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+public abstract class FieldPanel<T> extends AbstractFieldPanel<T> implements 
Cloneable {
+
+    private static final long serialVersionUID = -198988924922541273L;
+
+    protected FormComponent<T> field = null;
+
+    protected String title = null;
+
+    protected boolean isRequiredLabelAdded = false;
+
+    public FieldPanel(final String id, final IModel<T> model) {
+        super(id, model);
+
+        final Fragment fragment = new Fragment("required", 
"notRequiredFragment", this);
+        add(fragment);
+
+        setOutputMarkupId(true);
+    }
+
+    public FormComponent<T> getField() {
+        return field;
+    }
+
+    public FieldPanel<T> setTitle(final String title) {
+        this.title = title;
+        field.add(AttributeModifier.replace("title", title != null
+                ? title
+                : ""));
+
+        return this;
+    }
+
+    public FieldPanel<T> setStyleSheet(final String classes) {
+        field.add(AttributeModifier.replace("class", classes != null
+                ? classes
+                : ""));
+
+        return this;
+    }
+
+    public FieldPanel<T> setRequired(boolean required) {
+        field.setRequired(required);
+
+        return this;
+    }
+
+    public FieldPanel<T> setReadOnly(boolean readOnly) {
+        field.setEnabled(!readOnly);
+
+        return this;
+    }
+
+    public boolean isRequired() {
+        return field.isRequired();
+    }
+
+    public boolean isReadOnly() {
+        return !field.isEnabled();
+    }
+
+    public FieldPanel<T> addRequiredLabel() {
+        if (!isRequired()) {
+            setRequired(true);
+        }
+
+        final Fragment fragment = new Fragment("required", "requiredFragment", 
this);
+
+        fragment.add(new Label("requiredLabel", "*"));
+
+        replace(fragment);
+
+        this.isRequiredLabelAdded = true;
+
+        return this;
+    }
+
+    public FieldPanel<T> removeRequiredLabel() {
+        if (isRequired()) {
+            setRequired(false);
+        }
+
+        final Fragment fragment = new Fragment("required", 
"notRequiredFragment", this);
+
+        replace(fragment);
+
+        this.isRequiredLabelAdded = false;
+
+        return this;
+    }
+
+    @Override
+    public FieldPanel<T> setModelObject(final T object) {
+        field.setModelObject(object);
+        return this;
+    }
+
+    public T getModelObject() {
+        return (T) field.getModelObject();
+    }
+
+    public FieldPanel<T> setNewModel(final IModel<T> model) {
+        field.setModel(model);
+        return this;
+    }
+
+    /**
+     * Used by MultiValueSelectorPanel to attach items.
+     *
+     * @param item item to attach.
+     * @return updated FieldPanel object.
+     */
+    public FieldPanel<T> setNewModel(final ListItem<T> item) {
+        setNewModel(new IModel<T>() {
+
+            private static final long serialVersionUID = 6799404673615637845L;
+
+            @Override
+            public T getObject() {
+                return item.getModelObject();
+            }
+
+            @Override
+            public void setObject(final T object) {
+                item.setModelObject(object);
+            }
+
+            @Override
+            public void detach() {
+                // no detach
+            }
+        });
+        return this;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public FieldPanel<T> setNewModel(final List<Serializable> list) {
+        setNewModel(new Model() {
+
+            private static final long serialVersionUID = 1088212074765051906L;
+
+            @Override
+            public Serializable getObject() {
+                return list == null || list.isEmpty()
+                        ? null
+                        : list.get(0);
+            }
+
+            @Override
+            public void setObject(final Serializable object) {
+                list.clear();
+
+                if (object != null) {
+                    list.add(object);
+                }
+            }
+        });
+
+        return this;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public FieldPanel<T> clone() {
+        final FieldPanel<T> panel = SerializationUtils.clone(this);
+        panel.setModelObject(null);
+        return panel;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java
new file mode 100644
index 0000000..b31bbab
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java
@@ -0,0 +1,39 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+
+/**
+ * This empty class must exist because there not seems to be alternative to
+ * provide specialized HTML for links.
+ */
+public class LinkPanel extends Panel {
+
+    private static final long serialVersionUID = 4799005986804366330L;
+
+    public LinkPanel(final String id) {
+        super(id);
+    }
+
+    public LinkPanel(final String id, final IModel<?> model) {
+        super(id, model);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.java
new file mode 100644
index 0000000..2c41f37
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.java
@@ -0,0 +1,133 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+public class MappingPurposePanel extends Panel {
+
+    private static final long serialVersionUID = 322966537010107771L;
+
+    private final AjaxLink<Void> propagation;
+
+    private final AjaxLink<Void> synchronization;
+
+    private final AjaxLink<Void> both;
+
+    private final AjaxLink<Void> none;
+
+    public MappingPurposePanel(final String componentId, final 
IModel<MappingPurpose> model,
+            final WebMarkupContainer container) {
+
+        super(componentId, model);
+
+        propagation = new AjaxLink<Void>("propagationPurposeLink") {
+
+            private static final long serialVersionUID = -6957616042924610305L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                model.setObject(MappingPurpose.PROPAGATION);
+                setOpacity(MappingPurpose.PROPAGATION);
+                target.add(container);
+            }
+        };
+
+        synchronization = new AjaxLink<Void>("synchronizationPurposeLink") {
+
+            private static final long serialVersionUID = -6957616042924610305L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                model.setObject(MappingPurpose.SYNCHRONIZATION);
+                setOpacity(MappingPurpose.SYNCHRONIZATION);
+                target.add(container);
+            }
+        };
+
+        both = new AjaxLink<Void>("bothPurposeLink") {
+
+            private static final long serialVersionUID = -6957616042924610305L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                model.setObject(MappingPurpose.BOTH);
+                setOpacity(MappingPurpose.BOTH);
+                target.add(container);
+            }
+        };
+
+        none = new AjaxLink<Void>("nonePurposeLink") {
+
+            private static final long serialVersionUID = -6957616042924610305L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                model.setObject(MappingPurpose.NONE);
+                setOpacity(MappingPurpose.NONE);
+                target.add(container);
+            }
+        };
+
+        add(propagation);
+        add(synchronization);
+        add(both);
+        add(none);
+
+        setOpacity(model.getObject());
+    }
+
+    private void setOpacity(final MappingPurpose mappingPurpose) {
+        switch (mappingPurpose) {
+            case PROPAGATION:
+                propagation.add(new AttributeModifier("style", new 
Model<String>("opacity: 1;")));
+                synchronization.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                both.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                none.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                break;
+            case SYNCHRONIZATION:
+                synchronization.add(new AttributeModifier("style", new 
Model<String>("opacity: 1;")));
+                propagation.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                both.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                none.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                break;
+            case BOTH:
+                both.add(new AttributeModifier("style", new 
Model<String>("opacity: 1;")));
+                propagation.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                synchronization.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                none.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                break;
+            case NONE:
+                none.add(new AttributeModifier("style", new 
Model<String>("opacity: 1;")));
+                synchronization.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                propagation.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                both.add(new AttributeModifier("style", new 
Model<String>("opacity: 0.3;")));
+                break;
+            default:
+            // do nothing
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java
new file mode 100644
index 0000000..cd4ab2a
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java
@@ -0,0 +1,172 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.model.IModel;
+
+public class MultiFieldPanel<E> extends AbstractFieldPanel<List<E>> {
+
+    private static final long serialVersionUID = -6322397761456513324L;
+
+    private ListView<E> view;
+
+    private WebMarkupContainer container;
+
+    public MultiFieldPanel(final String id, final IModel<List<E>> model, final 
FieldPanel<E> panelTemplate) {
+        this(id, model, panelTemplate, false);
+    }
+
+    public MultiFieldPanel(final String id, final IModel<List<E>> model, final 
FieldPanel<E> panelTemplate,
+            final boolean eventTemplate) {
+
+        super(id, model);
+
+        // -----------------------
+        // Object container definition
+        // -----------------------
+        container = new WebMarkupContainer("multiValueContainer");
+        container.setOutputMarkupId(true);
+        add(container);
+        // -----------------------
+
+        view = new ListView<E>("view", model) {
+
+            private static final long serialVersionUID = -9180479401817023838L;
+
+            @Override
+            protected void populateItem(final ListItem<E> item) {
+                final FieldPanel<E> fieldPanel = panelTemplate.clone();
+
+                if (eventTemplate) {
+                    fieldPanel.getField().add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+                        private static final long serialVersionUID = 
-1107858522700306810L;
+
+                        @Override
+                        protected void onUpdate(final AjaxRequestTarget 
target) {
+                            send(getPage(), Broadcast.BREADTH, new 
MultiValueSelectorEvent(target));
+                        }
+                    });
+                }
+
+               fieldPanel.getField().add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_BLUR) {
+                    
+                    private static final long serialVersionUID = 
-1107858522700306810L;
+  
+                        @Override
+                        protected void onUpdate(final AjaxRequestTarget 
target) {
+                        }
+                    });
+
+                fieldPanel.setNewModel(item);
+                item.add(fieldPanel);
+
+                AjaxLink<Void> minus = new IndicatingAjaxLink<Void>("drop") {
+
+                    private static final long serialVersionUID = 
-7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        //Drop current component
+                        model.getObject().remove(item.getModelObject());
+                        fieldPanel.getField().clearInput();
+                        target.add(container);
+                        
+                        if (eventTemplate) {
+                            send(getPage(), Broadcast.BREADTH, new 
MultiValueSelectorEvent(target));
+                        }
+                    }
+                };
+
+                item.add(minus);
+
+                if (model.getObject().size() <= 1) {
+                    minus.setVisible(false);
+                    minus.setEnabled(false);
+                } else {
+                    minus.setVisible(true);
+                    minus.setEnabled(true);
+                }
+
+                final Fragment fragment;
+                if (item.getIndex() == model.getObject().size() - 1) {
+                    final AjaxLink<Void> plus = new 
IndicatingAjaxLink<Void>("add") {
+
+                        private static final long serialVersionUID = 
-7978723352517770644L;
+
+                        @Override
+                        public void onClick(final AjaxRequestTarget target) {
+                            //Add current component
+                            model.getObject().add(null);
+                            target.add(container);
+                        }
+                    };
+
+                    fragment = new Fragment("panelPlus", "fragmentPlus", 
container);
+
+                    fragment.add(plus);
+                } else {
+                    fragment = new Fragment("panelPlus", "emptyFragment", 
container);
+                }
+                item.add(fragment);
+            }
+        };
+
+        container.add(view.setOutputMarkupId(true));
+        setOutputMarkupId(true);
+    }
+
+    public ListView<E> getView() {
+        return view;
+    }
+
+    public WebMarkupContainer getContainer() {
+        return container;
+    }
+
+    @Override
+    public MultiFieldPanel<E> setModelObject(final List<E> object) {
+        view.setModelObject(object);
+        return this;
+    }
+
+    public static class MultiValueSelectorEvent {
+
+        final AjaxRequestTarget target;
+
+        public MultiValueSelectorEvent(final AjaxRequestTarget target) {
+            this.target = target;
+        }
+
+        public AjaxRequestTarget getTarget() {
+            return target;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/NonI18nPalette.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/NonI18nPalette.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/NonI18nPalette.java
new file mode 100644
index 0000000..55038da
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/NonI18nPalette.java
@@ -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.wicket.markup.html.form;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.wicket.extensions.markup.html.form.palette.Palette;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.model.IModel;
+
+public class NonI18nPalette<T> extends Palette<T> {
+
+    private static final long serialVersionUID = 2659070187837941889L;
+
+    public NonI18nPalette(final String id,
+            final IModel<? extends List<? extends T>> model,
+            final IModel<? extends Collection<? extends T>> choicesModel,
+            final IChoiceRenderer<T> choiceRenderer, final int rows,
+            final boolean allowOrder, final boolean allowMoveAll) {
+
+        super(id, model, choicesModel, choiceRenderer, rows, allowOrder, 
allowMoveAll);
+    }
+
+    @Override
+    protected boolean localizeDisplayValues() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/SelectableRecorder.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/SelectableRecorder.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/SelectableRecorder.java
new file mode 100644
index 0000000..2893533
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/SelectableRecorder.java
@@ -0,0 +1,204 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.extensions.markup.html.form.palette.Palette;
+import 
org.apache.wicket.extensions.markup.html.form.palette.component.Recorder;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * A variant of Recorder, supporting single element selection (for editing 
purpose, for example). <b>Note</b>: this
+ * class extends Recorder<T> but in fact it is a bare copy of most source 
code; this was done because the original class
+ * is keeping everything private.
+ *
+ * @param <T> Type of the palette
+ */
+public class SelectableRecorder<T> extends Recorder<T> {
+
+    private static final long serialVersionUID = -3009044376132921879L;
+
+    private boolean attached = false;
+
+    private static final String[] EMPTY_IDS = new String[0];
+
+    /**
+     * Conveniently maintained array of selected ids.
+     */
+    private String[] ids;
+
+    private String selectedId;
+
+    public SelectableRecorder(final String id, final Palette<T> palette) {
+        super(id, palette);
+    }
+
+    @Override
+    protected void onBeforeRender() {
+        super.onBeforeRender();
+
+        if (!getForm().hasError()) {
+            initIds();
+        } else if (ids == null) {
+            ids = EMPTY_IDS;
+        }
+        attached = true;
+    }
+
+    /**
+     * Synchronize ids collection from the palette's model
+     */
+    private void initIds() {
+        // construct the model string based on selection collection
+        IChoiceRenderer<T> renderer = getPalette().getChoiceRenderer();
+        StringBuilder modelStringBuffer = new StringBuilder();
+        Collection<T> modelCollection = getPalette().getModelCollection();
+        if (modelCollection == null) {
+            throw new WicketRuntimeException("Expected 
getPalette().getModelCollection() to return a non-null value."
+                    + " Please make sure you have model object assigned to the 
palette");
+        }
+        Iterator<T> selection = modelCollection.iterator();
+
+        int i = 0;
+        while (selection.hasNext()) {
+            modelStringBuffer.append(renderer.getIdValue(selection.next(), 
i++));
+            if (selection.hasNext()) {
+                modelStringBuffer.append(",");
+            }
+        }
+
+        // set model and update ids array
+        String modelString = modelStringBuffer.toString();
+        setDefaultModel(new Model<String>(modelString));
+        updateIds(modelString);
+    }
+
+    public T getSelectedItem() {
+        if (selectedId == null) {
+            return null;
+        }
+
+        IChoiceRenderer<T> renderer = getPalette().getChoiceRenderer();
+
+        T selected = null;
+        for (T choice : getPalette().getChoices()) {
+            if (renderer.getIdValue(choice, 0).equals(selectedId)) {
+                selected = choice;
+                break;
+            }
+        }
+
+        return selected;
+    }
+
+    /**
+     * @return iterator over selected choices
+     */
+    @Override
+    public Iterator<T> getSelectedChoices() {
+        IChoiceRenderer<T> renderer = getPalette().getChoiceRenderer();
+        if (ids.length == 0) {
+            return Collections.<T>emptyList().iterator();
+        }
+
+        List<T> selected = new ArrayList<T>(ids.length);
+        for (String id : ids) {
+            for (T choice : getPalette().getChoices()) {
+                if (renderer.getIdValue(choice, 0).equals(id)) {
+                    selected.add(choice);
+                    break;
+                }
+            }
+        }
+        return selected.iterator();
+    }
+
+    /**
+     * @return iterator over unselected choices
+     */
+    @Override
+    public Iterator<T> getUnselectedChoices() {
+        IChoiceRenderer<T> renderer = getPalette().getChoiceRenderer();
+        Collection<? extends T> choices = getPalette().getChoices();
+
+        if (choices.size() - ids.length == 0) {
+            return Collections.<T>emptyList().iterator();
+        }
+
+        List<T> unselected = new ArrayList<T>(Math.max(1, choices.size() - 
ids.length));
+        for (T choice : choices) {
+            final String choiceId = renderer.getIdValue(choice, 0);
+            boolean selected = false;
+            for (String id : ids) {
+                if (id.equals(choiceId)) {
+                    selected = true;
+                    break;
+                }
+            }
+            if (!selected) {
+                unselected.add(choice);
+            }
+        }
+        return unselected.iterator();
+    }
+
+    @Override
+    protected void onValid() {
+        super.onValid();
+        if (attached) {
+            updateIds();
+        }
+    }
+
+    @Override
+    protected void onInvalid() {
+        super.onInvalid();
+        if (attached) {
+            updateIds();
+        }
+    }
+
+    private void updateIds() {
+        updateIds(getValue());
+    }
+
+    @Override
+    protected void updateIds(final String value) {
+        if (Strings.isEmpty(value)) {
+            ids = EMPTY_IDS;
+        } else {
+            if (value.indexOf('|') == -1) {
+                ids = value.split(",");
+                selectedId = null;
+            } else {
+                String[] splitted = value.split("\\|");
+                selectedId = splitted[0];
+                ids = splitted[1].split(",");
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/SpinnerFieldPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/SpinnerFieldPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/SpinnerFieldPanel.java
new file mode 100644
index 0000000..4f71f81
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/SpinnerFieldPanel.java
@@ -0,0 +1,197 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.UUID;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.springframework.util.StringUtils;
+
+public class SpinnerFieldPanel<T extends Number> extends FieldPanel<T> {
+
+    private static final long serialVersionUID = 6413819574530703577L;
+
+    private final String name;
+
+    private final Class<T> reference;
+
+    private final IModel<T> model;
+
+    private final T min;
+
+    private final T max;
+
+    @SuppressWarnings("unchecked")
+    public SpinnerFieldPanel(final String id, final String name, final 
Class<T> reference, final IModel<T> model,
+            final T min, final T max) {
+
+        super(id, model);
+        this.name = name;
+        this.reference = reference;
+        this.model = model;
+        this.min = min;
+        this.max = max;
+
+        String uuid = UUID.randomUUID().toString();
+        field = new TextField<T>("spinnerField", model, reference);
+        field.setMarkupId(uuid);
+        add(field.setLabel(new Model<String>(name)));
+
+        if (!isReadOnly()) {
+            field.add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+                private static final long serialVersionUID = 
-1107858522700306810L;
+
+                @Override
+                protected void onUpdate(final AjaxRequestTarget target) {
+                    // nothing to do
+                }
+            });
+        }
+
+        final StringBuilder statements = new StringBuilder();
+        statements.append("jQuery(function() {").
+                append("var spinner = 
$('#").append(uuid).append("').spinner();").
+                append("$('#").append(uuid).append("').spinner(").
+                append("'option', 'stop', function(event, ui) { 
$(this).change(); });");
+        if (this.min != null) {
+            statements.
+                    append("$('#").append(uuid).append("').spinner(").
+                    append("'option', 'min', ").append(this.min).append(");");
+        }
+        if (this.max != null) {
+            statements.
+                    append("$('#").append(uuid).append("').spinner(").
+                    append("'option', 'max', ").append(this.max).append(");");
+        }
+        statements.append("});");
+        Label spinnerFieldJS = new Label("spinnerFieldJS", 
statements.toString());
+        spinnerFieldJS.setEscapeModelStrings(false);
+        add(spinnerFieldJS);
+    }
+
+    @Override
+    public SpinnerFieldPanel<T> setNewModel(final List<Serializable> list) {
+        setNewModel(new Model<T>() {
+
+            private static final long serialVersionUID = 527651414610325237L;
+
+            @Override
+            public T getObject() {
+                T value = null;
+
+                if (list != null && !list.isEmpty() && 
StringUtils.hasText(list.get(0).toString())) {
+                    value = reference.equals(Integer.class)
+                            ? 
reference.cast(NumberUtils.toInt(list.get(0).toString()))
+                            : reference.equals(Long.class)
+                            ? 
reference.cast(NumberUtils.toLong(list.get(0).toString()))
+                            : reference.equals(Short.class)
+                            ? 
reference.cast(NumberUtils.toShort(list.get(0).toString()))
+                            : reference.equals(Float.class)
+                            ? 
reference.cast(NumberUtils.toFloat(list.get(0).toString()))
+                            : reference.equals(byte.class)
+                            ? 
reference.cast(NumberUtils.toByte(list.get(0).toString()))
+                            : 
reference.cast(NumberUtils.toDouble(list.get(0).toString()));
+                }
+
+                return value;
+            }
+
+            @Override
+            public void setObject(final T object) {
+                list.clear();
+                if (object != null) {
+                    list.add(object.toString());
+                }
+            }
+        });
+
+        return this;
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public SpinnerFieldPanel<T> setNewModel(final ListItem item) {
+        field.setModel(new Model<T>() {
+
+            private static final long serialVersionUID = 6799404673615637845L;
+
+            @Override
+            public T getObject() {
+                T number = null;
+
+                final Object obj = item.getModelObject();
+
+                if (obj != null && !obj.toString().isEmpty()) {
+                    if (obj instanceof String) {
+                        number = reference.equals(Integer.class)
+                                ? reference.cast(Integer.valueOf((String) obj))
+                                : reference.equals(Long.class)
+                                ? reference.cast(Long.valueOf((String) obj))
+                                : reference.equals(Short.class)
+                                ? reference.cast(Short.valueOf((String) obj))
+                                : reference.equals(Float.class)
+                                ? reference.cast(Float.valueOf((String) obj))
+                                : reference.equals(byte.class)
+                                ? reference.cast(Byte.valueOf((String) obj))
+                                : reference.cast(Double.valueOf((String) obj));
+                    } else if (obj instanceof Number) {
+                        // Don't parse anything
+                        number = reference.cast(obj);
+                    }
+                }
+
+                return number;
+            }
+
+            @Override
+            @SuppressWarnings("unchecked")
+            public void setObject(final T object) {
+                item.setModelObject(object == null ? null : object.toString());
+            }
+        });
+
+        return this;
+    }
+
+    @Override
+    public SpinnerFieldPanel<T> clone() {
+        SpinnerFieldPanel<T> panel = new SpinnerFieldPanel<T>(getId(), name, 
reference, model, min, max);
+
+        panel.setRequired(isRequired());
+        panel.setReadOnly(isReadOnly());
+        panel.setTitle(title);
+
+        if (isRequiredLabelAdded) {
+            panel.addRequiredLabel();
+        }
+
+        return panel;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/AbstractBinaryPreviewer.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/AbstractBinaryPreviewer.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/AbstractBinaryPreviewer.java
new file mode 100644
index 0000000..24bdb47
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/AbstractBinaryPreviewer.java
@@ -0,0 +1,46 @@
+/*
+ * 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.wicket.markup.html.form.preview;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractBinaryPreviewer extends Panel {
+
+    /**
+     * Logger.
+     */
+    protected static final Logger LOG = 
LoggerFactory.getLogger(AbstractBinaryPreviewer.class);
+
+    private static final long serialVersionUID = -2482706463911903025L;
+
+    protected final String mimeType;
+
+    protected final byte[] uploadedBytes;
+
+    public AbstractBinaryPreviewer(final String id, final String mimeType, 
final byte[] uploadedBytes) {
+        super(id);
+        this.mimeType = mimeType;
+        this.uploadedBytes = uploadedBytes;
+    }
+
+    public abstract Component preview();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryCertPreviewer.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryCertPreviewer.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryCertPreviewer.java
new file mode 100644
index 0000000..61589d7
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryCertPreviewer.java
@@ -0,0 +1,70 @@
+/*
+ * 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.wicket.markup.html.form.preview;
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.BinaryPreview;
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.util.io.IOUtils;
+
+@BinaryPreview(mimeTypes = { "application/x-x509-ca-cert", 
"application/x-x509-user-cert", "application/pkix-cert" })
+public class BinaryCertPreviewer extends AbstractBinaryPreviewer {
+
+    private static final long serialVersionUID = -5843835939538055110L;
+
+    public BinaryCertPreviewer(final String id, final String mimeType, final 
byte[] uploadedBytes) {
+        super(id, mimeType, uploadedBytes);
+    }
+
+    @Override
+    public Component preview() {
+        final Label commonNameLabel = new Label("certCommonName", new 
Model<String>());
+        final ByteArrayInputStream certificateStream = new 
ByteArrayInputStream(uploadedBytes);
+        try {
+            final X509Certificate certificate = (X509Certificate) 
CertificateFactory.getInstance("X.509").
+                    generateCertificate(certificateStream);
+
+            final StringBuilder commonNameBuilder = new StringBuilder("cn=");
+
+            final LdapName ldapName = new 
LdapName(certificate.getIssuerDN().getName());
+
+            for (Rdn rdn : ldapName.getRdns()) {
+                if ("CN".equalsIgnoreCase(rdn.getType())) {
+                    commonNameBuilder.append(rdn.getValue() == null
+                            ? StringUtils.EMPTY
+                            : rdn.getValue().toString());
+                }
+            }
+            
commonNameLabel.setDefaultModelObject(commonNameBuilder.toString());
+        } catch (Exception e) {
+            LOG.error("Error evaluating certificate file", e);
+            throw new IllegalArgumentException("Error evaluating certificate 
file", e);
+        } finally {
+            IOUtils.closeQuietly(certificateStream);
+        }
+        return this.add(commonNameLabel);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryImagePreviewer.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryImagePreviewer.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryImagePreviewer.java
new file mode 100644
index 0000000..35e442e
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryImagePreviewer.java
@@ -0,0 +1,51 @@
+/*
+ * 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.wicket.markup.html.form.preview;
+
+import org.apache.syncope.client.console.BinaryPreview;
+import org.apache.wicket.Component;
+import 
org.apache.wicket.extensions.markup.html.image.resource.ThumbnailImageResource;
+import org.apache.wicket.markup.html.image.NonCachingImage;
+import org.apache.wicket.request.resource.DynamicImageResource;
+import org.apache.wicket.request.resource.IResource;
+
+@BinaryPreview(mimeTypes = { "image/jpeg", "image/png", "image/gif", 
"image/bmp", "image/x-png", "image/vnd.wap.wbmp" })
+public class BinaryImagePreviewer extends AbstractBinaryPreviewer {
+
+    private static final long serialVersionUID = 3338812359368457349L;
+
+    private static final int IMG_SIZE = 230;
+
+    public BinaryImagePreviewer(final String id, final String mimeType, final 
byte[] uploadedBytes) {
+        super(id, mimeType, uploadedBytes);
+    }
+
+    @Override
+    public Component preview() {
+        return this.add(new NonCachingImage("previewImage", new 
ThumbnailImageResource(new DynamicImageResource() {
+
+            private static final long serialVersionUID = 923201517955737928L;
+
+            @Override
+            protected byte[] getImageData(final IResource.Attributes 
attributes) {
+                return uploadedBytes;
+            }
+        }, IMG_SIZE)));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/link/VeilPopupSettings.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/link/VeilPopupSettings.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/link/VeilPopupSettings.java
new file mode 100644
index 0000000..51c8ec5
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/link/VeilPopupSettings.java
@@ -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.
+ */
+package org.apache.syncope.client.console.wicket.markup.html.link;
+
+import org.apache.wicket.markup.html.link.PopupSettings;
+
+public class VeilPopupSettings extends PopupSettings {
+
+    private static final long serialVersionUID = -2727046117490858226L;
+
+    @Override
+    public String getPopupJavaScript() {
+        return "document.getElementById('veil').style.display = 'block';" + 
super.getPopupJavaScript();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/AltListView.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/AltListView.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/AltListView.java
new file mode 100644
index 0000000..5a491ae
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/AltListView.java
@@ -0,0 +1,59 @@
+/*
+ * 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.wicket.markup.html.list;
+
+import java.util.List;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.IModel;
+
+public abstract class AltListView<T> extends ListView<T> {
+
+    private static final long serialVersionUID = 251378224847354710L;
+
+    public AltListView(final String id) {
+        super(id);
+    }
+
+    public AltListView(final String id, final IModel<? extends List<? extends 
T>> model) {
+        super(id, model);
+    }
+
+    public AltListView(final String id, final List<? extends T> list) {
+        super(id, list);
+    }
+
+    @Override
+    protected ListItem<T> newItem(final int index, final IModel<T> itemModel) {
+        return new ListItem<T>(index, itemModel) {
+
+            private static final long serialVersionUID = 5473483270932376694L;
+
+            @Override
+            protected void onComponentTag(final ComponentTag tag) {
+                if (index % 2 == 0) {
+                    tag.append("class", "alt", " ");
+                }
+
+                super.onComponentTag(tag);
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java
new file mode 100644
index 0000000..30775f5
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java
@@ -0,0 +1,152 @@
+/*
+ * 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.wicket.markup.html.list;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxPasswordFieldPanel;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.SpinnerFieldPanel;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.PasswordTextField;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.ClassUtils;
+
+public class ConnConfPropertyListView extends AltListView<ConnConfProperty> {
+
+    private static final long serialVersionUID = -5239334900329150316L;
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ConnConfPropertyListView.class);
+
+    private final boolean withOverridable;
+
+    private final Set<ConnConfProperty> configuration;
+
+    public ConnConfPropertyListView(final String id, final IModel<? extends 
List<? extends ConnConfProperty>> model,
+            final boolean withOverridable, final Set<ConnConfProperty> 
configuration) {
+
+        super(id, model);
+        this.configuration = configuration;
+        this.withOverridable = withOverridable;
+    }
+
+    @Override
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected void populateItem(final ListItem<ConnConfProperty> item) {
+        final ConnConfProperty property = item.getModelObject();
+
+        final Label label = new Label("connPropAttrSchema",
+                StringUtils.isBlank(property.getSchema().getDisplayName())
+                        ? property.getSchema().getName()
+                        : property.getSchema().getDisplayName());
+        item.add(label);
+
+        FieldPanel<? extends Serializable> field;
+        boolean required = false;
+        boolean isArray = false;
+
+        if (property.getSchema().isConfidential()
+                || 
Constants.GUARDED_STRING.equalsIgnoreCase(property.getSchema().getType())
+                || 
Constants.GUARDED_BYTE_ARRAY.equalsIgnoreCase(property.getSchema().getType())) {
+
+            field = new AjaxPasswordFieldPanel("panel",
+                    label.getDefaultModelObjectAsString(), new 
Model<String>());
+            ((PasswordTextField) field.getField()).setResetPassword(false);
+
+            required = property.getSchema().isRequired();
+        } else {
+            Class<?> propertySchemaClass;
+            try {
+                propertySchemaClass =
+                        ClassUtils.forName(property.getSchema().getType(), 
ClassUtils.getDefaultClassLoader());
+                if (ClassUtils.isPrimitiveOrWrapper(propertySchemaClass)) {
+                    propertySchemaClass = 
org.apache.commons.lang3.ClassUtils.primitiveToWrapper(propertySchemaClass);
+                }
+            } catch (Exception e) {
+                LOG.error("Error parsing attribute type", e);
+                propertySchemaClass = String.class;
+            }
+
+            if (ClassUtils.isAssignable(Number.class, propertySchemaClass)) {
+                @SuppressWarnings("unchecked")
+                final Class<Number> numberClass = (Class<Number>) 
propertySchemaClass;
+                field = new SpinnerFieldPanel<Number>("panel",
+                        label.getDefaultModelObjectAsString(), numberClass, 
new Model<Number>(), null, null);
+
+                required = property.getSchema().isRequired();
+            } else if (ClassUtils.isAssignable(Boolean.class, 
propertySchemaClass)) {
+                field = new AjaxCheckBoxPanel("panel",
+                        label.getDefaultModelObjectAsString(), new 
Model<Boolean>());
+            } else {
+                field = new AjaxTextFieldPanel("panel",
+                        label.getDefaultModelObjectAsString(), new 
Model<String>());
+
+                required = property.getSchema().isRequired();
+            }
+
+            if (propertySchemaClass.isArray()) {
+                isArray = true;
+            }
+        }
+
+        field.setTitle(property.getSchema().getHelpMessage());
+
+        if (required) {
+            field.addRequiredLabel();
+        }
+
+        if (isArray) {
+            if (property.getValues().isEmpty()) {
+                property.getValues().add(null);
+            }
+
+            final MultiFieldPanel multiFieldPanel = new 
MultiFieldPanel("panel",
+                    new PropertyModel<List<String>>(property, "values"), 
field);
+            item.add(multiFieldPanel);
+        } else {
+            setNewFieldModel(field, property.getValues());
+            item.add(field);
+        }
+
+        if (withOverridable) {
+            item.add(new AjaxCheckBoxPanel("connPropAttrOverridable",
+                    "connPropAttrOverridable", new 
PropertyModel<Boolean>(property, "overridable")));
+        }
+
+        configuration.add(property);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private void setNewFieldModel(final FieldPanel field, final List<Object> 
values) {
+        field.setNewModel(values);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/DefaultMutableTreeNodeExpansion.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/DefaultMutableTreeNodeExpansion.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/DefaultMutableTreeNodeExpansion.java
new file mode 100644
index 0000000..50db23c
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/DefaultMutableTreeNodeExpansion.java
@@ -0,0 +1,160 @@
+/*
+ * 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.wicket.markup.html.tree;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.Session;
+
+public class DefaultMutableTreeNodeExpansion implements 
Set<DefaultMutableTreeNode>, Serializable {
+
+    private static final long serialVersionUID = -2864060875425661224L;
+
+    private static MetaDataKey<DefaultMutableTreeNodeExpansion> KEY =
+            new MetaDataKey<DefaultMutableTreeNodeExpansion>() {
+
+                private static final long serialVersionUID = 
3109256773218160485L;
+
+            };
+
+    private Set<Long> ids = new HashSet<Long>();
+
+    private boolean inverse;
+
+    public void expandAll() {
+        ids.clear();
+
+        inverse = true;
+    }
+
+    public void collapseAll() {
+        ids.clear();
+
+        inverse = false;
+    }
+
+    @Override
+    public boolean add(final DefaultMutableTreeNode node) {
+        RoleTO roleTO = (RoleTO) node.getUserObject();
+        boolean isAdded;
+        if (inverse) {
+            isAdded = ids.remove(roleTO.getKey());
+        } else {
+            isAdded = ids.add(roleTO.getKey());
+        }
+        return isAdded;
+    }
+
+    @Override
+    public boolean remove(final Object object) {
+        DefaultMutableTreeNode node = (DefaultMutableTreeNode) object;
+        RoleTO roleTO = (RoleTO) node.getUserObject();
+        boolean isRemoved;
+        if (inverse) {
+            isRemoved = ids.add(roleTO.getKey());
+        } else {
+            isRemoved = ids.remove(roleTO.getKey());
+        }
+        return isRemoved;
+    }
+
+    @Override
+    public boolean contains(final Object object) {
+        DefaultMutableTreeNode node = (DefaultMutableTreeNode) object;
+        RoleTO roleTO = (RoleTO) node.getUserObject();
+        boolean isContained;
+        if (inverse) {
+            isContained = !ids.contains(roleTO.getKey());
+        } else {
+            isContained = ids.contains(roleTO.getKey());
+        }
+        return isContained;
+    }
+
+    @Override
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int size() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <A> A[] toArray(final A[] a) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Iterator<DefaultMutableTreeNode> iterator() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object[] toArray() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends DefaultMutableTreeNode> c) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Get the expansion for the session.
+     *
+     * @return expansion
+     */
+    public static DefaultMutableTreeNodeExpansion get() {
+        DefaultMutableTreeNodeExpansion expansion = 
Session.get().getMetaData(KEY);
+        if (expansion == null) {
+            expansion = new DefaultMutableTreeNodeExpansion();
+
+            Session.get().setMetaData(KEY, expansion);
+        }
+        return expansion;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/DefaultMutableTreeNodeExpansionModel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/DefaultMutableTreeNodeExpansionModel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/DefaultMutableTreeNodeExpansionModel.java
new file mode 100644
index 0000000..1b342bd
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/DefaultMutableTreeNodeExpansionModel.java
@@ -0,0 +1,36 @@
+/*
+ * 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.wicket.markup.html.tree;
+
+import java.util.Set;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+import org.apache.wicket.model.AbstractReadOnlyModel;
+
+public class DefaultMutableTreeNodeExpansionModel
+        extends AbstractReadOnlyModel<Set<DefaultMutableTreeNode>> {
+
+    private static final long serialVersionUID = -3407581132184748054L;
+
+    @Override
+    public Set<DefaultMutableTreeNode> getObject() {
+        return DefaultMutableTreeNodeExpansion.get();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/TreeRolePanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/TreeRolePanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/TreeRolePanel.java
new file mode 100644
index 0000000..b0be4e9
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/TreeRolePanel.java
@@ -0,0 +1,121 @@
+/*
+ * 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.wicket.markup.html.tree;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.apache.syncope.client.console.commons.RoleTreeBuilder;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.pages.Roles.TreeNodeClickUpdate;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import 
org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import 
org.apache.wicket.extensions.markup.html.repeater.tree.DefaultNestedTree;
+import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
+import org.apache.wicket.extensions.markup.html.repeater.tree.NestedTree;
+import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder;
+import 
org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class TreeRolePanel extends Panel {
+
+    private static final long serialVersionUID = 1762003213871836869L;
+
+    @SpringBean
+    private RoleTreeBuilder roleTreeBuilder;
+
+    @SpringBean
+    private XMLRolesReader xmlRolesReader;
+
+    private WebMarkupContainer treeContainer;
+
+    private NestedTree<DefaultMutableTreeNode> tree;
+
+    public TreeRolePanel(final String id) {
+        super(id);
+
+        treeContainer = new WebMarkupContainer("treeContainer");
+        treeContainer.setOutputMarkupId(true);
+        add(treeContainer);
+        updateTree();
+    }
+
+    private void updateTree() {
+        final ITreeProvider<DefaultMutableTreeNode> treeProvider = new 
TreeRoleProvider(roleTreeBuilder, true);
+        final DefaultMutableTreeNodeExpansionModel treeModel = new 
DefaultMutableTreeNodeExpansionModel();
+
+        tree = new DefaultNestedTree<DefaultMutableTreeNode>("treeTable", 
treeProvider, treeModel) {
+
+            private static final long serialVersionUID = 7137658050662575546L;
+
+            @Override
+            protected Component newContentComponent(final String id, final 
IModel<DefaultMutableTreeNode> node) {
+                final DefaultMutableTreeNode treeNode = node.getObject();
+                final RoleTO roleTO = (RoleTO) treeNode.getUserObject();
+
+                return new Folder<DefaultMutableTreeNode>(id, 
TreeRolePanel.this.tree, node) {
+
+                    private static final long serialVersionUID = 
9046323319920426493L;
+
+                    @Override
+                    protected boolean isClickable() {
+                        return true;
+                    }
+
+                    @Override
+                    protected IModel<?> newLabelModel(final 
IModel<DefaultMutableTreeNode> model) {
+                        return new Model<>(roleTO.getDisplayName());
+                    }
+
+                    @Override
+                    protected void onClick(final AjaxRequestTarget target) {
+                        super.onClick(target);
+
+                        send(getPage(), Broadcast.BREADTH, new 
TreeNodeClickUpdate(target, roleTO.getKey()));
+                    }
+                };
+            }
+        };
+        tree.add(new WindowsTheme());
+        tree.setOutputMarkupId(true);
+
+        DefaultMutableTreeNodeExpansion.get().expandAll();
+
+        MetaDataRoleAuthorizationStrategy.authorize(tree, ENABLE, 
xmlRolesReader.getEntitlement("Roles", "read"));
+
+        treeContainer.addOrReplace(tree);
+    }
+
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        super.onEvent(event);
+
+        if (event.getPayload() instanceof TreeNodeClickUpdate) {
+            final TreeNodeClickUpdate update = (TreeNodeClickUpdate) 
event.getPayload();
+            updateTree();
+            update.getTarget().add(treeContainer);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/TreeRoleProvider.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/TreeRoleProvider.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/TreeRoleProvider.java
new file mode 100644
index 0000000..6fbe9a4
--- /dev/null
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/tree/TreeRoleProvider.java
@@ -0,0 +1,43 @@
+/*
+ * 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.wicket.markup.html.tree;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.apache.syncope.client.console.commons.RoleTreeBuilder;
+import 
org.apache.wicket.extensions.markup.html.repeater.util.TreeModelProvider;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+public class TreeRoleProvider extends 
TreeModelProvider<DefaultMutableTreeNode> {
+
+    private static final long serialVersionUID = -7741964777100892335L;
+
+    public TreeRoleProvider(final RoleTreeBuilder roleTreeBuilder) {
+        this(roleTreeBuilder, false);
+    }
+
+    public TreeRoleProvider(final RoleTreeBuilder roleTreeBuilder, final 
boolean rootVisible) {
+        super(roleTreeBuilder.build(), rootVisible);
+    }
+
+    @Override
+    public IModel<DefaultMutableTreeNode> model(final DefaultMutableTreeNode 
treeNode) {
+        return new Model<DefaultMutableTreeNode>(treeNode);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/resources/META-INF/cxf/org.apache.cxf.Logger
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/resources/META-INF/cxf/org.apache.cxf.Logger 
b/client/console/src/main/resources/META-INF/cxf/org.apache.cxf.Logger
new file mode 100644
index 0000000..6e7bd36
--- /dev/null
+++ b/client/console/src/main/resources/META-INF/cxf/org.apache.cxf.Logger
@@ -0,0 +1 @@
+org.apache.cxf.common.logging.Slf4jLogger

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/resources/META-INF/resources/css/bulk.css
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/META-INF/resources/css/bulk.css 
b/client/console/src/main/resources/META-INF/resources/css/bulk.css
new file mode 100644
index 0000000..1f0e621
--- /dev/null
+++ b/client/console/src/main/resources/META-INF/resources/css/bulk.css
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+th.checkGroupColumn{
+  width: 20px;
+}
+
+td.checkGroupColumn{
+  text-align: center;
+}
+
+div.bulkAction{
+  display:inline-table;
+}
+
+div.bulkActionCell{
+  display: table-cell;
+  vertical-align: middle;
+  text-align: center;
+  width: 40px;
+  padding-left: 7px;
+}
+
+.pageRowElement{
+  display: inline-table;
+  width: 95%;
+}
+
+div#selectedObjects{
+  text-align: center;
+  margin-top: 10px;
+}
+
+div#selectedObjects table {
+  margin: 1em 0;
+  border-collapse: collapse;
+}
+
+div#selectedObjects table td, div#selectedObjects table th {
+  border: 1px solid #eee;
+  padding: .6em 10px;
+}
+
+div#actionRow{
+  height: 30px;
+  overflow: hidden;
+  text-align: left;
+  margin-top: 10px;
+}
+
+div#actions{
+  display: inline-table;
+  height: 30px;
+  overflow: hidden;
+}
+
+div#actions div#actionPanel{
+  display: table-cell;
+  height: 30px;
+  overflow: hidden;
+  cursor: auto;
+  background: none;
+  padding: 0px 10px;
+  vertical-align: middle;
+}
+
+div#actions div#cancelBtmForm{
+  display: table-cell;
+  height: 30px;
+  overflow: hidden;
+  vertical-align: middle;
+  padding-left: 3px;
+}
+
+div#actions div#cancelBtmForm form{
+  padding: 0px;
+  margin: 0px;
+}
+
+div#actions div#cancelBtmForm form input#cancel{
+  padding: 0.6em 1em;
+}

Reply via email to