001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *                               ***
008 *
009 *   Community License: GPL 3.0
010 *
011 *   This file is free software: you can redistribute it and/or modify
012 *   it under the terms of the GNU General Public License as published
013 *   by the Free Software Foundation, either version 3 of the License,
014 *   or (at your option) any later version.
015 *
016 *   This file is distributed in the hope that it will be useful, but
017 *   WITHOUT ANY WARRANTY; without even the implied warranty of
018 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
019 *   GNU General Public License for more details.
020 *
021 *   You should have received a copy of the GNU General Public License
022 *   along with this program. If not, see <http://www.gnu.org/licenses/>.
023 *
024 *                               ***
025 *
026 *   Available Commercial License: GraniteDS SLA 1.0
027 *
028 *   This is the appropriate option if you are creating proprietary
029 *   applications and you are not prepared to distribute and share the
030 *   source code of your application under the GPL v3 license.
031 *
032 *   Please visit http://www.granitedataservices.com/license for more
033 *   details.
034 */
035package org.granite.client.tide.data.impl;
036
037import java.util.ArrayList;
038import java.util.List;
039import java.util.WeakHashMap;
040
041import org.granite.client.tide.data.spi.DataManager;
042
043/**
044 *  Implementation of HashSet that holds weak references to UID entities 
045 *  
046 *  @author William DRAI
047 */
048public class UIDWeakSet {
049    
050        private final DataManager dataManager;
051    private final WeakHashMap<Object, Object>[] table;
052    
053    
054    public UIDWeakSet(DataManager dataManager) {
055        this(dataManager, 64);
056    }
057    
058    @SuppressWarnings("unchecked")
059    public UIDWeakSet(DataManager dataManager, int capacity) {
060        this.dataManager = dataManager;
061        table = new WeakHashMap[capacity];  
062    }
063    
064    public void clear() {
065        for (int i = 0; i < table.length; i++)
066            table[i] = null;
067    }
068    
069    public Object put(Object uidObject) {
070        int h = hash(dataManager.getCacheKey(uidObject));
071        
072        WeakHashMap<Object, Object> dic = table[h];
073        if (dic == null) {
074            dic = new WeakHashMap<Object, Object>();
075            table[h] = dic;
076        }
077        
078        Object old = null;
079        for (Object o : dic.keySet()) {
080            if (o == uidObject)
081                return o;
082            
083            if (dataManager.getUid(o) == dataManager.getUid(uidObject) && o.getClass().getName().equals(uidObject.getClass().getName())) {
084                old = o;
085                dic.remove(o);
086                break;
087            }
088        }
089        
090        dic.put(uidObject, null);
091        
092        return old;
093    }
094    
095    public Object get(String cacheKey) {
096        int h = hash(cacheKey);
097        
098        Object uidObject = null;
099        
100        WeakHashMap<Object, Object> dic = table[h];
101        if (dic != null) {
102            for (Object o : dic.keySet()) {
103                if (dataManager.getCacheKey(o).equals(cacheKey)) {
104                    uidObject = o;
105                    break;
106                }
107            }
108        }
109        
110        return uidObject;
111    }
112
113    public static interface Matcher {
114        
115        public boolean match(Object o);
116    }
117    
118    public Object find(Matcher matcher) {
119        for (int i = 0; i < table.length; i++) {
120            WeakHashMap<Object, Object> dic = table[i];
121            if (dic != null) {
122                for (Object o : dic.keySet()) {
123                    if (matcher.match(o))
124                        return o;
125                }
126            }
127        }
128        return null;
129    }
130
131    public static interface Operation {
132        
133        public void apply(Object o);
134    }
135    
136    public void apply(Operation operation) {
137        for (int i = 0; i < table.length; i++) {
138            WeakHashMap<Object, Object> dic = table[i];
139            if (dic != null) {
140                for (Object o : dic.keySet())
141                    operation.apply(o);
142            }
143        }
144    }
145    
146    public Object remove(String cacheKey) {
147        int h = hash(cacheKey);
148        
149        Object uidObject = null;
150        
151        WeakHashMap<Object, Object> dic = table[h];
152        if (dic != null) {
153            for (Object o : dic.keySet()) {
154                if (dataManager.getCacheKey(o).equals(cacheKey)) {
155                    uidObject = o;
156                    dic.remove(o);
157                    break;
158                }
159            }
160        }
161        
162        return uidObject;
163    }
164    
165    public int size() {
166        int size = 0;
167        
168        for (int i = 0; i < table.length; i++) {
169            WeakHashMap<Object, Object> dic = table[i];
170            if (dic != null)
171                size += dic.size();
172        }
173        
174        return size;
175    }
176    
177    public List<Object> data() {
178        List<Object> d = new ArrayList<Object>();
179        
180        for (int i = 0; i < table.length; i++) {
181            WeakHashMap<Object, Object> dic = table[i];
182            if (dic != null)
183                d.addAll(dic.keySet());
184        }
185        return d;
186    }
187    
188    private int hash(String uid) {
189        int h = 0;
190        int max = uid.length();
191        for (int i = 0; i < max; i++)
192            h = (31 * h) + uid.charAt(i);
193        return (Math.abs(h) % table.length);
194    }
195}