1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.table; |
7 | |
8 | import java.sql.Connection; |
9 | import java.sql.SQLException; |
10 | import java.util.HashMap; |
11 | import org.h2.message.DbException; |
12 | import org.h2.util.JdbcUtils; |
13 | import org.h2.util.StringUtils; |
14 | import org.h2.util.Utils; |
15 | |
16 | /** |
17 | * A connection for a linked table. The same connection may be used for multiple |
18 | * tables, that means a connection may be shared. |
19 | */ |
20 | public class TableLinkConnection { |
21 | |
22 | /** |
23 | * The map where the link is kept. |
24 | */ |
25 | private final HashMap<TableLinkConnection, TableLinkConnection> map; |
26 | |
27 | /** |
28 | * The connection information. |
29 | */ |
30 | private final String driver, url, user, password; |
31 | |
32 | /** |
33 | * The database connection. |
34 | */ |
35 | private Connection conn; |
36 | |
37 | /** |
38 | * How many times the connection is used. |
39 | */ |
40 | private int useCounter; |
41 | |
42 | private TableLinkConnection( |
43 | HashMap<TableLinkConnection, TableLinkConnection> map, |
44 | String driver, String url, String user, String password) { |
45 | this.map = map; |
46 | this.driver = driver; |
47 | this.url = url; |
48 | this.user = user; |
49 | this.password = password; |
50 | } |
51 | |
52 | /** |
53 | * Open a new connection. |
54 | * |
55 | * @param map the map where the connection should be stored |
56 | * (if shared connections are enabled). |
57 | * @param driver the JDBC driver class name |
58 | * @param url the database URL |
59 | * @param user the user name |
60 | * @param password the password |
61 | * @param shareLinkedConnections if connections should be shared |
62 | * @return a connection |
63 | */ |
64 | public static TableLinkConnection open( |
65 | HashMap<TableLinkConnection, TableLinkConnection> map, |
66 | String driver, String url, String user, String password, |
67 | boolean shareLinkedConnections) { |
68 | TableLinkConnection t = new TableLinkConnection(map, driver, url, |
69 | user, password); |
70 | if (!shareLinkedConnections) { |
71 | t.open(); |
72 | return t; |
73 | } |
74 | synchronized (map) { |
75 | TableLinkConnection result = map.get(t); |
76 | if (result == null) { |
77 | t.open(); |
78 | // put the connection in the map after is has been opened, |
79 | // when we know it works |
80 | map.put(t, t); |
81 | result = t; |
82 | } |
83 | result.useCounter++; |
84 | return result; |
85 | } |
86 | } |
87 | |
88 | private void open() { |
89 | try { |
90 | conn = JdbcUtils.getConnection(driver, url, user, password); |
91 | } catch (SQLException e) { |
92 | throw DbException.convert(e); |
93 | } |
94 | } |
95 | |
96 | @Override |
97 | public int hashCode() { |
98 | return Utils.hashCode(driver) |
99 | ^ Utils.hashCode(url) |
100 | ^ Utils.hashCode(user) |
101 | ^ Utils.hashCode(password); |
102 | } |
103 | |
104 | @Override |
105 | public boolean equals(Object o) { |
106 | if (o instanceof TableLinkConnection) { |
107 | TableLinkConnection other = (TableLinkConnection) o; |
108 | return StringUtils.equals(driver, other.driver) |
109 | && StringUtils.equals(url, other.url) |
110 | && StringUtils.equals(user, other.user) |
111 | && StringUtils.equals(password, other.password); |
112 | } |
113 | return false; |
114 | } |
115 | |
116 | /** |
117 | * Get the connection. |
118 | * This method and methods on the statement must be |
119 | * synchronized on this object. |
120 | * |
121 | * @return the connection |
122 | */ |
123 | Connection getConnection() { |
124 | return conn; |
125 | } |
126 | |
127 | /** |
128 | * Closes the connection if this is the last link to it. |
129 | * |
130 | * @param force if the connection needs to be closed even if it is still |
131 | * used elsewhere (for example, because the connection is broken) |
132 | */ |
133 | void close(boolean force) { |
134 | boolean actuallyClose = false; |
135 | synchronized (map) { |
136 | if (--useCounter <= 0 || force) { |
137 | actuallyClose = true; |
138 | map.remove(this); |
139 | } |
140 | } |
141 | if (actuallyClose) { |
142 | JdbcUtils.closeSilently(conn); |
143 | } |
144 | } |
145 | |
146 | } |