001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.cache.index;
016    
017    import com.liferay.portal.kernel.cache.PortalCache;
018    import com.liferay.portal.kernel.cache.PortalCacheListener;
019    import com.liferay.portal.kernel.concurrent.ConcurrentHashSet;
020    
021    import java.io.Serializable;
022    
023    import java.util.Collections;
024    import java.util.HashSet;
025    import java.util.Set;
026    import java.util.concurrent.ConcurrentHashMap;
027    import java.util.concurrent.ConcurrentMap;
028    
029    /**
030     * @author Shuyang Zhou
031     */
032    public class PortalCacheIndexer<I, K extends Serializable, V> {
033    
034            public PortalCacheIndexer(
035                    IndexEncoder<I, K> indexEncoder, PortalCache<K, V> portalCache) {
036    
037                    _indexEncoder = indexEncoder;
038    
039                    _portalCache = portalCache;
040    
041                    _portalCache.registerPortalCacheListener(
042                            new IndexerPortalCacheListener());
043    
044                    for (K indexedCacheKey : _portalCache.getKeys()) {
045                            _addIndexedCacheKey(indexedCacheKey);
046                    }
047            }
048    
049            public Set<K> getKeys(I index) {
050                    Set<K> keys = _indexedCacheKeys.get(index);
051    
052                    if (keys == null) {
053                            return Collections.emptySet();
054                    }
055    
056                    return new HashSet<>(keys);
057            }
058    
059            public void removeKeys(I index) {
060                    Set<K> keys = _indexedCacheKeys.remove(index);
061    
062                    if (keys == null) {
063                            return;
064                    }
065    
066                    for (K key : keys) {
067                            _portalCache.remove(key);
068                    }
069            }
070    
071            private void _addIndexedCacheKey(K key) {
072                    I index = _indexEncoder.encode(key);
073    
074                    Set<K> keys = _indexedCacheKeys.get(index);
075    
076                    if (keys == null) {
077                            Set<K> newKeys = new ConcurrentHashSet<>();
078    
079                            newKeys.add(key);
080    
081                            keys = _indexedCacheKeys.putIfAbsent(index, newKeys);
082    
083                            if (keys == null) {
084                                    return;
085                            }
086                    }
087    
088                    keys.add(key);
089            }
090    
091            private void _removeIndexedCacheKey(K key) {
092                    I index = _indexEncoder.encode(key);
093    
094                    Set<K> keys = _indexedCacheKeys.get(index);
095    
096                    if (keys == null) {
097                            return;
098                    }
099    
100                    keys.remove(key);
101    
102                    if (keys.isEmpty() && _indexedCacheKeys.remove(index, keys)) {
103                            for (K victimIndexedCacheKey : keys) {
104                                    _addIndexedCacheKey(victimIndexedCacheKey);
105                            }
106                    }
107            }
108    
109            private final ConcurrentMap<I, Set<K>> _indexedCacheKeys =
110                    new ConcurrentHashMap<>();
111            private final IndexEncoder<I, K> _indexEncoder;
112            private final PortalCache<K, V> _portalCache;
113    
114            private class IndexerPortalCacheListener
115                    implements PortalCacheListener<K, V> {
116    
117                    @Override
118                    public void dispose() {
119                            _indexedCacheKeys.clear();
120                    }
121    
122                    @Override
123                    public void notifyEntryEvicted(
124                            PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
125    
126                            _removeIndexedCacheKey(key);
127                    }
128    
129                    @Override
130                    public void notifyEntryExpired(
131                            PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
132    
133                            _removeIndexedCacheKey(key);
134                    }
135    
136                    @Override
137                    public void notifyEntryPut(
138                            PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
139    
140                            _addIndexedCacheKey(key);
141                    }
142    
143                    @Override
144                    public void notifyEntryRemoved(
145                            PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
146    
147                            _removeIndexedCacheKey(key);
148                    }
149    
150                    @Override
151                    public void notifyEntryUpdated(
152                            PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
153                    }
154    
155                    @Override
156                    public void notifyRemoveAll(PortalCache<K, V> portalCache) {
157                            _indexedCacheKeys.clear();
158                    }
159    
160            }
161    
162    }