1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.util;
24  
25  import com.liferay.portal.kernel.dao.db.DB;
26  import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
27  import com.liferay.portal.kernel.dao.jdbc.DataAccess;
28  import com.liferay.portal.kernel.util.FileUtil;
29  import com.liferay.portal.kernel.util.MultiValueMap;
30  import com.liferay.portal.kernel.util.SerializableUtil;
31  
32  import java.io.File;
33  import java.io.Serializable;
34  
35  import java.sql.Connection;
36  import java.sql.DriverManager;
37  import java.sql.PreparedStatement;
38  import java.sql.ResultSet;
39  
40  import java.util.Collection;
41  import java.util.HashSet;
42  import java.util.Set;
43  
44  /**
45   * <a href="FileMultiValueMap.java.html"><b><i>View Source</i></b></a>
46   *
47   * @author Alexander Chow
48   */
49  public class FileMultiValueMap<K extends Serializable, V extends Serializable>
50      extends MultiValueMap<K, V> {
51  
52      public FileMultiValueMap() {
53          _fileName = FileUtil.createTempFileName();
54  
55          try {
56              Class.forName("org.hsqldb.jdbcDriver");
57          }
58          catch (Exception e) {
59              throw new RuntimeException(e);
60          }
61  
62          _createDatabase();
63      }
64  
65      public void clear() {
66          try {
67              _deleteDatabase();
68              _createDatabase();
69          }
70          catch (Throwable t) {
71              throw new RuntimeException(t);
72          }
73      }
74  
75      public boolean containsKey(Object key) {
76          int count = _getCount((K)key, null);
77  
78          if (count > 0) {
79              return true;
80          }
81          else {
82              return false;
83          }
84      }
85  
86      public boolean containsValue(Object value) {
87          int count = _getCount(null, (V)value);
88  
89          if (count > 0) {
90              return true;
91          }
92          else {
93              return false;
94          }
95      }
96  
97      public Set<V> getAll(Object key) {
98          Connection con = null;
99          PreparedStatement ps = null;
100         ResultSet rs = null;
101 
102         Set<V> values = null;
103 
104         try {
105             con = _getConnection();
106 
107             ps = con.prepareStatement("SELECT value_ FROM Map WHERE key_ = ?");
108 
109             ps.setBytes(1, SerializableUtil.serialize(key));
110 
111             rs = ps.executeQuery();
112 
113             while (rs.next()) {
114                 if (values == null) {
115                     values = new HashSet<V>();
116                 }
117 
118                 V value = null;
119 
120                 value = (V)SerializableUtil.deserialize(rs.getBytes(_VALUE));
121 
122                 values.add(value);
123             }
124         }
125         catch (Exception e) {
126             throw new RuntimeException(e);
127         }
128         finally {
129             DataAccess.cleanUp(con, ps, rs);
130         }
131 
132         return values;
133     }
134 
135     public boolean isEmpty() {
136         int count = _getCount(null, null);
137 
138         if (count == 0) {
139             return true;
140         }
141         else {
142             return false;
143         }
144     }
145 
146     public Set<K> keySet() {
147         Connection con = null;
148         PreparedStatement ps = null;
149         ResultSet rs = null;
150 
151         Set<K> keys = null;
152 
153         try {
154             con = _getConnection();
155 
156             ps = con.prepareStatement("SELECT DISTINCT (key_) FROM Map ");
157 
158             rs = ps.executeQuery();
159 
160             while (rs.next()) {
161                 if (keys == null) {
162                     keys = new HashSet<K>();
163                 }
164 
165                 K key = null;
166 
167                 key = (K)SerializableUtil.deserialize(rs.getBytes(_KEY));
168 
169                 keys.add(key);
170             }
171         }
172         catch (Exception e) {
173             throw new RuntimeException(e);
174         }
175         finally {
176             DataAccess.cleanUp(con, ps, rs);
177         }
178 
179         return keys;
180     }
181 
182     public V put(K key, V value) {
183         if ((key == null) || (value == null)) {
184             return null;
185         }
186 
187         if (_getCount(key, value) == 0) {
188             Connection con = null;
189             PreparedStatement ps = null;
190 
191             try {
192                 con = _getConnection();
193 
194                 ps = con.prepareStatement(
195                     "INSERT INTO Map (key_, value_) values (?, ?)");
196 
197                 ps.setBytes(1, SerializableUtil.serialize(key));
198                 ps.setBytes(2, SerializableUtil.serialize(value));
199 
200                 ps.execute();
201             }
202             catch (Exception e) {
203                 throw new RuntimeException(e);
204             }
205             finally {
206                 DataAccess.cleanUp(con, ps);
207             }
208         }
209 
210         return value;
211     }
212 
213     public Set<V> putAll(K key, Collection<? extends V> values) {
214         Set<V> curValues = getAll(key);
215 
216         if ((values == null) || values.isEmpty()) {
217             return curValues;
218         }
219 
220         if (curValues == null) {
221             values = new HashSet<V>();
222         }
223 
224         for (V value: values) {
225             if (!curValues.contains(value)) {
226                 curValues.add(value);
227 
228                 put(key, value);
229             }
230         }
231 
232         return curValues;
233     }
234 
235     public V remove(Object key) {
236         Connection con = null;
237         PreparedStatement ps = null;
238         ResultSet rs = null;
239 
240         V firstValue = null;
241 
242         try {
243             con = _getConnection();
244 
245             ps = con.prepareStatement("SELECT value_ FROM Map WHERE key_ = ?");
246 
247             ps.setBytes(1, SerializableUtil.serialize(key));
248 
249             rs = ps.executeQuery();
250 
251             if (rs.next()) {
252                 firstValue = (V)SerializableUtil.deserialize(
253                     rs.getBytes(_VALUE));
254             }
255         }
256         catch (Exception e) {
257             throw new RuntimeException(e);
258         }
259         finally {
260             DataAccess.cleanUp(con, ps, rs);
261         }
262 
263         try {
264             con = _getConnection();
265 
266             ps = con.prepareStatement("DELETE FROM Map WHERE key_ = ?");
267 
268             ps.setBytes(1, SerializableUtil.serialize(key));
269 
270             ps.execute();
271         }
272         catch (Exception e) {
273             throw new RuntimeException(e);
274         }
275         finally {
276             DataAccess.cleanUp(con, ps);
277         }
278 
279         return firstValue;
280     }
281 
282     protected void finalize() throws Throwable {
283         try {
284             _deleteDatabase();
285         }
286         finally {
287             super.finalize();
288         }
289     }
290 
291     private void _createDatabase() {
292         Connection con = null;
293 
294         try {
295             con = _getConnection();
296 
297             DB db = DBFactoryUtil.getDB(DB.TYPE_HYPERSONIC);
298 
299             db.runSQL(con, _CREATE_SQL);
300         }
301         catch (Exception e) {
302             throw new RuntimeException(e);
303         }
304         finally {
305             DataAccess.cleanUp(con);
306         }
307     }
308 
309     private void _deleteDatabase() throws Throwable {
310         File[] files = new File[] {
311             new File(_fileName + ".properties"),
312             new File(_fileName + ".script"),
313             new File(_fileName + ".log"),
314             new File(_fileName + ".data"),
315             new File(_fileName + ".backup")
316         };
317 
318         for (File file : files) {
319             if (file.exists()) {
320                 file.delete();
321             }
322         }
323     }
324 
325     private Connection _getConnection() throws Exception {
326         return DriverManager.getConnection(
327             "jdbc:hsqldb:file:" + _fileName, "sa", "");
328     }
329 
330     private int _getCount(K key, V value) {
331         Connection con = null;
332         PreparedStatement ps = null;
333         ResultSet rs = null;
334 
335         try {
336             con = _getConnection();
337 
338             String sql = "SELECT count(*) FROM Map ";
339 
340             if ((key != null) && (value != null)) {
341                 sql += "WHERE key_ = ? AND value_ = ?";
342 
343                 ps = con.prepareStatement(sql);
344 
345                 ps.setBytes(1, SerializableUtil.serialize(key));
346                 ps.setBytes(2, SerializableUtil.serialize(value));
347             }
348             else if (key != null) {
349                 sql += "WHERE key_ = ?";
350 
351                 ps = con.prepareStatement(sql);
352 
353                 ps.setBytes(1, SerializableUtil.serialize(key));
354             }
355             else if (value != null) {
356                 sql += "WHERE value_ = ?";
357 
358                 ps = con.prepareStatement(sql);
359 
360                 ps.setBytes(1, SerializableUtil.serialize(value));
361             }
362             else {
363                 ps = con.prepareStatement(sql);
364             }
365 
366             rs = ps.executeQuery();
367 
368             rs.next();
369 
370             return rs.getInt(1);
371         }
372         catch (Exception e) {
373             throw new RuntimeException(e);
374         }
375         finally {
376             DataAccess.cleanUp(con, ps, rs);
377         }
378     }
379 
380     private static final String _CREATE_SQL =
381         "CREATE TABLE Map (key_ BLOB not null, value_ BLOB not null, primary " +
382             "key (key_, value_))";
383 
384     private static final String _KEY = "key_";
385 
386     private static final String _VALUE = "value_";
387 
388     private String _fileName;
389 
390 }