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