1 package org.apache.ojb.broker.metadata;
2
3 /* Copyright 2002-2005 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 import org.apache.commons.lang.SerializationUtils;
19 import org.apache.commons.lang.SystemUtils;
20 import org.apache.ojb.broker.PBKey;
21 import org.apache.ojb.broker.util.logging.Logger;
22 import org.apache.ojb.broker.util.logging.LoggerFactory;
23
24 import java.io.Serializable;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.Hashtable;
28 import java.util.Iterator;
29 import java.util.List;
30
31 import javax.sql.DataSource;
32
33 public class ConnectionRepository implements Serializable, XmlCapable
34 {
35 private static final long serialVersionUID = -5581126412817848887L;
36 private static Logger log = LoggerFactory.getLogger(ConnectionRepository.class);
37
38 private HashMap jcdMap;
39 private Hashtable jcdAliasToPBKeyMap;
40 private JdbcMetadataUtils utils;
41
42 public ConnectionRepository()
43 {
44 jcdMap = new HashMap();
45 jcdAliasToPBKeyMap = new Hashtable();
46 utils = new JdbcMetadataUtils();
47 }
48
49 /**
50 * Returns the matching {@link JdbcConnectionDescriptor}
51 * or <code>null</code> if no descriptor could be found. The user name
52 * and pass word will be set to match the supplied </code>PBKey</code>
53 * object. If the original user name and pass word are desired, the PBKey
54 * should be obtained with {@link #getStandardPBKeyForJcdAlias(String)}.
55 */
56 public JdbcConnectionDescriptor getDescriptor(PBKey pbKey)
57 {
58 JdbcConnectionDescriptor result = (JdbcConnectionDescriptor) jcdMap.get(pbKey);
59 if (result == null)
60 {
61 result = deepCopyOfFirstFound(pbKey.getAlias());
62 if (result != null)
63 {
64 result.setUserName(pbKey.getUser());
65 result.setPassWord(pbKey.getPassword());
66 // this build connection descriptor could not be the default connection
67 result.setDefaultConnection(false);
68 log.info("Automatic create of new jdbc-connection-descriptor for PBKey " + pbKey);
69 addDescriptor(result);
70 }
71 else
72 {
73 log.info("Could not find " + JdbcConnectionDescriptor.class.getName() + " for PBKey " + pbKey);
74 }
75 }
76 return result;
77 }
78
79 /**
80 * Returns a deep copy of the first found connection descriptor
81 * with the given <code>jcdAlias</code> name or <code>null</code>
82 * if none found.
83 */
84 private JdbcConnectionDescriptor deepCopyOfFirstFound(String jcdAlias)
85 {
86 Iterator it = jcdMap.values().iterator();
87 JdbcConnectionDescriptor jcd;
88 while (it.hasNext())
89 {
90 jcd = (JdbcConnectionDescriptor) it.next();
91 if (jcdAlias.equals(jcd.getJcdAlias()))
92 {
93 return (JdbcConnectionDescriptor) SerializationUtils.clone(jcd);
94 }
95 }
96 return null;
97 }
98
99 /**
100 * Return the matching {@link org.apache.ojb.broker.PBKey} for
101 * the given jcdAlias name, or <code>null</code> if no match
102 * was found.
103 */
104 public PBKey getStandardPBKeyForJcdAlias(String jcdAlias)
105 {
106 return (PBKey) jcdAliasToPBKeyMap.get(jcdAlias);
107 }
108
109 /**
110 * Add a new {@link JdbcConnectionDescriptor}.
111 */
112 public void addDescriptor(JdbcConnectionDescriptor jcd)
113 {
114 synchronized (jcdMap)
115 {
116 if (jcdMap.containsKey(jcd.getPBKey()))
117 {
118 throw new MetadataException("Found duplicate connection descriptor using PBKey " +
119 jcd.getPBKey() + ", remove the old descriptor first, before add the new one. " + jcd);
120 }
121 jcdMap.put(jcd.getPBKey(), jcd);
122 // only if the jcdAlias was not found, put the new PBKey,
123 // because we don't want to replace the original PBKey with
124 // automatic generated descriptors PBKey's - see method getDescriptor(PBKey key)
125 if (!jcdAliasToPBKeyMap.containsKey(jcd.getJcdAlias()))
126 {
127 jcdAliasToPBKeyMap.put(jcd.getJcdAlias(), jcd.getPBKey());
128 }
129 if (log.isDebugEnabled()) log.debug("New descriptor was added: " + jcd);
130 }
131 }
132
133 /**
134 * Creates and adds a new connection descriptor for the given JDBC connection url.
135 * This method tries to guess the platform to be used, but it should be checked
136 * afterwards nonetheless using the {@link JdbcConnectionDescriptor#getDbms()} method.
137 * For properties that are not part of the url, the following standard values are
138 * explicitly set:
139 * <ul>
140 * <li>jdbc level = 2.0</li>
141 * </ul>
142 *
143 * @param jcdAlias The connection alias for the created connection; if 'default' is used,
144 * then the new descriptor will become the default connection descriptor
145 * @param jdbcDriver The fully qualified jdbc driver name
146 * @param jdbcConnectionUrl The connection url of the form '[protocol]:[sub protocol]:{database-specific path]'
147 * where protocol is usually 'jdbc'
148 * @param username The user name (can be <code>null</code>)
149 * @param password The password (can be <code>null</code>)
150 * @return The created connection descriptor
151 * @see JdbcConnectionDescriptor#getDbms()
152 */
153 public JdbcConnectionDescriptor addDescriptor(String jcdAlias, String jdbcDriver, String jdbcConnectionUrl, String username, String password)
154 {
155 JdbcConnectionDescriptor jcd = new JdbcConnectionDescriptor();
156 HashMap props = utils.parseConnectionUrl(jdbcConnectionUrl);
157
158 jcd.setJcdAlias(jcdAlias);
159 jcd.setProtocol((String)props.get(JdbcMetadataUtils.PROPERTY_PROTOCOL));
160 jcd.setSubProtocol((String)props.get(JdbcMetadataUtils.PROPERTY_SUBPROTOCOL));
161 jcd.setDbAlias((String)props.get(JdbcMetadataUtils.PROPERTY_DBALIAS));
162
163 String platform = utils.findPlatformFor(jcd.getSubProtocol(), jdbcDriver);
164
165 jcd.setDbms(platform);
166 jcd.setJdbcLevel(2.0);
167 jcd.setDriver(jdbcDriver);
168 if (username != null)
169 {
170 jcd.setUserName(username);
171 jcd.setPassWord(password);
172 }
173 if ("default".equals(jcdAlias))
174 {
175 jcd.setDefaultConnection(true);
176 // arminw: MM will search for the default key
177 // MetadataManager.getInstance().setDefaultPBKey(jcd.getPBKey());
178 }
179
180 addDescriptor(jcd);
181 return jcd;
182 }
183
184 /**
185 * Creates and adds a new connection descriptor for the given JDBC data source.
186 * This method tries to guess the platform to be used, but it should be checked
187 * afterwards nonetheless using the {@link JdbcConnectionDescriptor#getDbms()} method.
188 * Note that the descriptor won't have a value for the driver because it is not possible
189 * to retrieve the driver classname from the data source.
190 *
191 * @param jcdAlias The connection alias for the created connection; if 'default' is used,
192 * then the new descriptor will become the default connection descriptor
193 * @param dataSource The data source
194 * @param username The user name (can be <code>null</code>)
195 * @param password The password (can be <code>null</code>)
196 * @return The created connection descriptor
197 * @see JdbcConnectionDescriptor#getDbms()
198 */
199 public JdbcConnectionDescriptor addDescriptor(String jcdAlias, DataSource dataSource, String username, String password)
200 {
201 JdbcConnectionDescriptor jcd = new JdbcConnectionDescriptor();
202
203 jcd.setJcdAlias(jcdAlias);
204 jcd.setDataSource(dataSource);
205 if (username != null)
206 {
207 jcd.setUserName(username);
208 jcd.setPassWord(password);
209 }
210 utils.fillJCDFromDataSource(jcd, dataSource, username, password);
211 if ("default".equals(jcdAlias))
212 {
213 jcd.setDefaultConnection(true);
214 // arminw: MM will search for the default key
215 // MetadataManager.getInstance().setDefaultPBKey(jcd.getPBKey());
216 }
217 addDescriptor(jcd);
218 return jcd;
219 }
220
221 /**
222 * Remove a descriptor.
223 * @param validKey This could be the {@link JdbcConnectionDescriptor}
224 * itself, or the associated {@link JdbcConnectionDescriptor#getPBKey PBKey}.
225 */
226 public void removeDescriptor(Object validKey)
227 {
228 PBKey pbKey;
229 if (validKey instanceof PBKey)
230 {
231 pbKey = (PBKey) validKey;
232 }
233 else if (validKey instanceof JdbcConnectionDescriptor)
234 {
235 pbKey = ((JdbcConnectionDescriptor) validKey).getPBKey();
236 }
237 else
238 {
239 throw new MetadataException("Could not remove descriptor, given object was no vaild key: " +
240 validKey);
241 }
242 Object removed = null;
243 synchronized (jcdMap)
244 {
245 removed = jcdMap.remove(pbKey);
246 jcdAliasToPBKeyMap.remove(pbKey.getAlias());
247 }
248 log.info("Remove descriptor: " + removed);
249 }
250
251 /**
252 * Return a deep copy of all managed {@link JdbcConnectionDescriptor}.
253 */
254 public List getAllDescriptor()
255 {
256 return (List) SerializationUtils.clone(new ArrayList(jcdMap.values()));
257 }
258
259 public String toXML()
260 {
261 String eol = SystemUtils.LINE_SEPARATOR;
262 // use copy to avoid sync problems
263 HashMap map = (HashMap) jcdMap.clone();
264 StringBuffer buf = new StringBuffer();
265 Iterator it = map.values().iterator();
266 while (it.hasNext())
267 {
268 JdbcConnectionDescriptor jcd = (JdbcConnectionDescriptor) it.next();
269 buf.append(jcd.toXML());
270 buf.append(eol);
271 }
272 return buf.toString();
273 }
274 }