001 package org.apache.ojb.broker.metadata;
002
003 /* Copyright 2002-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import org.apache.commons.lang.SerializationUtils;
019 import org.apache.commons.lang.SystemUtils;
020 import org.apache.ojb.broker.PBKey;
021 import org.apache.ojb.broker.util.logging.Logger;
022 import org.apache.ojb.broker.util.logging.LoggerFactory;
023
024 import java.io.Serializable;
025 import java.util.ArrayList;
026 import java.util.HashMap;
027 import java.util.Hashtable;
028 import java.util.Iterator;
029 import java.util.List;
030
031 import javax.sql.DataSource;
032
033 public class ConnectionRepository implements Serializable, XmlCapable
034 {
035 private static final long serialVersionUID = -5581126412817848887L;
036 private static Logger log = LoggerFactory.getLogger(ConnectionRepository.class);
037
038 private HashMap jcdMap;
039 private Hashtable jcdAliasToPBKeyMap;
040 private JdbcMetadataUtils utils;
041
042 public ConnectionRepository()
043 {
044 jcdMap = new HashMap();
045 jcdAliasToPBKeyMap = new Hashtable();
046 utils = new JdbcMetadataUtils();
047 }
048
049 /**
050 * Returns the matching {@link JdbcConnectionDescriptor}
051 * or <code>null</code> if no descriptor could be found. The user name
052 * and pass word will be set to match the supplied </code>PBKey</code>
053 * object. If the original user name and pass word are desired, the PBKey
054 * should be obtained with {@link #getStandardPBKeyForJcdAlias(String)}.
055 */
056 public JdbcConnectionDescriptor getDescriptor(PBKey pbKey)
057 {
058 JdbcConnectionDescriptor result = (JdbcConnectionDescriptor) jcdMap.get(pbKey);
059 if (result == null)
060 {
061 result = deepCopyOfFirstFound(pbKey.getAlias());
062 if (result != null)
063 {
064 result.setUserName(pbKey.getUser());
065 result.setPassWord(pbKey.getPassword());
066 // this build connection descriptor could not be the default connection
067 result.setDefaultConnection(false);
068 log.info("Automatic create of new jdbc-connection-descriptor for PBKey " + pbKey);
069 addDescriptor(result);
070 }
071 else
072 {
073 log.info("Could not find " + JdbcConnectionDescriptor.class.getName() + " for PBKey " + pbKey);
074 }
075 }
076 return result;
077 }
078
079 /**
080 * Returns a deep copy of the first found connection descriptor
081 * with the given <code>jcdAlias</code> name or <code>null</code>
082 * if none found.
083 */
084 private JdbcConnectionDescriptor deepCopyOfFirstFound(String jcdAlias)
085 {
086 Iterator it = jcdMap.values().iterator();
087 JdbcConnectionDescriptor jcd;
088 while (it.hasNext())
089 {
090 jcd = (JdbcConnectionDescriptor) it.next();
091 if (jcdAlias.equals(jcd.getJcdAlias()))
092 {
093 return (JdbcConnectionDescriptor) SerializationUtils.clone(jcd);
094 }
095 }
096 return null;
097 }
098
099 /**
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 }