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