001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryPos;
018    import com.liferay.portal.kernel.dao.orm.SQLQuery;
019    import com.liferay.portal.kernel.dao.orm.Session;
020    import com.liferay.portal.kernel.dao.orm.Type;
021    import com.liferay.portal.kernel.exception.NoSuchResourcePermissionException;
022    import com.liferay.portal.kernel.exception.PortalException;
023    import com.liferay.portal.kernel.exception.SystemException;
024    import com.liferay.portal.kernel.model.Resource;
025    import com.liferay.portal.kernel.model.ResourceAction;
026    import com.liferay.portal.kernel.model.ResourceConstants;
027    import com.liferay.portal.kernel.model.ResourcePermission;
028    import com.liferay.portal.kernel.model.ResourcePermissionConstants;
029    import com.liferay.portal.kernel.model.Role;
030    import com.liferay.portal.kernel.model.RoleConstants;
031    import com.liferay.portal.kernel.search.IndexWriterHelperUtil;
032    import com.liferay.portal.kernel.security.auth.PrincipalException;
033    import com.liferay.portal.kernel.security.permission.PermissionThreadLocal;
034    import com.liferay.portal.kernel.security.permission.PermissionUpdateHandler;
035    import com.liferay.portal.kernel.security.permission.PermissionUpdateHandlerRegistryUtil;
036    import com.liferay.portal.kernel.security.permission.ResourceActionsUtil;
037    import com.liferay.portal.kernel.service.ExceptionRetryAcceptor;
038    import com.liferay.portal.kernel.spring.aop.Property;
039    import com.liferay.portal.kernel.spring.aop.Retry;
040    import com.liferay.portal.kernel.transaction.TransactionCommitCallbackUtil;
041    import com.liferay.portal.kernel.util.ArrayUtil;
042    import com.liferay.portal.kernel.util.GetterUtil;
043    import com.liferay.portal.kernel.util.ListUtil;
044    import com.liferay.portal.kernel.util.StringBundler;
045    import com.liferay.portal.kernel.util.StringUtil;
046    import com.liferay.portal.security.permission.PermissionCacheUtil;
047    import com.liferay.portal.service.base.ResourcePermissionLocalServiceBaseImpl;
048    import com.liferay.portal.util.PropsValues;
049    import com.liferay.portal.util.ResourcePermissionsThreadLocal;
050    import com.liferay.util.dao.orm.CustomSQLUtil;
051    
052    import java.util.ArrayList;
053    import java.util.Collection;
054    import java.util.Collections;
055    import java.util.HashMap;
056    import java.util.HashSet;
057    import java.util.List;
058    import java.util.Map;
059    import java.util.Set;
060    import java.util.concurrent.Callable;
061    
062    /**
063     * Provides the local service for accessing, adding, checking, deleting,
064     * granting, and revoking resource permissions.
065     *
066     * <p>
067     * Before attempting to read any of the documentation for this class, first read
068     * {@link com.liferay.portal.model.impl.ResourcePermissionImpl} for an
069     * explanation of scoping.
070     * </p>
071     *
072     * @author Brian Wing Shun Chan
073     * @author Raymond Aug??
074     * @author Connor McKay
075     */
076    public class ResourcePermissionLocalServiceImpl
077            extends ResourcePermissionLocalServiceBaseImpl {
078    
079            /**
080             * @see com.liferay.portal.verify.VerifyPermission#fixOrganizationRolePermissions
081             */
082            public static final String[] EMPTY_ACTION_IDS = {null};
083    
084            /**
085             * Grants the role permission at the scope to perform the action on
086             * resources of the type. Existing actions are retained.
087             *
088             * <p>
089             * This method cannot be used to grant individual scope permissions, but is
090             * only intended for adding permissions at the company, group, and
091             * group-template scopes. For example, this method could be used to grant a
092             * company scope permission to edit message board posts.
093             * </p>
094             *
095             * <p>
096             * If a company scope permission is granted to resources that the role
097             * already had group scope permissions to, the group scope permissions are
098             * deleted. Likewise, if a group scope permission is granted to resources
099             * that the role already had company scope permissions to, the company scope
100             * permissions are deleted. Be aware that this latter behavior can result in
101             * an overall reduction in permissions for the role.
102             * </p>
103             *
104             * <p>
105             * Depending on the scope, the value of <code>primKey</code> will have
106             * different meanings. For more information, see {@link
107             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
108             * </p>
109             *
110             * @param companyId the primary key of the company
111             * @param name the resource's name, which can be either a class name or a
112             *        portlet ID
113             * @param scope the scope. This method only supports company, group, and
114             *        group-template scope.
115             * @param primKey the primary key
116             * @param roleId the primary key of the role
117             * @param actionId the action ID
118             */
119            @Override
120            @Retry(
121                    acceptor = ExceptionRetryAcceptor.class,
122                    properties = {
123                            @Property(
124                                    name = ExceptionRetryAcceptor.EXCEPTION_NAME,
125                                    value =
126                                            "org.springframework.dao.DataIntegrityViolationException"
127                            )
128                    }
129            )
130            public void addResourcePermission(
131                            long companyId, String name, int scope, String primKey, long roleId,
132                            String actionId)
133                    throws PortalException {
134    
135                    if (scope == ResourceConstants.SCOPE_COMPANY) {
136    
137                            // Remove group permission
138    
139                            removeResourcePermissions(
140                                    companyId, name, ResourceConstants.SCOPE_GROUP, roleId,
141                                    actionId);
142                    }
143                    else if (scope == ResourceConstants.SCOPE_GROUP) {
144    
145                            // Remove company permission
146    
147                            removeResourcePermissions(
148                                    companyId, name, ResourceConstants.SCOPE_COMPANY, roleId,
149                                    actionId);
150                    }
151                    else if (scope == ResourceConstants.SCOPE_INDIVIDUAL) {
152                            throw new NoSuchResourcePermissionException();
153                    }
154    
155                    updateResourcePermission(
156                            companyId, name, scope, primKey, roleId, 0, new String[] {actionId},
157                            ResourcePermissionConstants.OPERATOR_ADD);
158            }
159    
160            /**
161             * Grants the role permissions at the scope to perform the actions on all
162             * resources of the type. Existing actions are retained.
163             *
164             * <p>
165             * This method should only be used to add default permissions to existing
166             * resources en masse during upgrades or while verifying permissions. For
167             * example, this method could be used to grant site members individual scope
168             * permissions to view all blog posts.
169             * </p>
170             *
171             * @param resourceName the resource's name, which can be either a class name
172             *        or a portlet ID
173             * @param roleName the role's name
174             * @param scope the scope
175             * @param resourceActionBitwiseValue the bitwise IDs of the actions
176             */
177            @Override
178            public void addResourcePermissions(
179                    String resourceName, String roleName, int scope,
180                    long resourceActionBitwiseValue) {
181    
182                    List<Role> roles = rolePersistence.findByName(roleName);
183    
184                    if (roles.isEmpty()) {
185                            return;
186                    }
187    
188                    Session session = resourcePermissionPersistence.openSession();
189    
190                    try {
191    
192                            // Update existing resource permissions
193    
194                            String sql = CustomSQLUtil.get(_UPDATE_ACTION_IDS);
195    
196                            sql = StringUtil.replace(
197                                    sql, "[$ROLE_ID$]",
198                                    ListUtil.toString(roles, Role.ROLE_ID_ACCESSOR));
199    
200                            SQLQuery sqlQuery = session.createSynchronizedSQLQuery(sql);
201    
202                            QueryPos qPos = QueryPos.getInstance(sqlQuery);
203    
204                            qPos.add(resourceActionBitwiseValue);
205                            qPos.add(resourceActionBitwiseValue);
206                            qPos.add(resourceName);
207                            qPos.add(scope);
208    
209                            sqlQuery.executeUpdate();
210    
211                            // Add missing resource permissions
212    
213                            sql = CustomSQLUtil.get(_FIND_MISSING_RESOURCE_PERMISSIONS);
214    
215                            sqlQuery = session.createSynchronizedSQLQuery(sql);
216    
217                            sqlQuery.addScalar("companyId", Type.LONG);
218                            sqlQuery.addScalar("name", Type.STRING);
219                            sqlQuery.addScalar("scope", Type.INTEGER);
220                            sqlQuery.addScalar("primKey", Type.STRING);
221                            sqlQuery.addScalar("roleId", Type.LONG);
222    
223                            qPos = QueryPos.getInstance(sqlQuery);
224    
225                            qPos.add(resourceName);
226                            qPos.add(scope);
227                            qPos.add(roleName);
228    
229                            List<Object[]> resourcePermissionArrays = sqlQuery.list(true);
230    
231                            if (resourcePermissionArrays.isEmpty()) {
232                                    return;
233                            }
234    
235                            for (Object[] resourcePermissionArray : resourcePermissionArrays) {
236                                    long resourcePermissionId = counterLocalService.increment(
237                                            ResourcePermission.class.getName());
238    
239                                    ResourcePermission resourcePermission =
240                                            resourcePermissionPersistence.create(resourcePermissionId);
241    
242                                    resourcePermission.setCompanyId(
243                                            (Long)resourcePermissionArray[0]);
244                                    resourcePermission.setName((String)resourcePermissionArray[1]);
245                                    resourcePermission.setScope(
246                                            (Integer)resourcePermissionArray[2]);
247    
248                                    String primKey = (String)resourcePermissionArray[3];
249    
250                                    resourcePermission.setPrimKey(primKey);
251                                    resourcePermission.setPrimKeyId(GetterUtil.getLong(primKey));
252    
253                                    resourcePermission.setRoleId((Long)resourcePermissionArray[4]);
254                                    resourcePermission.setActionIds(resourceActionBitwiseValue);
255                                    resourcePermission.setViewActionId(
256                                            resourceActionBitwiseValue % 2 == 1);
257    
258                                    session.save(resourcePermission);
259    
260                                    PermissionCacheUtil.clearResourcePermissionCache(
261                                            resourcePermission.getScope(), resourcePermission.getName(),
262                                            resourcePermission.getPrimKey());
263                            }
264                    }
265                    catch (Exception e) {
266                            throw new SystemException(e);
267                    }
268                    finally {
269                            resourcePermissionPersistence.closeSession(session);
270    
271                            resourcePermissionPersistence.clearCache();
272                    }
273            }
274    
275            /**
276             * Deletes all resource permissions at the scope to resources of the type.
277             * This method should not be confused with any of the
278             * <code>removeResourcePermission</code> methods, as its purpose is very
279             * different. This method should only be used for deleting resource
280             * permissions that refer to a resource when that resource is deleted. For
281             * example this method could be used to delete all individual scope
282             * permissions to a blog post when it is deleted.
283             *
284             * <p>
285             * Depending on the scope, the value of <code>primKey</code> will have
286             * different meanings. For more information, see {@link
287             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
288             * </p>
289             *
290             * @param companyId the primary key of the company
291             * @param name the resource's name, which can be either a class name or a
292             *        portlet ID
293             * @param scope the scope
294             * @param primKey the primary key
295             */
296            @Override
297            public void deleteResourcePermissions(
298                            long companyId, String name, int scope, long primKey)
299                    throws PortalException {
300    
301                    deleteResourcePermissions(
302                            companyId, name, scope, String.valueOf(primKey));
303            }
304    
305            /**
306             * Deletes all resource permissions at the scope to resources of the type.
307             * This method should not be confused with any of the
308             * <code>removeResourcePermission</code> methods, as its purpose is very
309             * different. This method should only be used for deleting resource
310             * permissions that refer to a resource when that resource is deleted. For
311             * example this method could be used to delete all individual scope
312             * permissions to a blog post when it is deleted.
313             *
314             * <p>
315             * Depending on the scope, the value of <code>primKey</code> will have
316             * different meanings. For more information, see {@link
317             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
318             * </p>
319             *
320             * @param companyId the primary key of the company
321             * @param name the resource's name, which can be either a class name or a
322             *        portlet ID
323             * @param scope the scope
324             * @param primKey the primary key
325             */
326            @Override
327            public void deleteResourcePermissions(
328                            long companyId, String name, int scope, String primKey)
329                    throws PortalException {
330    
331                    List<ResourcePermission> resourcePermissions =
332                            resourcePermissionPersistence.findByC_N_S_P(
333                                    companyId, name, scope, primKey);
334    
335                    for (ResourcePermission resourcePermission : resourcePermissions) {
336                            deleteResourcePermission(
337                                    resourcePermission.getResourcePermissionId());
338                    }
339            }
340    
341            @Override
342            public ResourcePermission fetchResourcePermission(
343                    long companyId, String name, int scope, String primKey, long roleId) {
344    
345                    return resourcePermissionPersistence.fetchByC_N_S_P_R(
346                            companyId, name, scope, primKey, roleId);
347            }
348    
349            @Override
350            public Map<Long, Set<String>> getAvailableResourcePermissionActionIds(
351                    long companyId, String name, int scope, String primKey,
352                    Collection<String> actionIds) {
353    
354                    if (actionIds.isEmpty()) {
355                            return Collections.emptyMap();
356                    }
357    
358                    List<ResourcePermission> resourcePermissions = getResourcePermissions(
359                            companyId, name, scope, primKey);
360    
361                    Map<Long, Set<String>> roleIdsToActionIds = new HashMap<>(
362                            resourcePermissions.size());
363    
364                    for (ResourcePermission resourcePermission : resourcePermissions) {
365                            if (resourcePermission.getActionIds() == 0) {
366                                    roleIdsToActionIds.put(
367                                            resourcePermission.getRoleId(),
368                                            Collections.<String>emptySet());
369    
370                                    continue;
371                            }
372    
373                            Set<String> availableActionIds = new HashSet<>(actionIds.size());
374    
375                            for (String actionId : actionIds) {
376                                    if (resourcePermission.hasActionId(actionId)) {
377                                            availableActionIds.add(actionId);
378                                    }
379                            }
380    
381                            if (availableActionIds.size() > 0) {
382                                    roleIdsToActionIds.put(
383                                            resourcePermission.getRoleId(), availableActionIds);
384                            }
385                    }
386    
387                    return roleIdsToActionIds;
388            }
389    
390            /**
391             * Returns the intersection of action IDs the role has permission at the
392             * scope to perform on resources of the type.
393             *
394             * @param  companyId he primary key of the company
395             * @param  name the resource's name, which can be either a class name or a
396             *         portlet ID
397             * @param  scope the scope
398             * @param  primKey the primary key
399             * @param  roleId the primary key of the role
400             * @param  actionIds the action IDs
401             * @return the intersection of action IDs the role has permission at the
402             *         scope to perform on resources of the type
403             */
404            @Override
405            public List<String> getAvailableResourcePermissionActionIds(
406                            long companyId, String name, int scope, String primKey, long roleId,
407                            Collection<String> actionIds)
408                    throws PortalException {
409    
410                    ResourcePermission resourcePermission =
411                            resourcePermissionPersistence.fetchByC_N_S_P_R(
412                                    companyId, name, scope, primKey, roleId);
413    
414                    if (resourcePermission == null) {
415                            return Collections.emptyList();
416                    }
417    
418                    List<String> availableActionIds = new ArrayList<>(actionIds.size());
419    
420                    for (String actionId : actionIds) {
421                            ResourceAction resourceAction =
422                                    resourceActionLocalService.getResourceAction(name, actionId);
423    
424                            if (hasActionId(resourcePermission, resourceAction)) {
425                                    availableActionIds.add(actionId);
426                            }
427                    }
428    
429                    return availableActionIds;
430            }
431    
432            /**
433             * @deprecated As of 7.0.0, replaced by {@link
434             *             #getAvailableResourcePermissionActionIds(long, String, int,
435             *             String, Collection)}
436             */
437            @Deprecated
438            @Override
439            public Map<Long, Set<String>> getAvailableResourcePermissionActionIds(
440                    long companyId, String name, int scope, String primKey, long[] roleIds,
441                    Collection<String> actionIds) {
442    
443                    return getAvailableResourcePermissionActionIds(
444                            companyId, name, scope, primKey, new ArrayList<String>(actionIds));
445            }
446    
447            /**
448             * Returns the resource permission for the role at the scope to perform the
449             * actions on resources of the type.
450             *
451             * @param  companyId the primary key of the company
452             * @param  name the resource's name, which can be either a class name or a
453             *         portlet ID
454             * @param  scope the scope
455             * @param  primKey the primary key
456             * @param  roleId the primary key of the role
457             * @return the resource permission for the role at the scope to perform the
458             *         actions on resources of the type
459             */
460            @Override
461            public ResourcePermission getResourcePermission(
462                            long companyId, String name, int scope, String primKey, long roleId)
463                    throws PortalException {
464    
465                    return resourcePermissionPersistence.findByC_N_S_P_R(
466                            companyId, name, scope, primKey, roleId);
467            }
468    
469            /**
470             * Returns all the resource permissions at the scope of the type.
471             *
472             * @param  companyId the primary key of the company
473             * @param  name the resource's name, which can be either a class name or a
474             *         portlet ID
475             * @param  scope the scope
476             * @param  primKey the primary key
477             * @return the resource permissions at the scope of the type
478             */
479            @Override
480            public List<ResourcePermission> getResourcePermissions(
481                    long companyId, String name, int scope, String primKey) {
482    
483                    return resourcePermissionPersistence.findByC_N_S_P(
484                            companyId, name, scope, primKey);
485            }
486    
487            /**
488             * Returns the number of resource permissions at the scope of the type.
489             *
490             * @param  companyId the primary key of the company
491             * @param  name the resource's name, which can be either a class name or a
492             *         portlet ID
493             * @param  scope the scope
494             * @param  primKey the primary key
495             * @return the number of resource permissions at the scope of the type
496             */
497            @Override
498            public int getResourcePermissionsCount(
499                    long companyId, String name, int scope, String primKey) {
500    
501                    return resourcePermissionPersistence.countByC_N_S_P(
502                            companyId, name, scope, primKey);
503            }
504    
505            /**
506             * Returns the resource permissions that apply to the resource.
507             *
508             * @param  companyId the primary key of the resource's company
509             * @param  groupId the primary key of the resource's group
510             * @param  name the resource's name, which can be either a class name or a
511             *         portlet ID
512             * @param  primKey the primary key of the resource
513             * @return the resource permissions associated with the resource
514             */
515            @Override
516            public List<ResourcePermission> getResourceResourcePermissions(
517                    long companyId, long groupId, String name, String primKey) {
518    
519                    return resourcePermissionFinder.findByResource(
520                            companyId, groupId, name, primKey);
521            }
522    
523            /**
524             * Returns all the resource permissions for the role.
525             *
526             * @param  roleId the primary key of the role
527             * @return the resource permissions for the role
528             */
529            @Override
530            public List<ResourcePermission> getRoleResourcePermissions(long roleId) {
531                    return resourcePermissionPersistence.findByRoleId(roleId);
532            }
533    
534            /**
535             * Returns a range of all the resource permissions for the role at the
536             * scopes.
537             *
538             * <p>
539             * Useful when paginating results. Returns a maximum of <code>end -
540             * start</code> instances. <code>start</code> and <code>end</code> are not
541             * primary keys, they are indexes in the result set. Thus, <code>0</code>
542             * refers to the first result in the set. Setting both <code>start</code>
543             * and <code>end</code> to {@link
544             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
545             * result set.
546             * </p>
547             *
548             * @param  roleId the primary key of the role
549             * @param  scopes the scopes
550             * @param  start the lower bound of the range of results
551             * @param  end the upper bound of the range of results (not inclusive)
552             * @return the range of resource permissions for the role at the scopes
553             */
554            @Override
555            public List<ResourcePermission> getRoleResourcePermissions(
556                    long roleId, int[] scopes, int start, int end) {
557    
558                    return resourcePermissionFinder.findByR_S(roleId, scopes, start, end);
559            }
560    
561            @Override
562            public List<Role> getRoles(
563                            long companyId, String name, int scope, String primKey,
564                            String actionId)
565                    throws PortalException {
566    
567                    List<ResourcePermission> resourcePermissions =
568                            resourcePermissionPersistence.findByC_N_S_P(
569                                    companyId, name, scope, primKey);
570    
571                    if (resourcePermissions.isEmpty()) {
572                            return Collections.emptyList();
573                    }
574    
575                    ResourceAction resourceAction =
576                            resourceActionLocalService.getResourceAction(name, actionId);
577    
578                    Set<Long> rolesIds = new HashSet<>();
579    
580                    for (ResourcePermission resourcePermission : resourcePermissions) {
581                            if (resourcePermission.hasAction(resourceAction)) {
582                                    rolesIds.add(resourcePermission.getRoleId());
583                            }
584                    }
585    
586                    List<Role> roles = new ArrayList<>(rolesIds.size());
587    
588                    for (long roleId : rolesIds) {
589                            roles.add(roleLocalService.getRole(roleId));
590                    }
591    
592                    return roles;
593            }
594    
595            /**
596             * Returns all the resource permissions where scope = any &#63;.
597             *
598             * <p>
599             * Useful when paginating results. Returns a maximum of <code>end -
600             * start</code> instances. <code>start</code> and <code>end</code> are not
601             * primary keys, they are indexes in the result set. Thus, <code>0</code>
602             * refers to the first result in the set. Setting both <code>start</code>
603             * and <code>end</code> to {@link
604             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
605             * result set.
606             * </p>
607             *
608             * @param  scopes the scopes
609             * @return the resource permissions where scope = any &#63;
610             */
611            @Override
612            public List<ResourcePermission> getScopeResourcePermissions(int[] scopes) {
613                    return resourcePermissionPersistence.findByScope(scopes);
614            }
615    
616            /**
617             * Returns <code>true</code> if the resource permission grants permission to
618             * perform the resource action. Note that this method does not ensure that
619             * the resource permission refers to the same type of resource as the
620             * resource action.
621             *
622             * @param  resourcePermission the resource permission
623             * @param  resourceAction the resource action
624             * @return <code>true</code> if the resource permission grants permission to
625             *         perform the resource action
626             */
627            @Override
628            public boolean hasActionId(
629                    ResourcePermission resourcePermission, ResourceAction resourceAction) {
630    
631                    long actionIds = resourcePermission.getActionIds();
632                    long bitwiseValue = resourceAction.getBitwiseValue();
633    
634                    if ((actionIds & bitwiseValue) == bitwiseValue) {
635                            return true;
636                    }
637                    else {
638                            return false;
639                    }
640            }
641    
642            /**
643             * Returns <code>true</code> if the roles have permission at the scope to
644             * perform the action on the resources.
645             *
646             * <p>
647             * Depending on the scope, the value of <code>primKey</code> will have
648             * different meanings. For more information, see {@link
649             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
650             * </p>
651             *
652             * @param  resources the resources
653             * @param  roleIds the primary keys of the roles
654             * @param  actionId the action ID
655             * @return <code>true</code> if any one of the roles has permission to
656             *         perform the action on any one of the resources;
657             *         <code>false</code> otherwise
658             */
659            @Override
660            public boolean hasResourcePermission(
661                            List<Resource> resources, long[] roleIds, String actionId)
662                    throws PortalException {
663    
664                    if (roleIds.length == 0) {
665                            return false;
666                    }
667    
668                    int size = resources.size();
669    
670                    if (size < 2) {
671                            throw new IllegalArgumentException(
672                                    "The list of resources must contain at least two values");
673                    }
674    
675                    Resource individualResource = resources.get(0);
676    
677                    if (individualResource.getScope() !=
678                                    ResourceConstants.SCOPE_INDIVIDUAL) {
679    
680                            throw new IllegalArgumentException(
681                                    "The first resource must be an individual scope");
682                    }
683    
684                    Resource companyResource = resources.get(size - 1);
685    
686                    if (companyResource.getScope() != ResourceConstants.SCOPE_COMPANY) {
687                            throw new IllegalArgumentException(
688                                    "The last resource must be a company scope");
689                    }
690    
691                    // See LPS-47464
692    
693                    if (resourcePermissionPersistence.countByC_N_S_P(
694                                    individualResource.getCompanyId(), individualResource.getName(),
695                                    individualResource.getScope(),
696                                    individualResource.getPrimKey()) < 1) {
697    
698                            StringBundler sb = new StringBundler(9);
699    
700                            sb.append("{companyId=");
701                            sb.append(individualResource.getCompanyId());
702                            sb.append(", name=");
703                            sb.append(individualResource.getName());
704                            sb.append(", primKey=");
705                            sb.append(individualResource.getPrimKey());
706                            sb.append(", scope=");
707                            sb.append(individualResource.getScope());
708                            sb.append("}");
709    
710                            throw new NoSuchResourcePermissionException(sb.toString());
711                    }
712    
713                    // Iterate the list of resources in reverse order to test permissions
714                    // from company scope to individual scope because it is more likely that
715                    // a permission is assigned at a higher scope. Optimizing this method to
716                    // one SQL call may actually slow things down since most of the calls
717                    // will pull from the cache after the first request.
718    
719                    for (int i = size - 1; i >= 0; i--) {
720                            Resource resource = resources.get(i);
721    
722                            if (hasResourcePermission(
723                                            resource.getCompanyId(), resource.getName(),
724                                            resource.getScope(), resource.getPrimKey(), roleIds,
725                                            actionId)) {
726    
727                                    return true;
728                            }
729                    }
730    
731                    return false;
732            }
733    
734            /**
735             * Returns <code>true</code> if the role has permission at the scope to
736             * perform the action on resources of the type.
737             *
738             * <p>
739             * Depending on the scope, the value of <code>primKey</code> will have
740             * different meanings. For more information, see {@link
741             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
742             * </p>
743             *
744             * @param  companyId the primary key of the company
745             * @param  name the resource's name, which can be either a class name or a
746             *         portlet ID
747             * @param  scope the scope
748             * @param  primKey the primary key
749             * @param  roleId the primary key of the role
750             * @param  actionId the action ID
751             * @return <code>true</code> if the role has permission to perform the
752             *         action on the resource; <code>false</code> otherwise
753             */
754            @Override
755            public boolean hasResourcePermission(
756                            long companyId, String name, int scope, String primKey, long roleId,
757                            String actionId)
758                    throws PortalException {
759    
760                    ResourcePermission resourcePermission =
761                            resourcePermissionPersistence.fetchByC_N_S_P_R(
762                                    companyId, name, scope, primKey, roleId);
763    
764                    if (resourcePermission == null) {
765                            return false;
766                    }
767    
768                    ResourceAction resourceAction =
769                            resourceActionLocalService.getResourceAction(name, actionId);
770    
771                    if (hasActionId(resourcePermission, resourceAction)) {
772                            return true;
773                    }
774    
775                    return false;
776            }
777    
778            /**
779             * Returns <code>true</code> if the roles have permission at the scope to
780             * perform the action on resources of the type.
781             *
782             * <p>
783             * Depending on the scope, the value of <code>primKey</code> will have
784             * different meanings. For more information, see {@link
785             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
786             * </p>
787             *
788             * @param  companyId the primary key of the company
789             * @param  name the resource's name, which can be either a class name or a
790             *         portlet ID
791             * @param  scope the scope
792             * @param  primKey the primary key
793             * @param  roleIds the primary keys of the roles
794             * @param  actionId the action ID
795             * @return <code>true</code> if any one of the roles has permission to
796             *         perform the action on the resource; <code>false</code> otherwise
797             */
798            @Override
799            public boolean hasResourcePermission(
800                            long companyId, String name, int scope, String primKey,
801                            long[] roleIds, String actionId)
802                    throws PortalException {
803    
804                    if (roleIds.length == 0) {
805                            return false;
806                    }
807    
808                    ResourceAction resourceAction =
809                            resourceActionLocalService.getResourceAction(name, actionId);
810    
811                    if (roleIds.length >
812                                    PropsValues.
813                                            PERMISSIONS_ROLE_RESOURCE_PERMISSION_QUERY_THRESHOLD) {
814    
815                            int count = resourcePermissionFinder.countByC_N_S_P_R_A(
816                                    companyId, name, scope, primKey, roleIds,
817                                    resourceAction.getBitwiseValue());
818    
819                            if (count > 0) {
820                                    return true;
821                            }
822                    }
823                    else {
824                            List<ResourcePermission> resourcePermissions =
825                                    resourcePermissionPersistence.findByC_N_S_P_R(
826                                            companyId, name, scope, primKey, roleIds);
827    
828                            if (resourcePermissions.isEmpty()) {
829                                    return false;
830                            }
831    
832                            for (ResourcePermission resourcePermission : resourcePermissions) {
833                                    if (hasActionId(resourcePermission, resourceAction)) {
834                                            return true;
835                                    }
836                            }
837                    }
838    
839                    return false;
840            }
841    
842            /**
843             * @deprecated As of 7.0.0, replaced by {@link #getRoles(long, String, int,
844             *             String, String}
845             */
846            @Deprecated
847            @Override
848            public boolean[] hasResourcePermissions(
849                            long companyId, String name, int scope, String primKey,
850                            long[] roleIds, String actionId)
851                    throws PortalException {
852    
853                    boolean[] hasResourcePermissions = new boolean[roleIds.length];
854    
855                    if (roleIds.length == 0) {
856                            return hasResourcePermissions;
857                    }
858    
859                    ResourceAction resourceAction =
860                            resourceActionLocalService.getResourceAction(name, actionId);
861    
862                    List<ResourcePermission> resourcePermissions =
863                            resourcePermissionPersistence.findByC_N_S_P_R(
864                                    companyId, name, scope, primKey, roleIds);
865    
866                    if (resourcePermissions.isEmpty()) {
867                            return hasResourcePermissions;
868                    }
869    
870                    for (ResourcePermission resourcePermission : resourcePermissions) {
871                            if (hasActionId(resourcePermission, resourceAction)) {
872                                    long roleId = resourcePermission.getRoleId();
873    
874                                    for (int i = 0; i < roleIds.length; i++) {
875                                            if (roleIds[i] == roleId) {
876                                                    hasResourcePermissions[i] = true;
877    
878                                                    break;
879                                            }
880                                    }
881                            }
882                    }
883    
884                    return hasResourcePermissions;
885            }
886    
887            /**
888             * Returns <code>true</code> if the role has permission at the scope to
889             * perform the action on the resource.
890             *
891             * <p>
892             * Depending on the scope, the value of <code>primKey</code> will have
893             * different meanings. For more information, see {@link
894             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
895             * </p>
896             *
897             * @param  companyId the primary key of the company
898             * @param  name the resource's name, which can be either a class name or a
899             *         portlet ID
900             * @param  scope the scope
901             * @param  roleId the primary key of the role
902             * @param  actionId the action ID
903             * @return <code>true</code> if the role has permission to perform the
904             *         action on the resource; <code>false</code> otherwise
905             */
906            @Override
907            public boolean hasScopeResourcePermission(
908                            long companyId, String name, int scope, long roleId,
909                            String actionId)
910                    throws PortalException {
911    
912                    List<ResourcePermission> resourcePermissions =
913                            resourcePermissionPersistence.findByC_N_S(companyId, name, scope);
914    
915                    for (ResourcePermission resourcePermission : resourcePermissions) {
916                            if (hasResourcePermission(
917                                            companyId, name, scope, resourcePermission.getPrimKey(),
918                                            roleId, actionId)) {
919    
920                                    return true;
921                            }
922                    }
923    
924                    return false;
925            }
926    
927            /**
928             * Reassigns all the resource permissions from the source role to the
929             * destination role, and deletes the source role.
930             *
931             * @param fromRoleId the primary key of the source role
932             * @param toRoleId the primary key of the destination role
933             */
934            @Override
935            public void mergePermissions(long fromRoleId, long toRoleId)
936                    throws PortalException {
937    
938                    Role fromRole = rolePersistence.findByPrimaryKey(fromRoleId);
939                    Role toRole = rolePersistence.findByPrimaryKey(toRoleId);
940    
941                    if (fromRole.getType() != toRole.getType()) {
942                            throw new PortalException("Role types are mismatched");
943                    }
944                    else if (toRole.isSystem()) {
945                            throw new PortalException("Cannot move permissions to system role");
946                    }
947                    else if (fromRole.isSystem()) {
948                            throw new PortalException(
949                                    "Cannot move permissions from system role");
950                    }
951    
952                    List<ResourcePermission> resourcePermissions =
953                            getRoleResourcePermissions(fromRoleId);
954    
955                    for (ResourcePermission resourcePermission : resourcePermissions) {
956                            resourcePermission.setRoleId(toRoleId);
957    
958                            resourcePermissionPersistence.update(resourcePermission);
959                    }
960    
961                    roleLocalService.deleteRole(fromRoleId);
962    
963                    PermissionCacheUtil.clearCache();
964            }
965    
966            /**
967             * Grants the role default permissions to all the resources of the type and
968             * at the scope stored in the resource permission, deletes the resource
969             * permission, and deletes the resource permission's role if it has no
970             * permissions remaining.
971             *
972             * @param resourcePermissionId the primary key of the resource permission
973             * @param toRoleId the primary key of the role
974             */
975            @Override
976            public void reassignPermissions(long resourcePermissionId, long toRoleId)
977                    throws PortalException {
978    
979                    ResourcePermission resourcePermission = getResourcePermission(
980                            resourcePermissionId);
981    
982                    long companyId = resourcePermission.getCompanyId();
983                    String name = resourcePermission.getName();
984                    int scope = resourcePermission.getScope();
985                    String primKey = resourcePermission.getPrimKey();
986                    long fromRoleId = resourcePermission.getRoleId();
987    
988                    Role toRole = roleLocalService.getRole(toRoleId);
989    
990                    List<String> actionIds = null;
991    
992                    if (toRole.getType() == RoleConstants.TYPE_REGULAR) {
993                            actionIds = ResourceActionsUtil.getModelResourceActions(name);
994                    }
995                    else {
996                            actionIds = ResourceActionsUtil.getModelResourceGroupDefaultActions(
997                                    name);
998                    }
999    
1000                    setResourcePermissions(
1001                            companyId, name, scope, primKey, toRoleId,
1002                            actionIds.toArray(new String[actionIds.size()]));
1003    
1004                    resourcePermissionPersistence.remove(resourcePermissionId);
1005    
1006                    List<ResourcePermission> resourcePermissions =
1007                            getRoleResourcePermissions(fromRoleId);
1008    
1009                    if (resourcePermissions.isEmpty()) {
1010                            roleLocalService.deleteRole(fromRoleId);
1011                    }
1012    
1013                    PermissionCacheUtil.clearCache();
1014            }
1015    
1016            /**
1017             * Revokes permission at the scope from the role to perform the action on
1018             * resources of the type. For example, this method could be used to revoke a
1019             * group scope permission to edit blog posts.
1020             *
1021             * <p>
1022             * Depending on the scope, the value of <code>primKey</code> will have
1023             * different meanings. For more information, see {@link
1024             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
1025             * </p>
1026             *
1027             * @param companyId the primary key of the company
1028             * @param name the resource's name, which can be either a class name or a
1029             *        portlet ID
1030             * @param scope the scope
1031             * @param primKey the primary key
1032             * @param roleId the primary key of the role
1033             * @param actionId the action ID
1034             */
1035            @Override
1036            public void removeResourcePermission(
1037                            long companyId, String name, int scope, String primKey, long roleId,
1038                            String actionId)
1039                    throws PortalException {
1040    
1041                    updateResourcePermission(
1042                            companyId, name, scope, primKey, roleId, 0, new String[] {actionId},
1043                            ResourcePermissionConstants.OPERATOR_REMOVE);
1044            }
1045    
1046            /**
1047             * Revokes all permissions at the scope from the role to perform the action
1048             * on resources of the type. For example, this method could be used to
1049             * revoke all individual scope permissions to edit blog posts from site
1050             * members.
1051             *
1052             * @param companyId the primary key of the company
1053             * @param name the resource's name, which can be either a class name or a
1054             *        portlet ID
1055             * @param scope the scope
1056             * @param roleId the primary key of the role
1057             * @param actionId the action ID
1058             */
1059            @Override
1060            public void removeResourcePermissions(
1061                            long companyId, String name, int scope, long roleId,
1062                            String actionId)
1063                    throws PortalException {
1064    
1065                    List<ResourcePermission> resourcePermissions =
1066                            resourcePermissionPersistence.findByC_N_S(companyId, name, scope);
1067    
1068                    for (ResourcePermission resourcePermission : resourcePermissions) {
1069                            updateResourcePermission(
1070                                    companyId, name, scope, resourcePermission.getPrimKey(), roleId,
1071                                    0, new String[] {actionId},
1072                                    ResourcePermissionConstants.OPERATOR_REMOVE);
1073                    }
1074            }
1075    
1076            /**
1077             * Updates the role's permissions at the scope, setting the actions that can
1078             * be performed on resources of the type, also setting the owner of any
1079             * newly created resource permissions. Existing actions are replaced.
1080             *
1081             * <p>
1082             * This method can be used to set permissions at any scope, but it is
1083             * generally only used at the individual scope. For example, it could be
1084             * used to set the guest permissions on a blog post.
1085             * </p>
1086             *
1087             * <p>
1088             * Depending on the scope, the value of <code>primKey</code> will have
1089             * different meanings. For more information, see {@link
1090             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
1091             * </p>
1092             *
1093             * @param companyId the primary key of the company
1094             * @param name the resource's name, which can be either a class name or a
1095             *        portlet ID
1096             * @param scope the scope
1097             * @param primKey the primary key
1098             * @param roleId the primary key of the role
1099             * @param ownerId the primary key of the owner (generally the user that
1100             *        created the resource)
1101             * @param actionIds the action IDs of the actions
1102             */
1103            @Override
1104            @Retry(
1105                    acceptor = ExceptionRetryAcceptor.class,
1106                    properties = {
1107                            @Property(
1108                                    name = ExceptionRetryAcceptor.EXCEPTION_NAME,
1109                                    value =
1110                                            "org.springframework.dao.DataIntegrityViolationException"
1111                            )
1112                    }
1113            )
1114            public void setOwnerResourcePermissions(
1115                            long companyId, String name, int scope, String primKey, long roleId,
1116                            long ownerId, String[] actionIds)
1117                    throws PortalException {
1118    
1119                    updateResourcePermission(
1120                            companyId, name, scope, primKey, roleId, ownerId, actionIds,
1121                            ResourcePermissionConstants.OPERATOR_SET);
1122            }
1123    
1124            /**
1125             * Updates the role's permissions at the scope, setting the actions that can
1126             * be performed on resources of the type. Existing actions are replaced.
1127             *
1128             * <p>
1129             * This method can be used to set permissions at any scope, but it is
1130             * generally only used at the individual scope. For example, it could be
1131             * used to set the guest permissions on a blog post.
1132             * </p>
1133             *
1134             * <p>
1135             * Depending on the scope, the value of <code>primKey</code> will have
1136             * different meanings. For more information, see {@link
1137             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
1138             * </p>
1139             *
1140             * @param companyId the primary key of the company
1141             * @param name the resource's name, which can be either a class name or a
1142             *        portlet ID
1143             * @param scope the scope
1144             * @param primKey the primary key
1145             * @param roleId the primary key of the role
1146             * @param actionIds the action IDs of the actions
1147             */
1148            @Override
1149            @Retry(
1150                    acceptor = ExceptionRetryAcceptor.class,
1151                    properties = {
1152                            @Property(
1153                                    name = ExceptionRetryAcceptor.EXCEPTION_NAME,
1154                                    value =
1155                                            "org.springframework.dao.DataIntegrityViolationException"
1156                            )
1157                    }
1158            )
1159            public void setResourcePermissions(
1160                            long companyId, String name, int scope, String primKey, long roleId,
1161                            String[] actionIds)
1162                    throws PortalException {
1163    
1164                    updateResourcePermission(
1165                            companyId, name, scope, primKey, roleId, 0, actionIds,
1166                            ResourcePermissionConstants.OPERATOR_SET);
1167            }
1168    
1169            /**
1170             * Updates the role's permissions at the scope, setting the actions that can
1171             * be performed on resources of the type. Existing actions are replaced.
1172             *
1173             * <p>
1174             * This method can be used to set permissions at any scope, but it is
1175             * generally only used at the individual scope. For example, it could be
1176             * used to set the guest permissions on a blog post.
1177             * </p>
1178             *
1179             * <p>
1180             * Depending on the scope, the value of <code>primKey</code> will have
1181             * different meanings. For more information, see {@link
1182             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
1183             * </p>
1184             *
1185             * @param companyId the primary key of the company
1186             * @param name the resource's name, which can be either a class name or a
1187             *        portlet ID
1188             * @param scope the scope
1189             * @param primKey the primary key
1190             * @param roleIdsToActionIds a map of role IDs to action IDs of the actions
1191             */
1192            @Override
1193            @Retry(
1194                    acceptor = ExceptionRetryAcceptor.class,
1195                    properties = {
1196                            @Property(
1197                                    name = ExceptionRetryAcceptor.EXCEPTION_NAME,
1198                                    value =
1199                                            "org.springframework.dao.DataIntegrityViolationException"
1200                            )
1201                    }
1202            )
1203            public void setResourcePermissions(
1204                            long companyId, String name, int scope, String primKey,
1205                            Map<Long, String[]> roleIdsToActionIds)
1206                    throws PortalException {
1207    
1208                    updateResourcePermission(
1209                            companyId, name, scope, primKey, 0, roleIdsToActionIds);
1210            }
1211    
1212            protected void doUpdateResourcePermission(
1213                            long companyId, String name, int scope, String primKey,
1214                            long ownerId, long roleId, String[] actionIds, int operator,
1215                            boolean fetch)
1216                    throws PortalException {
1217    
1218                    ResourcePermission resourcePermission = null;
1219    
1220                    Map<Long, ResourcePermission> resourcePermissionsMap =
1221                            ResourcePermissionsThreadLocal.getResourcePermissions();
1222    
1223                    if (resourcePermissionsMap != null) {
1224                            resourcePermission = resourcePermissionsMap.get(roleId);
1225                    }
1226                    else if (fetch) {
1227                            resourcePermission = resourcePermissionPersistence.fetchByC_N_S_P_R(
1228                                    companyId, name, scope, primKey, roleId);
1229                    }
1230    
1231                    if (resourcePermission == null) {
1232                            if (((operator == ResourcePermissionConstants.OPERATOR_ADD) ||
1233                                     (operator == ResourcePermissionConstants.OPERATOR_SET)) &&
1234                                    (actionIds.length == 0)) {
1235    
1236                                    return;
1237                            }
1238    
1239                            if (operator == ResourcePermissionConstants.OPERATOR_REMOVE) {
1240                                    return;
1241                            }
1242    
1243                            long resourcePermissionId = counterLocalService.increment(
1244                                    ResourcePermission.class.getName());
1245    
1246                            resourcePermission = resourcePermissionPersistence.create(
1247                                    resourcePermissionId);
1248    
1249                            resourcePermission.setCompanyId(companyId);
1250                            resourcePermission.setName(name);
1251                            resourcePermission.setScope(scope);
1252                            resourcePermission.setPrimKey(primKey);
1253                            resourcePermission.setPrimKeyId(GetterUtil.getLong(primKey));
1254                            resourcePermission.setRoleId(roleId);
1255                            resourcePermission.setOwnerId(ownerId);
1256                    }
1257    
1258                    List<String> unsupportedActionIds = Collections.emptyList();
1259    
1260                    if (((operator == ResourcePermissionConstants.OPERATOR_ADD) ||
1261                             (operator == ResourcePermissionConstants.OPERATOR_SET)) &&
1262                            isGuestRoleId(companyId, roleId)) {
1263    
1264                            unsupportedActionIds =
1265                                    ResourceActionsUtil.getResourceGuestUnsupportedActions(
1266                                            name, name);
1267                    }
1268    
1269                    long actionIdsLong = resourcePermission.getActionIds();
1270    
1271                    if (operator == ResourcePermissionConstants.OPERATOR_SET) {
1272                            actionIdsLong = 0;
1273                    }
1274    
1275                    for (String actionId : actionIds) {
1276                            if (actionId == null) {
1277                                    break;
1278                            }
1279    
1280                            if (unsupportedActionIds.contains(actionId)) {
1281                                    throw new PrincipalException(
1282                                            actionId + "is not supported by role " + roleId);
1283                            }
1284    
1285                            ResourceAction resourceAction =
1286                                    resourceActionLocalService.getResourceAction(name, actionId);
1287    
1288                            if ((operator == ResourcePermissionConstants.OPERATOR_ADD) ||
1289                                    (operator == ResourcePermissionConstants.OPERATOR_SET)) {
1290    
1291                                    actionIdsLong |= resourceAction.getBitwiseValue();
1292                            }
1293                            else {
1294                                    actionIdsLong =
1295                                            actionIdsLong & (~resourceAction.getBitwiseValue());
1296                            }
1297                    }
1298    
1299                    resourcePermission.setActionIds(actionIdsLong);
1300                    resourcePermission.setViewActionId(actionIdsLong % 2 == 1);
1301    
1302                    resourcePermissionPersistence.update(resourcePermission);
1303    
1304                    IndexWriterHelperUtil.updatePermissionFields(name, primKey);
1305            }
1306    
1307            protected boolean isGuestRoleId(long companyId, long roleId)
1308                    throws PortalException {
1309    
1310                    Role guestRole = roleLocalService.getRole(
1311                            companyId, RoleConstants.GUEST);
1312    
1313                    if (roleId == guestRole.getRoleId()) {
1314                            return true;
1315                    }
1316    
1317                    return false;
1318            }
1319    
1320            /**
1321             * Updates the role's permissions at the scope, either adding to, removing
1322             * from, or setting the actions that can be performed on resources of the
1323             * type. Automatically creates a new resource permission if none exists, or
1324             * deletes the existing resource permission if it no longer grants
1325             * permissions to perform any action.
1326             *
1327             * <p>
1328             * Depending on the scope, the value of <code>primKey</code> will have
1329             * different meanings. For more information, see {@link
1330             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
1331             * </p>
1332             *
1333             * @param companyId the primary key of the company
1334             * @param name the resource's name, which can be either a class name or a
1335             *        portlet ID
1336             * @param scope the scope
1337             * @param primKey the primary key
1338             * @param roleId the primary key of the role
1339             * @param ownerId the primary key of the owner
1340             * @param actionIds the action IDs of the actions
1341             * @param operator whether to add to, remove from, or set/replace the
1342             *        existing actions. Possible values can be found in {@link
1343             *        ResourcePermissionConstants}.
1344             */
1345            protected void updateResourcePermission(
1346                            long companyId, String name, int scope, String primKey, long roleId,
1347                            long ownerId, String[] actionIds, int operator)
1348                    throws PortalException {
1349    
1350                    doUpdateResourcePermission(
1351                            companyId, name, scope, primKey, ownerId, roleId, actionIds,
1352                            operator, true);
1353            }
1354    
1355            /**
1356             * Updates the role's permissions at the scope, either adding to, removing
1357             * from, or setting the actions that can be performed on resources of the
1358             * type. Automatically creates a new resource permission if none exists, or
1359             * deletes the existing resource permission if it no longer grants
1360             * permissions to perform any action.
1361             *
1362             * <p>
1363             * Depending on the scope, the value of <code>primKey</code> will have
1364             * different meanings. For more information, see {@link
1365             * com.liferay.portal.model.impl.ResourcePermissionImpl}.
1366             * </p>
1367             *
1368             * @param companyId the primary key of the company
1369             * @param name the resource's name, which can be either a class name or a
1370             *        portlet ID
1371             * @param scope the scope
1372             * @param primKey the primary key
1373             * @param ownerId the primary key of the owner
1374             */
1375            protected void updateResourcePermission(
1376                            long companyId, String name, int scope, String primKey,
1377                            long ownerId, Map<Long, String[]> roleIdsToActionIds)
1378                    throws PortalException {
1379    
1380                    boolean flushResourcePermissionEnabled =
1381                            PermissionThreadLocal.isFlushResourcePermissionEnabled(
1382                                    name, primKey);
1383    
1384                    PermissionThreadLocal.setFlushResourcePermissionEnabled(
1385                            name, primKey, false);
1386    
1387                    try {
1388                            long[] roleIds = ArrayUtil.toLongArray(roleIdsToActionIds.keySet());
1389    
1390                            List<ResourcePermission> resourcePermissions =
1391                                    resourcePermissionPersistence.findByC_N_S_P_R(
1392                                            companyId, name, scope, primKey, roleIds);
1393    
1394                            for (ResourcePermission resourcePermission : resourcePermissions) {
1395                                    long roleId = resourcePermission.getRoleId();
1396                                    String[] actionIds = roleIdsToActionIds.remove(roleId);
1397    
1398                                    doUpdateResourcePermission(
1399                                            companyId, name, scope, primKey, ownerId, roleId, actionIds,
1400                                            ResourcePermissionConstants.OPERATOR_SET, true);
1401                            }
1402    
1403                            if (roleIdsToActionIds.isEmpty()) {
1404                                    return;
1405                            }
1406    
1407                            for (Map.Entry<Long, String[]> entry :
1408                                            roleIdsToActionIds.entrySet()) {
1409    
1410                                    long roleId = entry.getKey();
1411                                    String[] actionIds = entry.getValue();
1412    
1413                                    doUpdateResourcePermission(
1414                                            companyId, name, scope, primKey, ownerId, roleId, actionIds,
1415                                            ResourcePermissionConstants.OPERATOR_SET, false);
1416                            }
1417    
1418                            TransactionCommitCallbackUtil.registerCallback(
1419                                    new UpdateResourcePermissionCallable(name, primKey));
1420                    }
1421                    finally {
1422                            PermissionThreadLocal.setFlushResourcePermissionEnabled(
1423                                    name, primKey, flushResourcePermissionEnabled);
1424    
1425                            PermissionCacheUtil.clearResourcePermissionCache(
1426                                    scope, name, primKey);
1427    
1428                            IndexWriterHelperUtil.updatePermissionFields(name, primKey);
1429                    }
1430            }
1431    
1432            private static final String _FIND_MISSING_RESOURCE_PERMISSIONS =
1433                    ResourcePermissionLocalServiceImpl.class.getName() +
1434                            ".findMissingResourcePermissions";
1435    
1436            private static final String _UPDATE_ACTION_IDS =
1437                    ResourcePermissionLocalServiceImpl.class.getName() + ".updateActionIds";
1438    
1439            private static class UpdateResourcePermissionCallable
1440                    implements Callable<Void> {
1441    
1442                    public UpdateResourcePermissionCallable(String name, String primKey) {
1443                            _name = name;
1444                            _primKey = primKey;
1445                    }
1446    
1447                    @Override
1448                    public Void call() {
1449                            PermissionUpdateHandler permissionUpdateHandler =
1450                                    PermissionUpdateHandlerRegistryUtil.getPermissionUpdateHandler(
1451                                            _name);
1452    
1453                            if (permissionUpdateHandler == null) {
1454                                    return null;
1455                            }
1456    
1457                            permissionUpdateHandler.updatedPermission(_primKey);
1458    
1459                            return null;
1460                    }
1461    
1462                    private final String _name;
1463                    private final String _primKey;
1464    
1465            }
1466    
1467    }