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