001    /**
002     * Copyright (c) 2000-2010 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.util;
016    
017    import com.liferay.portal.kernel.dao.db.DB;
018    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
019    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
020    import com.liferay.portal.kernel.util.FileUtil;
021    import com.liferay.portal.kernel.util.MultiValueMap;
022    import com.liferay.portal.kernel.util.SerializableUtil;
023    
024    import java.io.File;
025    import java.io.Serializable;
026    
027    import java.sql.Connection;
028    import java.sql.DriverManager;
029    import java.sql.PreparedStatement;
030    import java.sql.ResultSet;
031    
032    import java.util.Collection;
033    import java.util.HashSet;
034    import java.util.Set;
035    
036    /**
037     * @author Alexander Chow
038     */
039    public class FileMultiValueMap<K extends Serializable, V extends Serializable>
040            extends MultiValueMap<K, V> {
041    
042            public FileMultiValueMap() {
043                    _fileName = FileUtil.createTempFileName();
044    
045                    try {
046                            Class.forName("org.hsqldb.jdbcDriver");
047                    }
048                    catch (Exception e) {
049                            throw new RuntimeException(e);
050                    }
051    
052                    _createDatabase();
053            }
054    
055            public void clear() {
056                    try {
057                            _deleteDatabase();
058                            _createDatabase();
059                    }
060                    catch (Throwable t) {
061                            throw new RuntimeException(t);
062                    }
063            }
064    
065            public boolean containsKey(Object key) {
066                    int count = _getCount((K)key, null);
067    
068                    if (count > 0) {
069                            return true;
070                    }
071                    else {
072                            return false;
073                    }
074            }
075    
076            public boolean containsValue(Object value) {
077                    int count = _getCount(null, (V)value);
078    
079                    if (count > 0) {
080                            return true;
081                    }
082                    else {
083                            return false;
084                    }
085            }
086    
087            public Set<V> getAll(Object key) {
088                    Connection con = null;
089                    PreparedStatement ps = null;
090                    ResultSet rs = null;
091    
092                    Set<V> values = null;
093    
094                    try {
095                            con = _getConnection();
096    
097                            ps = con.prepareStatement("SELECT value_ FROM Map WHERE key_ = ?");
098    
099                            ps.setBytes(1, SerializableUtil.serialize(key));
100    
101                            rs = ps.executeQuery();
102    
103                            while (rs.next()) {
104                                    if (values == null) {
105                                            values = new HashSet<V>();
106                                    }
107    
108                                    V value = null;
109    
110                                    value = (V)SerializableUtil.deserialize(rs.getBytes(_VALUE));
111    
112                                    values.add(value);
113                            }
114                    }
115                    catch (Exception e) {
116                            throw new RuntimeException(e);
117                    }
118                    finally {
119                            DataAccess.cleanUp(con, ps, rs);
120                    }
121    
122                    return values;
123            }
124    
125            public boolean isEmpty() {
126                    int count = _getCount(null, null);
127    
128                    if (count == 0) {
129                            return true;
130                    }
131                    else {
132                            return false;
133                    }
134            }
135    
136            public Set<K> keySet() {
137                    Connection con = null;
138                    PreparedStatement ps = null;
139                    ResultSet rs = null;
140    
141                    Set<K> keys = null;
142    
143                    try {
144                            con = _getConnection();
145    
146                            ps = con.prepareStatement("SELECT DISTINCT (key_) FROM Map ");
147    
148                            rs = ps.executeQuery();
149    
150                            while (rs.next()) {
151                                    if (keys == null) {
152                                            keys = new HashSet<K>();
153                                    }
154    
155                                    K key = null;
156    
157                                    key = (K)SerializableUtil.deserialize(rs.getBytes(_KEY));
158    
159                                    keys.add(key);
160                            }
161                    }
162                    catch (Exception e) {
163                            throw new RuntimeException(e);
164                    }
165                    finally {
166                            DataAccess.cleanUp(con, ps, rs);
167                    }
168    
169                    return keys;
170            }
171    
172            public V put(K key, V value) {
173                    if ((key == null) || (value == null)) {
174                            return null;
175                    }
176    
177                    if (_getCount(key, value) == 0) {
178                            Connection con = null;
179                            PreparedStatement ps = null;
180    
181                            try {
182                                    con = _getConnection();
183    
184                                    ps = con.prepareStatement(
185                                            "INSERT INTO Map (key_, value_) values (?, ?)");
186    
187                                    ps.setBytes(1, SerializableUtil.serialize(key));
188                                    ps.setBytes(2, SerializableUtil.serialize(value));
189    
190                                    ps.execute();
191                            }
192                            catch (Exception e) {
193                                    throw new RuntimeException(e);
194                            }
195                            finally {
196                                    DataAccess.cleanUp(con, ps);
197                            }
198                    }
199    
200                    return value;
201            }
202    
203            public Set<V> putAll(K key, Collection<? extends V> values) {
204                    Set<V> curValues = getAll(key);
205    
206                    if ((values == null) || values.isEmpty()) {
207                            return curValues;
208                    }
209    
210                    if (curValues == null) {
211                            values = new HashSet<V>();
212                    }
213    
214                    for (V value: values) {
215                            if (!curValues.contains(value)) {
216                                    curValues.add(value);
217    
218                                    put(key, value);
219                            }
220                    }
221    
222                    return curValues;
223            }
224    
225            public V remove(Object key) {
226                    Connection con = null;
227                    PreparedStatement ps = null;
228                    ResultSet rs = null;
229    
230                    V firstValue = null;
231    
232                    try {
233                            con = _getConnection();
234    
235                            ps = con.prepareStatement("SELECT value_ FROM Map WHERE key_ = ?");
236    
237                            ps.setBytes(1, SerializableUtil.serialize(key));
238    
239                            rs = ps.executeQuery();
240    
241                            if (rs.next()) {
242                                    firstValue = (V)SerializableUtil.deserialize(
243                                            rs.getBytes(_VALUE));
244                            }
245                    }
246                    catch (Exception e) {
247                            throw new RuntimeException(e);
248                    }
249                    finally {
250                            DataAccess.cleanUp(con, ps, rs);
251                    }
252    
253                    try {
254                            con = _getConnection();
255    
256                            ps = con.prepareStatement("DELETE FROM Map WHERE key_ = ?");
257    
258                            ps.setBytes(1, SerializableUtil.serialize(key));
259    
260                            ps.execute();
261                    }
262                    catch (Exception e) {
263                            throw new RuntimeException(e);
264                    }
265                    finally {
266                            DataAccess.cleanUp(con, ps);
267                    }
268    
269                    return firstValue;
270            }
271    
272            protected void finalize() throws Throwable {
273                    try {
274                            _deleteDatabase();
275                    }
276                    finally {
277                            super.finalize();
278                    }
279            }
280    
281            private void _createDatabase() {
282                    Connection con = null;
283    
284                    try {
285                            con = _getConnection();
286    
287                            DB db = DBFactoryUtil.getDB(DB.TYPE_HYPERSONIC);
288    
289                            db.runSQL(con, _CREATE_SQL);
290                    }
291                    catch (Exception e) {
292                            throw new RuntimeException(e);
293                    }
294                    finally {
295                            DataAccess.cleanUp(con);
296                    }
297            }
298    
299            private void _deleteDatabase() throws Throwable {
300                    File[] files = new File[] {
301                            new File(_fileName + ".properties"),
302                            new File(_fileName + ".script"),
303                            new File(_fileName + ".log"),
304                            new File(_fileName + ".data"),
305                            new File(_fileName + ".backup")
306                    };
307    
308                    for (File file : files) {
309                            if (file.exists()) {
310                                    file.delete();
311                            }
312                    }
313            }
314    
315            private Connection _getConnection() throws Exception {
316                    return DriverManager.getConnection(
317                            "jdbc:hsqldb:file:" + _fileName, "sa", "");
318            }
319    
320            private int _getCount(K key, V value) {
321                    Connection con = null;
322                    PreparedStatement ps = null;
323                    ResultSet rs = null;
324    
325                    try {
326                            con = _getConnection();
327    
328                            String sql = "SELECT count(*) FROM Map ";
329    
330                            if ((key != null) && (value != null)) {
331                                    sql += "WHERE key_ = ? AND value_ = ?";
332    
333                                    ps = con.prepareStatement(sql);
334    
335                                    ps.setBytes(1, SerializableUtil.serialize(key));
336                                    ps.setBytes(2, SerializableUtil.serialize(value));
337                            }
338                            else if (key != null) {
339                                    sql += "WHERE key_ = ?";
340    
341                                    ps = con.prepareStatement(sql);
342    
343                                    ps.setBytes(1, SerializableUtil.serialize(key));
344                            }
345                            else if (value != null) {
346                                    sql += "WHERE value_ = ?";
347    
348                                    ps = con.prepareStatement(sql);
349    
350                                    ps.setBytes(1, SerializableUtil.serialize(value));
351                            }
352                            else {
353                                    ps = con.prepareStatement(sql);
354                            }
355    
356                            rs = ps.executeQuery();
357    
358                            rs.next();
359    
360                            return rs.getInt(1);
361                    }
362                    catch (Exception e) {
363                            throw new RuntimeException(e);
364                    }
365                    finally {
366                            DataAccess.cleanUp(con, ps, rs);
367                    }
368            }
369    
370            private static final String _CREATE_SQL =
371                    "CREATE TABLE Map (key_ BLOB not null, value_ BLOB not null, primary " +
372                            "key (key_, value_))";
373    
374            private static final String _KEY = "key_";
375    
376            private static final String _VALUE = "value_";
377    
378            private String _fileName;
379    
380    }