package org.apache.ojb.broker.metadata;
/* Copyright 2002-2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.ojb.broker.PBKey;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import javax.sql.DataSource;
public class ConnectionRepository implements Serializable, XmlCapable
{
private static final long serialVersionUID = -5581126412817848887L;
private static Logger log = LoggerFactory.getLogger(ConnectionRepository.class);
private HashMap jcdMap;
private Hashtable jcdAliasToPBKeyMap;
private JdbcMetadataUtils utils;
public ConnectionRepository()
{
jcdMap = new HashMap();
jcdAliasToPBKeyMap = new Hashtable();
utils = new JdbcMetadataUtils();
}
/**
* Returns the matching {@link JdbcConnectionDescriptor}
* or <code>null</code> if no descriptor could be found. The user name
* and pass word will be set to match the supplied </code>PBKey</code>
* object. If the original user name and pass word are desired, the PBKey
* should be obtained with {@link #getStandardPBKeyForJcdAlias(String)}.
*/
public JdbcConnectionDescriptor getDescriptor(PBKey pbKey)
{
JdbcConnectionDescriptor result = (JdbcConnectionDescriptor) jcdMap.get(pbKey);
if (result == null)
{
result = deepCopyOfFirstFound(pbKey.getAlias());
if (result != null)
{
result.setUserName(pbKey.getUser());
result.setPassWord(pbKey.getPassword());
// this build connection descriptor could not be the default connection
result.setDefaultConnection(false);
log.info("Automatic create of new jdbc-connection-descriptor for PBKey " + pbKey);
addDescriptor(result);
}
else
{
log.info("Could not find " + JdbcConnectionDescriptor.class.getName() + " for PBKey " + pbKey);
}
}
return result;
}
/**
* Returns a deep copy of the first found connection descriptor
* with the given <code>jcdAlias</code> name or <code>null</code>
* if none found.
*/
private JdbcConnectionDescriptor deepCopyOfFirstFound(String jcdAlias)
{
Iterator it = jcdMap.values().iterator();
JdbcConnectionDescriptor jcd;
while (it.hasNext())
{
jcd = (JdbcConnectionDescriptor) it.next();
if (jcdAlias.equals(jcd.getJcdAlias()))
{
return (JdbcConnectionDescriptor) SerializationUtils.clone(jcd);
}
}
return null;
}
/**
* Return the matching {@link org.apache.ojb.broker.PBKey} for
* the given jcdAlias name, or <code>null</code> if no match
* was found.
*/
public PBKey getStandardPBKeyForJcdAlias(String jcdAlias)
{
return (PBKey) jcdAliasToPBKeyMap.get(jcdAlias);
}
/**
* Add a new {@link JdbcConnectionDescriptor}.
*/
public void addDescriptor(JdbcConnectionDescriptor jcd)
{
synchronized (jcdMap)
{
if (jcdMap.containsKey(jcd.getPBKey()))
{
throw new MetadataException("Found duplicate connection descriptor using PBKey " +
jcd.getPBKey() + ", remove the old descriptor first, before add the new one. " + jcd);
}
jcdMap.put(jcd.getPBKey(), jcd);
// only if the jcdAlias was not found, put the new PBKey,
// because we don't want to replace the original PBKey with
// automatic generated descriptors PBKey's - see method getDescriptor(PBKey key)
if (!jcdAliasToPBKeyMap.containsKey(jcd.getJcdAlias()))
{
jcdAliasToPBKeyMap.put(jcd.getJcdAlias(), jcd.getPBKey());
}
if (log.isDebugEnabled()) log.debug("New descriptor was added: " + jcd);
}
}
/**
* Creates and adds a new connection descriptor for the given JDBC connection url.
* This method tries to guess the platform to be used, but it should be checked
* afterwards nonetheless using the {@link JdbcConnectionDescriptor#getDbms()} method.
* For properties that are not part of the url, the following standard values are
* explicitly set:
* <ul>
* <li>jdbc level = 2.0</li>
* </ul>
*
* @param jcdAlias The connection alias for the created connection; if 'default' is used,
* then the new descriptor will become the default connection descriptor
* @param jdbcDriver The fully qualified jdbc driver name
* @param jdbcConnectionUrl The connection url of the form '[protocol]:[sub protocol]:{database-specific path]'
* where protocol is usually 'jdbc'
* @param username The user name (can be <code>null</code>)
* @param password The password (can be <code>null</code>)
* @return The created connection descriptor
* @see JdbcConnectionDescriptor#getDbms()
*/
public JdbcConnectionDescriptor addDescriptor(String jcdAlias, String jdbcDriver, String jdbcConnectionUrl, String username, String password)
{
JdbcConnectionDescriptor jcd = new JdbcConnectionDescriptor();
HashMap props = utils.parseConnectionUrl(jdbcConnectionUrl);
jcd.setJcdAlias(jcdAlias);
jcd.setProtocol((String)props.get(JdbcMetadataUtils.PROPERTY_PROTOCOL));
jcd.setSubProtocol((String)props.get(JdbcMetadataUtils.PROPERTY_SUBPROTOCOL));
jcd.setDbAlias((String)props.get(JdbcMetadataUtils.PROPERTY_DBALIAS));
String platform = utils.findPlatformFor(jcd.getSubProtocol(), jdbcDriver);
jcd.setDbms(platform);
jcd.setJdbcLevel(2.0);
jcd.setDriver(jdbcDriver);
if (username != null)
{
jcd.setUserName(username);
jcd.setPassWord(password);
}
if ("default".equals(jcdAlias))
{
jcd.setDefaultConnection(true);
// arminw: MM will search for the default key
// MetadataManager.getInstance().setDefaultPBKey(jcd.getPBKey());
}
addDescriptor(jcd);
return jcd;
}
/**
* Creates and adds a new connection descriptor for the given JDBC data source.
* This method tries to guess the platform to be used, but it should be checked
* afterwards nonetheless using the {@link JdbcConnectionDescriptor#getDbms()} method.
* Note that the descriptor won't have a value for the driver because it is not possible
* to retrieve the driver classname from the data source.
*
* @param jcdAlias The connection alias for the created connection; if 'default' is used,
* then the new descriptor will become the default connection descriptor
* @param dataSource The data source
* @param username The user name (can be <code>null</code>)
* @param password The password (can be <code>null</code>)
* @return The created connection descriptor
* @see JdbcConnectionDescriptor#getDbms()
*/
public JdbcConnectionDescriptor addDescriptor(String jcdAlias, DataSource dataSource, String username, String password)
{
JdbcConnectionDescriptor jcd = new JdbcConnectionDescriptor();
jcd.setJcdAlias(jcdAlias);
jcd.setDataSource(dataSource);
if (username != null)
{
jcd.setUserName(username);
jcd.setPassWord(password);
}
utils.fillJCDFromDataSource(jcd, dataSource, username, password);
if ("default".equals(jcdAlias))
{
jcd.setDefaultConnection(true);
// arminw: MM will search for the default key
// MetadataManager.getInstance().setDefaultPBKey(jcd.getPBKey());
}
addDescriptor(jcd);
return jcd;
}
/**
* Remove a descriptor.
* @param validKey This could be the {@link JdbcConnectionDescriptor}
* itself, or the associated {@link JdbcConnectionDescriptor#getPBKey PBKey}.
*/
public void removeDescriptor(Object validKey)
{
PBKey pbKey;
if (validKey instanceof PBKey)
{
pbKey = (PBKey) validKey;
}
else if (validKey instanceof JdbcConnectionDescriptor)
{
pbKey = ((JdbcConnectionDescriptor) validKey).getPBKey();
}
else
{
throw new MetadataException("Could not remove descriptor, given object was no vaild key: " +
validKey);
}
Object removed = null;
synchronized (jcdMap)
{
removed = jcdMap.remove(pbKey);
jcdAliasToPBKeyMap.remove(pbKey.getAlias());
}
log.info("Remove descriptor: " + removed);
}
/**
* Return a deep copy of all managed {@link JdbcConnectionDescriptor}.
*/
public List getAllDescriptor()
{
return (List) SerializationUtils.clone(new ArrayList(jcdMap.values()));
}
public String toXML()
{
String eol = SystemUtils.LINE_SEPARATOR;
// use copy to avoid sync problems
HashMap map = (HashMap) jcdMap.clone();
StringBuffer buf = new StringBuffer();
Iterator it = map.values().iterator();
while (it.hasNext())
{
JdbcConnectionDescriptor jcd = (JdbcConnectionDescriptor) it.next();
buf.append(jcd.toXML());
buf.append(eol);
}
return buf.toString();
}
}