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