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