[SYNCOPE-119] (re)Introducing Roles

Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/18958ba2
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/18958ba2
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/18958ba2

Branch: refs/heads/master
Commit: 18958ba234672741adba9b9fa42a503166b9692a
Parents: 423e4cc
Author: Francesco Chicchiriccò <ilgro...@apache.org>
Authored: Fri Apr 10 15:11:19 2015 +0200
Committer: Francesco Chicchiriccò <ilgro...@apache.org>
Committed: Fri Apr 10 15:11:19 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/common/lib/to/RoleTO.java    |  87 +++++++++++++
 .../syncope/common/lib/types/Entitlement.java   | 103 +++++++++++++++
 .../common/rest/api/service/RoleService.java    |  97 ++++++++++++++
 .../syncope/core/logic/NotificationLogic.java   |  20 +--
 .../apache/syncope/core/logic/RoleLogic.java    | 129 +++++++++++++++++++
 .../core/misc/search/SearchCondConverter.java   |   6 +-
 .../core/persistence/api/dao/RoleDAO.java       |  40 ++++++
 .../core/persistence/api/entity/Role.java       |  43 +++++++
 .../core/persistence/jpa/dao/JPARealmDAO.java   |  11 ++
 .../core/persistence/jpa/dao/JPARoleDAO.java    |  89 +++++++++++++
 .../persistence/jpa/entity/JPAConnInstance.java |   2 +-
 .../jpa/entity/JPAEntityFactory.java            |   3 +
 .../jpa/entity/JPAExternalResource.java         |   2 +-
 .../persistence/jpa/entity/JPANotification.java |   2 +-
 .../core/persistence/jpa/entity/JPARole.java    | 125 ++++++++++++++++++
 .../resources/META-INF/spring-orm-oracle.xml    |   9 ++
 .../resources/META-INF/spring-orm-sqlserver.xml |   9 ++
 .../src/main/resources/META-INF/spring-orm.xml  |   9 ++
 .../src/main/resources/content.xml              |   9 +-
 .../persistence/jpa/entity/EntitlementTest.java |   2 +-
 .../core/persistence/jpa/entity/RoleTest.java   | 109 ++++++++++++++++
 .../persistence/jpa/relationship/RealmTest.java |  60 +++++++++
 .../src/test/resources/content.xml              | 126 ++++++++++--------
 .../provisioning/api/data/RoleDataBinder.java   |  31 +++++
 .../java/data/RoleDataBinderImpl.java           |  96 ++++++++++++++
 .../core/rest/cxf/service/RoleServiceImpl.java  |  67 ++++++++++
 .../fit/core/reference/AbstractITCase.java      |   4 +
 .../syncope/fit/core/reference/RoleITCase.java  | 124 ++++++++++++++++++
 28 files changed, 1344 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
----------------------------------------------------------------------
diff --git 
a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java 
b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
new file mode 100644
index 0000000..f7e46de
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
@@ -0,0 +1,87 @@
+/*
+ * 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.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.Entitlement;
+
+@XmlRootElement(name = "role")
+@XmlType
+public class RoleTO extends AbstractBaseBean {
+
+    private static final long serialVersionUID = 4560822655754800031L;
+
+    private long key;
+
+    private String name;
+
+    private String criteria;
+
+    private final Set<Entitlement> entitlements = 
EnumSet.noneOf(Entitlement.class);
+
+    private final List<String> realms = new ArrayList<>();
+
+    public long getKey() {
+        return key;
+    }
+
+    public void setKey(final long key) {
+        this.key = key;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public String getCriteria() {
+        return criteria;
+    }
+
+    public void setCriteria(final String criteria) {
+        this.criteria = criteria;
+    }
+
+    @XmlElementWrapper(name = "entitlements")
+    @XmlElement(name = "entitlement")
+    @JsonProperty("entitlements")
+    public Set<Entitlement> getEntitlements() {
+        return entitlements;
+    }
+
+    @XmlElementWrapper(name = "realms")
+    @XmlElement(name = "realm")
+    @JsonProperty("realms")
+    public List<String> getRealms() {
+        return realms;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java
----------------------------------------------------------------------
diff --git 
a/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java 
b/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java
new file mode 100644
index 0000000..8e40551
--- /dev/null
+++ 
b/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.types;
+
+public enum Entitlement {
+
+    REALM_LIST,
+    REALM_CREATE,
+    REALM_UPDATE,
+    REALM_DELETE,
+    ROLE_LIST,
+    ROLE_CREATE,
+    ROLE_READ,
+    ROLE_UPDATE,
+    ROLE_DELETE,
+    SCHEMA_LIST,
+    SCHEMA_CREATE,
+    SCHEMA_READ,
+    SCHEMA_UPDATE,
+    SCHEMA_DELETE,
+    USER_LIST,
+    USER_CREATE,
+    USER_READ,
+    USER_UPDATE,
+    USER_DELETE,
+    USER_VIEW,
+    GROUP_LIST,
+    GROUP_CREATE,
+    GROUP_READ,
+    GROUP_UPDATE,
+    GROUP_DELETE,
+    RESOURCE_LIST,
+    RESOURCE_CREATE,
+    RESOURCE_READ,
+    RESOURCE_UPDATE,
+    RESOURCE_DELETE,
+    RESOURCE_GETCONNECTOROBJECT,
+    CONNECTOR_LIST,
+    CONNECTOR_CREATE,
+    CONNECTOR_READ,
+    CONNECTOR_UPDATE,
+    CONNECTOR_DELETE,
+    CONNECTOR_RELOAD,
+    CONFIGURATION_EXPORT,
+    CONFIGURATION_LIST,
+    CONFIGURATION_SET,
+    CONFIGURATION_DELETE,
+    TASK_LIST,
+    TASK_CREATE,
+    TASK_READ,
+    TASK_UPDATE,
+    TASK_DELETE,
+    TASK_EXECUTE,
+    POLICY_LIST,
+    POLICY_CREATE,
+    POLICY_READ,
+    POLICY_UPDATE,
+    POLICY_DELETE,
+    WORKFLOW_DEF_READ,
+    WORKFLOW_DEF_UPDATE,
+    WORKFLOW_TASK_LIST,
+    WORKFLOW_FORM_LIST,
+    WORKFLOW_FORM_READ,
+    WORKFLOW_FORM_CLAIM,
+    WORKFLOW_FORM_SUBMIT,
+    NOTIFICATION_LIST,
+    NOTIFICATION_CREATE,
+    NOTIFICATION_READ,
+    NOTIFICATION_UPDATE,
+    NOTIFICATION_DELETE,
+    REPORT_LIST,
+    REPORT_READ,
+    REPORT_CREATE,
+    REPORT_UPDATE,
+    REPORT_DELETE,
+    REPORT_EXECUTE,
+    LOG_LIST,
+    LOG_SET_LEVEL,
+    LOG_DELETE,
+    AUDIT_LIST,
+    AUDIT_ENABLE,
+    AUDIT_DISABLE,
+    SECURITY_QUESTION_CREATE,
+    SECURITY_QUESTION_UPDATE,
+    SECURITY_QUESTION_DELETE;
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
----------------------------------------------------------------------
diff --git 
a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
 
b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
new file mode 100644
index 0000000..172af5f
--- /dev/null
+++ 
b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
@@ -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.
+ */
+package org.apache.syncope.common.rest.api.service;
+
+import java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.lib.to.RoleTO;
+
+/**
+ * REST operations for roles.
+ */
+@Path("roles")
+public interface RoleService extends JAXRSService {
+
+    /**
+     * Returns a list of all roles.
+     *
+     * @return list of all roles.
+     */
+    @GET
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    List<RoleTO> list();
+
+    /**
+     * Returns role with matching id.
+     *
+     * @param roleKey role id to be read
+     * @return role with matching id
+     */
+    @GET
+    @Path("{roleKey}")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    RoleTO read(@NotNull @PathParam("roleKey") Long roleKey);
+
+    /**
+     * Creates a new role.
+     *
+     * @param roleTO role to be created
+     * @return <tt>Response</tt> object featuring <tt>Location</tt> header of 
created role
+     */
+    @Descriptions({
+        @Description(target = DocTarget.RESPONSE,
+                value = "Featuring <tt>Location</tt> header of created role")
+    })
+    @POST
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    Response create(@NotNull RoleTO roleTO);
+
+    /**
+     * Updates the role matching the provided id.
+     *
+     * @param roleKey role id to be updated
+     * @param roleTO role to be stored
+     */
+    @PUT
+    @Path("{roleKey}")
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    void update(@NotNull @PathParam("roleKey") Long roleKey, @NotNull RoleTO 
roleTO);
+
+    /**
+     * Deletes the role matching the provided id.
+     *
+     * @param roleKey role id to be deleted
+     */
+    @DELETE
+    @Path("{roleKey}")
+    void delete(@NotNull @PathParam("roleKey") Long roleKey);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java
----------------------------------------------------------------------
diff --git 
a/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java 
b/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java
index 8b8c387..c7ad949 100644
--- 
a/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java
+++ 
b/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java
@@ -43,12 +43,12 @@ public class NotificationLogic extends 
AbstractTransactionalLogic<NotificationTO
     private NotificationDataBinder binder;
 
     @PreAuthorize("hasRole('NOTIFICATION_READ')")
-    public NotificationTO read(final Long notificationId) {
-        Notification notification = notificationDAO.find(notificationId);
+    public NotificationTO read(final Long notificationKey) {
+        Notification notification = notificationDAO.find(notificationKey);
         if (notification == null) {
-            LOG.error("Could not find notification '" + notificationId + "'");
+            LOG.error("Could not find notification '" + notificationKey + "'");
 
-            throw new NotFoundException(String.valueOf(notificationId));
+            throw new NotFoundException(String.valueOf(notificationKey));
         }
 
         return binder.getNotificationTO(notification);
@@ -84,17 +84,17 @@ public class NotificationLogic extends 
AbstractTransactionalLogic<NotificationTO
         return binder.getNotificationTO(notification);
     }
 
-    @PreAuthorize("hasRole('CONNECTOR_DELETE')")
-    public NotificationTO delete(final Long notificationId) {
-        Notification notification = notificationDAO.find(notificationId);
+    @PreAuthorize("hasRole('NOTIFICATION_DELETE')")
+    public NotificationTO delete(final Long notificationKey) {
+        Notification notification = notificationDAO.find(notificationKey);
         if (notification == null) {
-            LOG.error("Could not find notification '" + notificationId + "'");
+            LOG.error("Could not find notification '" + notificationKey + "'");
 
-            throw new NotFoundException(String.valueOf(notificationId));
+            throw new NotFoundException(String.valueOf(notificationKey));
         }
 
         NotificationTO deleted = binder.getNotificationTO(notification);
-        notificationDAO.delete(notificationId);
+        notificationDAO.delete(notificationKey);
         return deleted;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
----------------------------------------------------------------------
diff --git 
a/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java 
b/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
new file mode 100644
index 0000000..668d263
--- /dev/null
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
+import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.provisioning.api.data.RoleDataBinder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RoleLogic extends AbstractTransactionalLogic<RoleTO> {
+
+    @Autowired
+    private RoleDataBinder binder;
+
+    @Autowired
+    private RoleDAO roleDAO;
+
+    @PreAuthorize("hasRole('ROLE_READ')")
+    public RoleTO read(final Long roleKey) {
+        Role role = roleDAO.find(roleKey);
+        if (role == null) {
+            LOG.error("Could not find role '" + roleKey + "'");
+
+            throw new NotFoundException(String.valueOf(roleKey));
+        }
+
+        return binder.getRoleTO(role);
+    }
+
+    @PreAuthorize("hasRole('ROLE_LIST')")
+    public List<RoleTO> list() {
+        return CollectionUtils.collect(roleDAO.findAll(), new 
Transformer<Role, RoleTO>() {
+
+            @Override
+            public RoleTO transform(final Role input) {
+                return binder.getRoleTO(input);
+            }
+        }, new ArrayList<RoleTO>());
+    }
+
+    @PreAuthorize("hasRole('ROLE_CREATE')")
+    public RoleTO create(final RoleTO roleTO) {
+        return binder.getRoleTO(roleDAO.save(binder.create(roleTO)));
+    }
+
+    @PreAuthorize("hasRole('ROLE_UPDATE')")
+    public RoleTO update(final RoleTO roleTO) {
+        Role role = roleDAO.find(roleTO.getKey());
+        if (role == null) {
+            LOG.error("Could not find role '" + roleTO.getKey() + "'");
+            throw new NotFoundException(String.valueOf(roleTO.getKey()));
+        }
+
+        binder.update(role, roleTO);
+        role = roleDAO.save(role);
+
+        return binder.getRoleTO(role);
+    }
+
+    @PreAuthorize("hasRole('ROLE_DELETE')")
+    public RoleTO delete(final Long roleKey) {
+        Role role = roleDAO.find(roleKey);
+        if (role == null) {
+            LOG.error("Could not find role '" + roleKey + "'");
+
+            throw new NotFoundException(String.valueOf(roleKey));
+        }
+
+        RoleTO deleted = binder.getRoleTO(role);
+        roleDAO.delete(roleKey);
+        return deleted;
+    }
+
+    @Override
+    protected RoleTO resolveReference(final Method method, final Object... 
args)
+            throws UnresolvedReferenceException {
+
+        Long key = null;
+
+        if (ArrayUtils.isNotEmpty(args)) {
+            for (int i = 0; key == null && i < args.length; i++) {
+                if (args[i] instanceof Long) {
+                    key = (Long) args[i];
+                } else if (args[i] instanceof RoleTO) {
+                    key = ((RoleTO) args[i]).getKey();
+                }
+            }
+        }
+
+        if ((key != null) && !key.equals(0L)) {
+            try {
+                return binder.getRoleTO(roleDAO.find(key));
+            } catch (Throwable ignore) {
+                LOG.debug("Unresolved reference", ignore);
+                throw new UnresolvedReferenceException(ignore);
+            }
+        }
+
+        throw new UnresolvedReferenceException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
----------------------------------------------------------------------
diff --git 
a/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
 
b/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
index e6756ad..684592c 100644
--- 
a/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
+++ 
b/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
@@ -24,7 +24,7 @@ import 
org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 
 /**
- * Converts FIQL expressions to Syncope's <tt>SearchCond</tt>.
+ * Converts FIQL expressions to Syncope's {@link SearchCond}.
  */
 public final class SearchCondConverter {
 
@@ -36,10 +36,10 @@ public final class SearchCondConverter {
      * @see FiqlParser
      */
     public static SearchCond convert(final String fiqlExpression) {
-        FiqlParser<SearchBean> fiqlParser = new FiqlParser<SearchBean>(
+        FiqlParser<SearchBean> fiqlParser = new FiqlParser<>(
                 SearchBean.class, 
AbstractFiqlSearchConditionBuilder.CONTEXTUAL_PROPERTIES);
-        SearchCondVisitor searchCondVisitor = new SearchCondVisitor();
 
+        SearchCondVisitor searchCondVisitor = new SearchCondVisitor();
         searchCondVisitor.visit(fiqlParser.parse(fiqlExpression));
         return searchCondVisitor.getQuery();
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java
 
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java
new file mode 100644
index 0000000..76723b0
--- /dev/null
+++ 
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.dao;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.Role;
+
+public interface RoleDAO extends DAO<Role, Long> {
+
+    Role find(Long key);
+
+    Role find(String name);
+
+    List<Role> findByRealm(Realm realm);
+
+    List<Role> findAll();
+
+    Role save(Role role);
+
+    void delete(Role role);
+
+    void delete(Long key);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
 
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
new file mode 100644
index 0000000..7753ee2
--- /dev/null
+++ 
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.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.core.persistence.api.entity;
+
+import java.util.List;
+import java.util.Set;
+import org.apache.syncope.common.lib.types.Entitlement;
+
+public interface Role extends Entity<Long> {
+
+    String getName();
+
+    void setName(String name);
+
+    String getCriteria();
+
+    void setCriteria(String criteria);
+
+    Set<Entitlement> getEntitlements();
+
+    boolean addRealm(Realm realm);
+
+    boolean removeReam(Realm realm);
+
+    List<? extends Realm> getRealms();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
index 896277c..0921d8c 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARealmDAO.java
@@ -27,8 +27,11 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.core.persistence.api.dao.MalformedPathException;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.jpa.entity.JPARealm;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 
 @Repository
@@ -36,6 +39,9 @@ public class JPARealmDAO extends AbstractDAO<Realm, Long> 
implements RealmDAO {
 
     private static final Pattern PATH_PATTERN = 
Pattern.compile("^(/[A-Za-z0-9]+)+");
 
+    @Autowired
+    private RoleDAO roleDAO;
+
     @Override
     public Realm getRoot() {
         TypedQuery<Realm> query = entityManager.createQuery(
@@ -128,7 +134,12 @@ public class JPARealmDAO extends AbstractDAO<Realm, Long> 
implements RealmDAO {
     @Override
     public void delete(final Realm realm) {
         for (Realm toBeDeleted : findDescendants(realm)) {
+            for (Role role : roleDAO.findByRealm(toBeDeleted)) {
+                role.getRealms().remove(toBeDeleted);
+            }
+
             toBeDeleted.setParent(null);
+
             entityManager.remove(toBeDeleted);
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
new file mode 100644
index 0000000..f240850
--- /dev/null
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.List;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.jpa.entity.JPARole;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class JPARoleDAO extends AbstractDAO<Role, Long> implements RoleDAO {
+
+    @Override
+    public Role find(final Long key) {
+        return entityManager.find(JPARole.class, key);
+    }
+
+    @Override
+    public Role find(final String name) {
+        TypedQuery<Role> query = entityManager.createQuery(
+                "SELECT e FROM " + JPARole.class.getSimpleName() + " e WHERE 
e.name=:name", Role.class);
+        query.setParameter("name", name);
+
+        Role result = null;
+        try {
+            result = query.getSingleResult();
+        } catch (NoResultException e) {
+            LOG.debug("Found more than one match", e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public List<Role> findByRealm(final Realm realm) {
+        TypedQuery<Role> query = entityManager.createQuery(
+                "SELECT e FROM " + JPARole.class.getSimpleName() + " e WHERE 
:realm MEMBER OF e.realms", Role.class);
+        query.setParameter("realm", realm);
+        return query.getResultList();
+    }
+
+    @Override
+    public List<Role> findAll() {
+        TypedQuery<Role> query = entityManager.createQuery(
+                "SELECT e FROM " + JPARole.class.getSimpleName() + " e ", 
Role.class);
+        return query.getResultList();
+    }
+
+    @Override
+    public Role save(final Role role) {
+        return entityManager.merge(role);
+    }
+
+    @Override
+    public void delete(final Role role) {
+        entityManager.remove(role);
+    }
+
+    @Override
+    public void delete(final Long key) {
+        Role role = find(key);
+        if (role == null) {
+            return;
+        }
+
+        delete(role);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
index 6abedd5..746bf48 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
@@ -94,7 +94,7 @@ public class JPAConnInstance extends AbstractEntity<Long> 
implements ConnInstanc
      */
     @ElementCollection(fetch = FetchType.EAGER)
     @Enumerated(EnumType.STRING)
-    @Column(name = "capabilities")
+    @Column(name = "capability")
     @CollectionTable(name = "ConnInstance_capabilities",
             joinColumns =
             @JoinColumn(name = "ConnInstance_id", referencedColumnName = "id"))

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
index a4cadf4..4d83b7c 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
@@ -34,6 +34,7 @@ import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Report;
 import org.apache.syncope.core.persistence.api.entity.ReportExec;
 import org.apache.syncope.core.persistence.api.entity.ReportletConfInstance;
+import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.api.entity.SyncPolicy;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
 import 
org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrUniqueValue;
@@ -144,6 +145,8 @@ public class JPAEntityFactory implements EntityFactory {
 
         if (reference.equals(Realm.class)) {
             result = (T) new JPARealm();
+        } else if (reference.equals(Role.class)) {
+            result = (T) new JPARole();
         } else if (reference.equals(User.class)) {
             result = (T) new JPAUser();
         } else if (reference.equals(Group.class)) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAExternalResource.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAExternalResource.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAExternalResource.java
index 908422b..2f28485 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAExternalResource.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAExternalResource.java
@@ -179,7 +179,7 @@ public class JPAExternalResource extends 
AbstractAnnotatedEntity<String> impleme
      * (Optional) classes for PropagationAction.
      */
     @ElementCollection(fetch = FetchType.EAGER)
-    @Column(name = "action")
+    @Column(name = "actionClassName")
     @CollectionTable(name = "ExternalResource_PropActions",
             joinColumns =
             @JoinColumn(name = "ExternalResource_name", referencedColumnName = 
"name"))

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
index d2acd58..498032e 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
@@ -53,10 +53,10 @@ public class JPANotification extends AbstractEntity<Long> 
implements Notificatio
     private Long id;
 
     @ElementCollection(fetch = FetchType.EAGER)
+    @Column(name = "event")
     @CollectionTable(name = "Notification_events",
             joinColumns =
             @JoinColumn(name = "Notification_id", referencedColumnName = "id"))
-    @Column(name = "events")
     private List<String> events;
 
     private String userAbout;

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
new file mode 100644
index 0000000..3d7ac29
--- /dev/null
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.persistence.Cacheable;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.Role;
+
+@Entity
+@Table(name = JPARole.TABLE)
+@Cacheable
+public class JPARole extends AbstractEntity<Long> implements Role {
+
+    private static final long serialVersionUID = -7657701119422588832L;
+
+    public static final String TABLE = "SyncopeRole";
+
+    @Id
+    private Long id;
+
+    @Column(unique = true)
+    @NotNull
+    private String name;
+
+    @ElementCollection(fetch = FetchType.EAGER)
+    @Enumerated(EnumType.STRING)
+    @Column(name = "entitlement")
+    @CollectionTable(name = "SyncopeRole_entitlements",
+            joinColumns =
+            @JoinColumn(name = "role_id", referencedColumnName = "id"))
+    private Set<Entitlement> entitlements = new HashSet<>();
+
+    @ManyToMany(fetch = FetchType.EAGER)
+    @JoinTable(joinColumns =
+            @JoinColumn(name = "role_id"),
+            inverseJoinColumns =
+            @JoinColumn(name = "realm_id"))
+    @Valid
+    private List<JPARealm> realms = new ArrayList<>();
+
+    private String criteria;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getCriteria() {
+        return criteria;
+    }
+
+    @Override
+    public void setCriteria(final String criteria) {
+        this.criteria = criteria;
+    }
+
+    @Override
+    public Set<Entitlement> getEntitlements() {
+        return entitlements;
+    }
+
+    @Override
+    public boolean addRealm(final Realm realm) {
+        checkType(realm, JPARealm.class);
+        return realms.add((JPARealm) realm);
+    }
+
+    @Override
+    public boolean removeReam(final Realm realm) {
+        checkType(realm, JPARealm.class);
+        return realms.remove((JPARealm) realm);
+    }
+
+    @Override
+    public List<? extends Realm> getRealms() {
+        return realms;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml 
b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
index ea3a058..3a61895 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
@@ -48,6 +48,15 @@ under the License.
     </attributes>
   </entity>
   
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPARole">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_Role" strategy="TABLE"/>
+        <table-generator name="SEQ_Role" pk-column-value="SEQ_Role" 
initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+
   <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUser">
     <attributes>
       <id name="id">

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml 
b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
index ea3a058..97af974 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
@@ -48,6 +48,15 @@ under the License.
     </attributes>
   </entity>
   
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPARole">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_Role" strategy="TABLE"/>
+        <table-generator name="SEQ_Role" pk-column-value="SEQ_Role" 
initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+  
   <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUser">
     <attributes>
       <id name="id">

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml 
b/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
index e26f6d0..5921b94 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
@@ -48,6 +48,15 @@ under the License.
     </attributes>
   </entity>
 
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPARole">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_Role" strategy="TABLE"/>
+        <table-generator name="SEQ_Role" pk-column-value="SEQ_Role" 
initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+
   <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUser">
     <attributes>
       <id name="id">

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/main/resources/content.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/content.xml 
b/core/persistence-jpa/src/main/resources/content.xml
index e060c62..6b6c287 100644
--- a/core/persistence-jpa/src/main/resources/content.xml
+++ b/core/persistence-jpa/src/main/resources/content.xml
@@ -103,18 +103,23 @@ under the License.
   <Notification id="1" active="1" recipientAttrName="email" 
recipientAttrType="UserPlainSchema" selfAsRecipient="1" 
                 sender="ad...@syncope.apache.org" subject="Password Reset 
request" template="requestPasswordReset" 
                 traceLevel="FAILURES" userAbout="token!=$null"/> 
-  <Notification_events Notification_id="1" 
events="[CUSTOM]:[]:[]:[requestPasswordReset]:[SUCCESS]"/>
+  <Notification_events Notification_id="1" 
event="[CUSTOM]:[]:[]:[requestPasswordReset]:[SUCCESS]"/>
   
   <Notification id="2" active="1" recipientAttrName="email" 
recipientAttrType="UserPlainSchema" selfAsRecipient="1" 
                 sender="ad...@syncope.apache.org" subject="Password Reset 
successful" template="confirmPasswordReset" 
                 traceLevel="FAILURES" userAbout="token!=$null"/> 
-  <Notification_events Notification_id="2" 
events="[CUSTOM]:[]:[]:[confirmPasswordReset]:[SUCCESS]"/>  
+  <Notification_events Notification_id="2" 
event="[CUSTOM]:[]:[]:[confirmPasswordReset]:[SUCCESS]"/>  
   
   <!-- Authentication and authorization -->
   <Entitlement name="REALM_LIST"/>
   <Entitlement name="REALM_CREATE"/>
   <Entitlement name="REALM_UPDATE"/>
   <Entitlement name="REALM_DELETE"/>
+  <Entitlement name="ROLE_LIST"/>
+  <Entitlement name="ROLE_CREATE"/>
+  <Entitlement name="ROLE_READ"/>
+  <Entitlement name="ROLE_UPDATE"/>
+  <Entitlement name="ROLE_DELETE"/>
   <Entitlement name="SCHEMA_LIST"/>
   <Entitlement name="SCHEMA_CREATE"/>
   <Entitlement name="SCHEMA_READ"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/EntitlementTest.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/EntitlementTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/EntitlementTest.java
index ccea7da..82fa875 100644
--- 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/EntitlementTest.java
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/EntitlementTest.java
@@ -39,7 +39,7 @@ public class EntitlementTest extends AbstractTest {
     @Test
     public void findAll() {
         List<Entitlement> list = entitlementDAO.findAll();
-        assertEquals("did not get expected number of entitlements ", 90, 
list.size());
+        assertEquals("did not get expected number of entitlements ", 95, 
list.size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java
new file mode 100644
index 0000000..b4830cf
--- /dev/null
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java
@@ -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.core.persistence.jpa.entity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.common.lib.search.UserFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.core.misc.search.SearchCondConverter;
+import org.apache.syncope.core.persistence.api.GroupEntitlementUtil;
+import org.apache.syncope.core.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
+import org.apache.syncope.core.persistence.api.dao.SubjectSearchDAO;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+public class RoleTest extends AbstractTest {
+
+    @Autowired
+    private RoleDAO roleDAO;
+
+    @Autowired
+    private EntitlementDAO entitlementDAO;
+
+    @Autowired
+    private SubjectSearchDAO searchDAO;
+
+    @Autowired
+    private RealmDAO realmDAO;
+
+    @Test
+    public void find() {
+        Role role1 = roleDAO.find(2L);
+        assertNotNull(role1);
+        assertNotNull(role1.getName());
+        assertFalse(searchDAO.<User>search(
+                GroupEntitlementUtil.getGroupKeys(entitlementDAO.findAll()),
+                SearchCondConverter.convert(role1.getCriteria()),
+                Collections.<OrderByClause>emptyList(), 
SubjectType.USER).isEmpty());
+        assertFalse(role1.getRealms().isEmpty());
+        assertFalse(role1.getEntitlements().isEmpty());
+        assertTrue(role1.getEntitlements().contains(Entitlement.USER_LIST));
+
+        Role role2 = roleDAO.find(role1.getName());
+        assertEquals(role1, role2);
+    }
+
+    @Test
+    public void findAll() {
+        List<Role> list = roleDAO.findAll();
+        assertNotNull(list);
+        assertFalse(list.isEmpty());
+        for (Role role : list) {
+            assertNotNull(role);
+        }
+    }
+
+    @Test
+    public void save() {
+        Role role = entityFactory.newEntity(Role.class);
+        role.setName("new");
+        role.setCriteria(new 
UserFiqlSearchConditionBuilder().inGroups(2L).query());
+        role.addRealm(realmDAO.getRoot());
+        role.addRealm(realmDAO.find("/even/two"));
+        role.getEntitlements().add(Entitlement.LOG_LIST);
+        role.getEntitlements().add(Entitlement.LOG_SET_LEVEL);
+
+        Role actual = roleDAO.save(role);
+        assertNotNull(actual);
+    }
+
+    @Test
+    public void delete() {
+        assertNotNull(roleDAO.find(3L));
+
+        roleDAO.delete(3L);
+        assertNull(roleDAO.find(3L));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/18958ba2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/RealmTest.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/RealmTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/RealmTest.java
new file mode 100644
index 0000000..e652e62
--- /dev/null
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/RealmTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.relationship;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+public class RealmTest extends AbstractTest {
+
+    @Autowired
+    private RealmDAO realmDAO;
+
+    @Autowired
+    private RoleDAO roleDAO;
+
+    @Test
+    public void test() {
+        Realm realm = realmDAO.find("/odd");
+        assertNotNull(realm);
+
+        Role role = roleDAO.find(1L);
+        assertTrue(role.getRealms().contains(realm));
+
+        int beforeSize = role.getRealms().size();
+
+        realmDAO.delete(realm);
+
+        realmDAO.flush();
+
+        role = roleDAO.find(1L);
+        assertEquals(beforeSize - 1, role.getRealms().size());
+    }
+}

Reply via email to