001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.security.permission;
016    
017    import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
018    import com.liferay.portal.kernel.cache.PortalCache;
019    import com.liferay.portal.kernel.cache.index.IndexEncoder;
020    import com.liferay.portal.kernel.cache.index.PortalCacheIndexer;
021    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
022    import com.liferay.portal.kernel.cluster.ClusterInvokeThreadLocal;
023    import com.liferay.portal.kernel.cluster.ClusterRequest;
024    import com.liferay.portal.kernel.exception.SystemException;
025    import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
026    import com.liferay.portal.kernel.log.Log;
027    import com.liferay.portal.kernel.log.LogFactoryUtil;
028    import com.liferay.portal.kernel.util.AutoResetThreadLocal;
029    import com.liferay.portal.kernel.util.HashUtil;
030    import com.liferay.portal.kernel.util.MethodHandler;
031    import com.liferay.portal.kernel.util.MethodKey;
032    import com.liferay.portal.kernel.util.StringBundler;
033    import com.liferay.portal.kernel.util.StringPool;
034    import com.liferay.portal.kernel.util.Validator;
035    import com.liferay.portal.model.ResourceConstants;
036    import com.liferay.portal.model.Role;
037    import com.liferay.portal.util.PropsValues;
038    
039    import java.io.Serializable;
040    
041    import java.util.Map;
042    
043    import org.apache.commons.collections.map.LRUMap;
044    
045    /**
046     * @author Charles May
047     * @author Michael Young
048     * @author Shuyang Zhou
049     * @author Connor McKay
050     * @author L??szl?? Csontos
051     */
052    public class PermissionCacheUtil {
053    
054            public static final String PERMISSION_CACHE_NAME =
055                    PermissionCacheUtil.class.getName() + "_PERMISSION";
056    
057            public static final String PERMISSION_CHECKER_BAG_CACHE_NAME =
058                    PermissionCacheUtil.class.getName() + "_PERMISSION_CHECKER_BAG";
059    
060            public static final String RESOURCE_BLOCK_IDS_BAG_CACHE_NAME =
061                    PermissionCacheUtil.class.getName() + "_RESOURCE_BLOCK_IDS_BAG";
062    
063            public static final String USER_PERMISSION_CHECKER_BAG_CACHE_NAME =
064                    PermissionCacheUtil.class.getName() + "_USER_PERMISSION_CHECKER_BAG";
065    
066            public static final String USER_ROLE_CACHE_NAME =
067                    PermissionCacheUtil.class.getName() + "_USER_ROLE";
068    
069            public static void clearCache() {
070                    if (ExportImportThreadLocal.isImportInProcess()) {
071                            return;
072                    }
073    
074                    clearLocalCache();
075    
076                    _permissionCheckerBagPortalCache.removeAll();
077                    _permissionPortalCache.removeAll();
078                    _resourceBlockIdsBagCache.removeAll();
079                    _userPermissionCheckerBagPortalCache.removeAll();
080                    _userRolePortalCache.removeAll();
081            }
082    
083            public static void clearLocalCache() {
084                    if (_localCacheAvailable) {
085                            Map<Serializable, Object> localCache = _localCache.get();
086    
087                            localCache.clear();
088                    }
089            }
090    
091            public static void clearCache(long... userIds) {
092                    if (ExportImportThreadLocal.isImportInProcess()) {
093                            return;
094                    }
095    
096                    clearLocalCache();
097    
098                    for (long userId : userIds) {
099                            _userPermissionCheckerBagPortalCache.remove(userId);
100    
101                            _permissionCheckerBagPortalCacheIndexer.removeKeys(userId);
102                            _userRolePortalCacheIndexer.removeKeys(userId);
103                    }
104    
105                    _permissionPortalCache.removeAll();
106                    _resourceBlockIdsBagCache.removeAll();
107    
108                    _sendClearCacheClusterMessage(_clearCacheMethodKey, userIds);
109            }
110    
111            public static void clearResourceBlockCache(
112                    long companyId, long groupId, String name) {
113    
114                    if (ExportImportThreadLocal.isImportInProcess() ||
115                            !PermissionThreadLocal.isFlushResourceBlockEnabled(
116                                    companyId, groupId, name)) {
117    
118                            return;
119                    }
120    
121                    clearLocalCache();
122    
123                    _resourceBlockIdsBagCacheIndexer.removeKeys(
124                            ResourceBlockIdsBagKeyIndexEncoder.encode(
125                                    companyId, groupId, name));
126    
127                    _sendClearCacheClusterMessage(
128                            _clearResourceBlockCacheMethodKey, companyId, groupId, name);
129            }
130    
131            public static void clearResourceCache() {
132                    if (!ExportImportThreadLocal.isImportInProcess()) {
133                            clearLocalCache();
134    
135                            _resourceBlockIdsBagCache.removeAll();
136                            _permissionPortalCache.removeAll();
137                    }
138            }
139    
140            public static void clearResourcePermissionCache(
141                    int scope, String name, String primKey) {
142    
143                    if (ExportImportThreadLocal.isImportInProcess() ||
144                            !PermissionThreadLocal.isFlushResourcePermissionEnabled(
145                                    name, primKey)) {
146    
147                            return;
148                    }
149    
150                    clearLocalCache();
151    
152                    if (scope == ResourceConstants.SCOPE_INDIVIDUAL) {
153                            _permissionPortalCacheNamePrimKeyIndexer.removeKeys(
154                                    PermissionKeyNamePrimKeyIndexEncoder.encode(name, primKey));
155    
156                            _sendClearCacheClusterMessage(
157                                    _clearResourcePermissionCacheMethodKey, scope, name, primKey);
158                    }
159                    else if (scope == ResourceConstants.SCOPE_GROUP) {
160                            _permissionPortalCacheGroupIdIndexer.removeKeys(
161                                    Long.valueOf(primKey));
162    
163                            _sendClearCacheClusterMessage(
164                                    _clearResourcePermissionCacheMethodKey, scope, name, primKey);
165                    }
166                    else {
167                            _permissionPortalCache.removeAll();
168                    }
169            }
170    
171            public static PermissionCheckerBag getBag(long userId, long groupId) {
172                    BagKey bagKey = new BagKey(userId, groupId);
173    
174                    return get(bagKey, _permissionCheckerBagPortalCache);
175            }
176    
177            public static Boolean getPermission(
178                    long userId, boolean signedIn, long groupId, String name,
179                    String primKey, String actionId) {
180    
181                    PermissionKey permissionKey = new PermissionKey(
182                            userId, signedIn, groupId, name, primKey, actionId);
183    
184                    return get(permissionKey, _permissionPortalCache);
185            }
186    
187            public static ResourceBlockIdsBag getResourceBlockIdsBag(
188                    long companyId, long groupId, long userId, String name) {
189    
190                    ResourceBlockIdsBagKey resourceBlockIdsBagKey =
191                            new ResourceBlockIdsBagKey(companyId, groupId, userId, name);
192    
193                    return get(resourceBlockIdsBagKey, _resourceBlockIdsBagCache);
194            }
195    
196            public static UserPermissionCheckerBag getUserBag(long userId) {
197                    return get(userId, _userPermissionCheckerBagPortalCache);
198            }
199    
200            public static Boolean getUserRole(long userId, Role role) {
201                    UserRoleKey userRoleKey = new UserRoleKey(userId, role.getRoleId());
202    
203                    Boolean userRole = _userRolePortalCache.get(userRoleKey);
204    
205                    if (userRole != null) {
206                            return userRole;
207                    }
208    
209                    return null;
210            }
211    
212            public static void putBag(
213                    long userId, long groupId, PermissionCheckerBag bag) {
214    
215                    if (bag == null) {
216                            return;
217                    }
218    
219                    BagKey bagKey = new BagKey(userId, groupId);
220    
221                    put(bagKey, bag, _permissionCheckerBagPortalCache);
222            }
223    
224            public static void putPermission(
225                    long userId, boolean signedIn, long groupId, String name,
226                    String primKey, String actionId, Boolean value) {
227    
228                    PermissionKey permissionKey = new PermissionKey(
229                            userId, signedIn, groupId, name, primKey, actionId);
230    
231                    put(permissionKey, value, _permissionPortalCache);
232            }
233    
234            public static void putResourceBlockIdsBag(
235                    long companyId, long groupId, long userId, String name,
236                    ResourceBlockIdsBag resourceBlockIdsBag) {
237    
238                    if (resourceBlockIdsBag == null) {
239                            return;
240                    }
241    
242                    ResourceBlockIdsBagKey resourceBlockIdsBagKey =
243                            new ResourceBlockIdsBagKey(companyId, groupId, userId, name);
244    
245                    put(
246                            resourceBlockIdsBagKey, resourceBlockIdsBag,
247                            _resourceBlockIdsBagCache);
248            }
249    
250            public static void putUserBag(
251                    long userId, UserPermissionCheckerBag userPermissionCheckerBag) {
252    
253                    put(
254                            userId, userPermissionCheckerBag,
255                            _userPermissionCheckerBagPortalCache);
256            }
257    
258            protected static
259                    <K extends Serializable, V, C extends PortalCache<K, V>> V get(
260                            K key, C portalCache) {
261    
262                    V value = null;
263    
264                    if (_localCacheAvailable) {
265                            Map<K, V> localCache = _localCache.get();
266    
267                            value = localCache.get(key);
268                    }
269    
270                    if (value == null) {
271                            value = portalCache.get(key);
272                    }
273    
274                    return value;
275            }
276    
277            protected static
278                    <K extends Serializable, V, C extends PortalCache<K, V>> void put(
279                            K key, V value, C portalCache) {
280    
281                    if (_localCacheAvailable) {
282                            Map<K, V> localCache = _localCache.get();
283    
284                            localCache.put(key, value);
285                    }
286    
287                    portalCache.put(key, value);
288            }
289    
290            public static void putUserRole(long userId, Role role, Boolean value) {
291                    if (value == null) {
292                            return;
293                    }
294    
295                    UserRoleKey userRoleKey = new UserRoleKey(userId, role.getRoleId());
296    
297                    _userRolePortalCache.put(userRoleKey, value);
298            }
299    
300            private static void _sendClearCacheClusterMessage(
301                    MethodKey methodKey, Object... arguments) {
302    
303                    if (!ClusterInvokeThreadLocal.isEnabled()) {
304                            return;
305                    }
306    
307                    ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
308                            new MethodHandler(methodKey, arguments), true);
309    
310                    clusterRequest.setFireAndForget(true);
311    
312                    try {
313                            ClusterExecutorUtil.execute(clusterRequest);
314                    }
315                    catch (SystemException se) {
316                            _log.error(se, se);
317                    }
318            }
319    
320            private static final MethodKey _clearCacheMethodKey = new MethodKey(
321                    PermissionCacheUtil.class, "clearCache", long[].class);
322            private static final MethodKey _clearResourceBlockCacheMethodKey =
323                    new MethodKey(
324                            PermissionCacheUtil.class, "clearResourceBlockCache", long.class,
325                            long.class, String.class);
326            private static final MethodKey _clearResourcePermissionCacheMethodKey =
327                    new MethodKey(
328                            PermissionCacheUtil.class, "clearResourcePermissionCache",
329                            int.class, String.class, String.class);
330            private static final PortalCache<BagKey, PermissionCheckerBag>
331                    _permissionCheckerBagPortalCache = MultiVMPoolUtil.getCache(
332                            PERMISSION_CHECKER_BAG_CACHE_NAME,
333                            PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE);
334            private static final PortalCacheIndexer<Long, BagKey, PermissionCheckerBag>
335                    _permissionCheckerBagPortalCacheIndexer =
336                            new PortalCacheIndexer<Long, BagKey, PermissionCheckerBag>(
337                                    new BagKeyIndexEncoder(), _permissionCheckerBagPortalCache);
338            private static final PortalCache<PermissionKey, Boolean>
339                    _permissionPortalCache = MultiVMPoolUtil.getCache(
340                            PERMISSION_CACHE_NAME,
341                            PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE);
342            private static final PortalCacheIndexer<Long, PermissionKey, Boolean>
343                    _permissionPortalCacheGroupIdIndexer =
344                            new PortalCacheIndexer<Long, PermissionKey, Boolean>(
345                                    new PermissionKeyGroupIdIndexEncoder(), _permissionPortalCache);
346            private static final PortalCacheIndexer<String, PermissionKey, Boolean>
347                    _permissionPortalCacheNamePrimKeyIndexer =
348                            new PortalCacheIndexer<String, PermissionKey, Boolean>(
349                                    new PermissionKeyNamePrimKeyIndexEncoder(),
350                                    _permissionPortalCache);
351            private static final
352                    PortalCache<ResourceBlockIdsBagKey, ResourceBlockIdsBag>
353                            _resourceBlockIdsBagCache = MultiVMPoolUtil.getCache(
354                                    RESOURCE_BLOCK_IDS_BAG_CACHE_NAME,
355                                    PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE);
356            private static final PortalCacheIndexer
357                    <String, ResourceBlockIdsBagKey, ResourceBlockIdsBag>
358                            _resourceBlockIdsBagCacheIndexer = new PortalCacheIndexer
359                                    <String, ResourceBlockIdsBagKey, ResourceBlockIdsBag>(
360                                            new ResourceBlockIdsBagKeyIndexEncoder(),
361                                            _resourceBlockIdsBagCache);
362            private static final PortalCache<Long, UserPermissionCheckerBag>
363                    _userPermissionCheckerBagPortalCache = MultiVMPoolUtil.getCache(
364                            USER_PERMISSION_CHECKER_BAG_CACHE_NAME,
365                            PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE);
366            private static final PortalCache<UserRoleKey, Boolean>
367                    _userRolePortalCache = MultiVMPoolUtil.getCache(
368                            USER_ROLE_CACHE_NAME,
369                            PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE);
370            private static final PortalCacheIndexer<Long, UserRoleKey, Boolean>
371                    _userRolePortalCacheIndexer =
372                            new PortalCacheIndexer<Long, UserRoleKey, Boolean>(
373                                    new UserRoleKeyIndexEncoder(), _userRolePortalCache);
374    
375            private static Log _log = LogFactoryUtil.getLog(PermissionCacheUtil.class);
376    
377            private static ThreadLocal<LRUMap> _localCache;
378            private static boolean _localCacheAvailable;
379    
380            private static class BagKey implements Serializable {
381    
382                    @Override
383                    public boolean equals(Object obj) {
384                            BagKey bagKey = (BagKey)obj;
385    
386                            if ((bagKey._userId == _userId) && (bagKey._groupId == _groupId)) {
387                                    return true;
388                            }
389    
390                            return false;
391                    }
392    
393                    @Override
394                    public int hashCode() {
395                            int hashCode = HashUtil.hash(0, _userId);
396    
397                            return HashUtil.hash(hashCode, _groupId);
398                    }
399    
400                    private BagKey(long userId, long groupId) {
401                            _userId = userId;
402                            _groupId = groupId;
403                    }
404    
405                    private static final long serialVersionUID = 1L;
406    
407                    private final long _groupId;
408                    private final long _userId;
409    
410            }
411    
412            private static class BagKeyIndexEncoder
413                    implements IndexEncoder<Long, BagKey> {
414    
415                    @Override
416                    public Long encode(BagKey bagKey) {
417                            return bagKey._userId;
418                    }
419    
420            }
421    
422            private static class PermissionKey implements Serializable {
423    
424                    @Override
425                    public boolean equals(Object obj) {
426                            PermissionKey permissionKey = (PermissionKey)obj;
427    
428                            if ((permissionKey._userId == _userId) &&
429                                    (permissionKey._signedIn == _signedIn) &&
430                                    (permissionKey._groupId == _groupId) &&
431                                    Validator.equals(permissionKey._name, _name) &&
432                                    Validator.equals(permissionKey._primKey, _primKey) &&
433                                    Validator.equals(permissionKey._actionId, _actionId)) {
434    
435                                    return true;
436                            }
437    
438                            return false;
439                    }
440    
441                    @Override
442                    public int hashCode() {
443                            int hashCode = HashUtil.hash(0, _userId);
444    
445                            hashCode = HashUtil.hash(hashCode, _signedIn);
446                            hashCode = HashUtil.hash(hashCode, _groupId);
447                            hashCode = HashUtil.hash(hashCode, _name);
448                            hashCode = HashUtil.hash(hashCode, _primKey);
449                            hashCode = HashUtil.hash(hashCode, _actionId);
450    
451                            return hashCode;
452                    }
453    
454                    private PermissionKey(
455                            long userId, boolean signedIn, long groupId, String name,
456                            String primKey, String actionId) {
457    
458                            _userId = userId;
459                            _signedIn = signedIn;
460                            _groupId = groupId;
461                            _name = name;
462                            _primKey = primKey;
463                            _actionId = actionId;
464                    }
465    
466                    private static final long serialVersionUID = 1L;
467    
468                    private final String _actionId;
469                    private final long _groupId;
470                    private final String _name;
471                    private final String _primKey;
472                    private final boolean _signedIn;
473                    private final long _userId;
474    
475            }
476    
477            private static class PermissionKeyGroupIdIndexEncoder
478                    implements IndexEncoder<Long, PermissionKey> {
479    
480                    @Override
481                    public Long encode(PermissionKey permissionKey) {
482                            return permissionKey._groupId;
483                    }
484    
485            }
486    
487            private static class PermissionKeyNamePrimKeyIndexEncoder
488                    implements IndexEncoder<String, PermissionKey> {
489    
490                    public static String encode(String name, String primKey) {
491                            return name.concat(StringPool.UNDERLINE).concat(primKey);
492                    }
493    
494                    @Override
495                    public String encode(PermissionKey permissionKey) {
496                            return encode(permissionKey._name, permissionKey._primKey);
497                    }
498    
499            }
500    
501            private static class ResourceBlockIdsBagKey implements Serializable {
502    
503                    @Override
504                    public boolean equals(Object obj) {
505                            ResourceBlockIdsBagKey resourceBlockIdsKey =
506                                    (ResourceBlockIdsBagKey)obj;
507    
508                            if ((resourceBlockIdsKey._companyId == _companyId) &&
509                                    (resourceBlockIdsKey._groupId == _groupId) &&
510                                    (resourceBlockIdsKey._userId == _userId) &&
511                                    Validator.equals(resourceBlockIdsKey._name, _name)) {
512    
513                                    return true;
514                            }
515    
516                            return false;
517                    }
518    
519                    @Override
520                    public int hashCode() {
521                            int hashCode = HashUtil.hash(0, _companyId);
522    
523                            hashCode = HashUtil.hash(hashCode, _groupId);
524                            hashCode = HashUtil.hash(hashCode, _userId);
525                            hashCode = HashUtil.hash(hashCode, _name);
526    
527                            return hashCode;
528                    }
529    
530                    private ResourceBlockIdsBagKey(
531                            long companyId, long groupId, long userId, String name) {
532    
533                            _companyId = companyId;
534                            _groupId = groupId;
535                            _userId = userId;
536                            _name = name;
537                    }
538    
539                    private static final long serialVersionUID = 1L;
540    
541                    private final long _companyId;
542                    private final long _groupId;
543                    private final String _name;
544                    private final long _userId;
545    
546            }
547    
548            private static class ResourceBlockIdsBagKeyIndexEncoder
549                    implements IndexEncoder<String, ResourceBlockIdsBagKey> {
550    
551                    public static String encode(long companyId, long groupId, String name) {
552                            StringBundler sb = new StringBundler(5);
553    
554                            sb.append(companyId);
555                            sb.append(StringPool.UNDERLINE);
556                            sb.append(groupId);
557                            sb.append(StringPool.UNDERLINE);
558                            sb.append(name);
559    
560                            return sb.toString();
561                    }
562    
563                    @Override
564                    public String encode(ResourceBlockIdsBagKey resourceBlockIdsBagKey) {
565                            return encode(
566                                    resourceBlockIdsBagKey._companyId,
567                                    resourceBlockIdsBagKey._groupId, resourceBlockIdsBagKey._name);
568                    }
569    
570            }
571    
572            private static class UserRoleKey implements Serializable {
573    
574                    @Override
575                    public boolean equals(Object obj) {
576                            UserRoleKey userRoleKey = (UserRoleKey)obj;
577    
578                            if ((userRoleKey._userId == _userId) &&
579                                    (userRoleKey._roleId == _roleId)) {
580    
581                                    return true;
582                            }
583    
584                            return false;
585                    }
586    
587                    @Override
588                    public int hashCode() {
589                            int hashCode = HashUtil.hash(0, _userId);
590    
591                            return HashUtil.hash(hashCode, _roleId);
592                    }
593    
594                    private UserRoleKey(long userId, long roleId) {
595                            _userId = userId;
596                            _roleId = roleId;
597                    }
598    
599                    private static final long serialVersionUID = 1L;
600    
601                    private final long _roleId;
602                    private final long _userId;
603    
604            }
605    
606            private static class UserRoleKeyIndexEncoder
607                    implements IndexEncoder<Long, UserRoleKey> {
608    
609                    @Override
610                    public Long encode(UserRoleKey userRoleKey) {
611                            return userRoleKey._userId;
612                    }
613    
614            }
615    
616            static {
617                    if (PropsValues.PERMISSIONS_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
618                            _localCache = new AutoResetThreadLocal<LRUMap>(
619                                    PermissionCacheUtil.class + "._localCache",
620                                    new LRUMap(
621                                            PropsValues.PERMISSIONS_THREAD_LOCAL_CACHE_MAX_SIZE));
622                            _localCacheAvailable = true;
623                    }
624            }
625    
626    }