View Javadoc

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 }