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