/*
Copyright (C) 2003 EBI, GRL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ensembl.mart.lib.config;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import org.ensembl.mart.lib.DetailedDataSource;
import org.ensembl.mart.lib.InputSourceUtil;
/**
* DSConfigAdaptor implimentation for working with MartRegistry Objects.
* @author <a href="mailto:dlondon@ebi.ac.uk">Darin London</a>
* @author <a href="mailto:craig@ebi.ac.uk">Craig Melsopp</a>
*/
public class RegistryDSConfigAdaptor extends CompositeDSConfigAdaptor {
private MartRegistry martreg; // single, underlying MartRegistry for this Adaptor
private URL url;
private DetailedDataSource dsource;
private Set martRegs = new TreeSet(); // keep a list of MartRegistry Objects pulled from RegistryLocation elements
private boolean ignoreCache = false;
private boolean includeHiddenMembers = false;
private boolean loadFully = false;
/**
* Constructs an empty RegistryDSConfigAdaptor. A URL for
* an existing MartRegistry document can be set later, using setExistingRegistryURL.
* will be validated.
* @param ignoreCache - if set to true, no caching will occur in any child adaptors specified by Location
* objects in the given MartRegistry
* @param includeHiddenMembers - if set to true, DatasetConfig objects loaded by child adaptors will include
* hidden members.
*/
public RegistryDSConfigAdaptor(boolean ignoreCache, boolean includeHiddenMembers) {
super();
this.ignoreCache = ignoreCache;
this.includeHiddenMembers = includeHiddenMembers;
}
/**
* Constructs a RegistryDSConfigAdaptor with a url containing a MartRegistry.dtd compliant XML Document.
* @param url -- URL pointing to MartRegistry.dtd compliant XML Document
* @param ignoreCache - if set to true, no caching will occur in any child adaptors specified by Location
* objects in the given MartRegistry
* @param includeHiddenMembers - if set to true, DatasetConfig objects loaded by child adaptors will include
* hidden members.
* @throws ConfigurationException if url is null, and for all underlying URL/XML parsing Exceptions
*/
public RegistryDSConfigAdaptor(URL url, boolean ignoreCache, boolean loadFully, boolean includeHiddenMembers)
throws ConfigurationException {
super();
this.ignoreCache = ignoreCache;
this.includeHiddenMembers = includeHiddenMembers;
this.loadFully = loadFully;
if (loadFully)
this.ignoreCache = true;
setRegistryURL(url);
adaptorName = url.toString();
}
public RegistryDSConfigAdaptor(
DetailedDataSource dsource,
boolean ignoreCache,
boolean includeHiddenMembers)
throws ConfigurationException {
super();
setRegistryDatasource(dsource);
this.ignoreCache = ignoreCache;
this.includeHiddenMembers = includeHiddenMembers;
adaptorName = dsource.getName();
}
/**
* Constructs a RegistryDSConfigAdaptor with an existing MartRegistry object.
* Users can set a URL to refer to this MartRegistry using setRegistryURL.
* @param martreg -- existing MartRegistry object
* @throws ConfigurationException for all underlying Exceptions
*/
public RegistryDSConfigAdaptor(MartRegistry martreg) throws ConfigurationException {
super();
this.martreg = martreg;
loadAdaptorsFromRegistry();
}
/**
* Construct a RegistryDSConfigAdaptor with an existing MartRegistry object, and its URL
* @param martreg -- existing MartRegistry object
* @param url -- url refering, or to refer to this MartRegistry object
* @throws ConfigurationException for all underlying Exceptions
*/
public RegistryDSConfigAdaptor(MartRegistry martreg, URL url,
boolean ignoreCache,
boolean loadFully,
boolean includeHiddenMembers) throws ConfigurationException {
super();
this.martreg = martreg;
this.ignoreCache = ignoreCache;
this.includeHiddenMembers = includeHiddenMembers;
this.loadFully = loadFully;
if (loadFully)
this.ignoreCache = true;
if (url != null) {
this.url = url;
adaptorName = url.toString();
}
loadAdaptorsFromRegistry();
}
public RegistryDSConfigAdaptor(MartRegistry martreg, DetailedDataSource dsource,
boolean ignoreCache,
boolean loadFully,
boolean includeHiddenMembers) throws ConfigurationException {
this.martreg = martreg;
this.includeHiddenMembers = includeHiddenMembers;
this.ignoreCache = ignoreCache;
this.loadFully = loadFully;
if (loadFully)
this.ignoreCache = true;
if (dsource != null) {
this.dsource = dsource;
adaptorName = dsource.getName();
}
loadAdaptorsFromRegistry();
}
/**
* Construct a RegistryDSConfigAdaptor with an existing DSConfigAdaptor object. Users can set
* its URL later with a call to setRegistryURL.
* @param adaptor -- adaptor to initialize this RegistryAdaptor with.
*/
public RegistryDSConfigAdaptor(DSConfigAdaptor adaptor) throws ConfigurationException {
super();
adaptors.add(adaptor);
martreg = getMartRegistry();
}
/**
* Construct a RegistryDSConfigAdaptor with an existing DSConfigAdaptor object, and its URL.
* @param adaptor -- adaptor to initialize this RegistryAdaptor with.
* @param url -- url to refer to this MartRegistry object
*/
public RegistryDSConfigAdaptor(DSConfigAdaptor adaptor, URL url) throws ConfigurationException {
super();
adaptors.add(adaptor);
if (url != null) {
this.url = url;
adaptorName = url.toString();
}
martreg = getMartRegistry();
}
public RegistryDSConfigAdaptor(DSConfigAdaptor adaptor, DetailedDataSource dsource) throws ConfigurationException {
super();
adaptors.add(adaptor);
if (dsource != null) {
this.dsource = dsource;
adaptorName = dsource.getName();
}
martreg = getMartRegistry();
}
/**
* Sets the URL refering to the underlying MartRegistry object.
* If no adaptors have been added, or the object was constructed with an existing MartRegistry object,
* the object attempts to access this URL to create a MartRegistry object. Otherwise, it simply records the
* URL for future reference.
* @param url -- url refering to the underlying MartRegistry object.
* @throws ConfigurationException if url is null, or if the url has already been set, and for all URL/XML parsing exceptions
*/
public void setRegistryURL(URL url) throws ConfigurationException {
if (url == null)
throw new ConfigurationException("Attempt to set url with a null URL\n");
if (this.dsource != null)
throw new ConfigurationException("A RegistryAdaptor can work with only one MartRegistry document, either from a URL, or from a Database\n");
if (this.url != null)
throw new ConfigurationException("A RegistryAdaptor can only work with one MartRegistry document URL\n");
this.url = url;
if (martreg == null) {
if (adaptors.size() > 0)
martreg = getMartRegistry();
else {
loadMartRegistryFromURL();
loadAdaptorsFromRegistry();
}
}
if (adaptorName == null)
adaptorName = url.toString();
}
private void loadMartRegistryFromURL() throws ConfigurationException {
try {
martreg = MartRegistryXMLUtils.XMLStreamToMartRegistry(InputSourceUtil.getStreamForURL(url));
} catch (ConfigurationException e) {
throw e;
} catch (IOException e) {
throw new ConfigurationException("Caught IOException opening Stream for supplied url: " + e.getMessage(), e);
}
}
/**
* Returns the URL for this MartRegistryAdaptor. May be null.
* @return URL url
*/
public URL getURL() {
return url;
}
public void setRegistryDatasource(DetailedDataSource dsource) throws ConfigurationException {
if (dsource == null)
throw new ConfigurationException("Attempt to set Datasource with a null DetailedDataSource\n");
if (this.url != null)
throw new ConfigurationException("A RegistryAdaptor can work with only one MartRegistry document, either from a URL, or from a Database\n");
if (this.dsource != null)
throw new ConfigurationException("A RegistryAdaptor can only work with one MartRegistry document DataSource\n");
this.dsource = dsource;
if (martreg == null) {
if (adaptors.size() > 0)
martreg = getMartRegistry();
else {
loadMartRegistryFromDatasource();
loadAdaptorsFromRegistry();
}
}
if (adaptorName == null)
adaptorName = dsource.getName();
}
private void loadMartRegistryFromDatasource() throws ConfigurationException {
martreg = MartRegistryXMLUtils.DataSourceToMartRegistry(dsource);
}
public DetailedDataSource getDatasource() {
return dsource;
}
/*
* TODO: This method iterates through all of the MartLocation objects within the MartRegistry object underlying this
* MartRegistryAdaptor, determining the unique set of DSConfigAdaptors to represent the object. If two DSConfigAdaptor
* objects are found to support the same DatasetConfig object (based on internalName), then the first encountered DSConfigAdaptor
* is given precedence. The last encountered DSConfigAdaptor is either modified using the removeDatasetConfig command (if it is a
* MultiDSConfigAdaptor), or thrown away. In the case where all of the DatasetConfig objects within a MultiDSConfigAdaptor are found
* to be supported by previously loaded adaptors, the entire MultiDSConfigAdaptor is thrown away. This does set up the possibility that
* DatasetConfig specifications for the same Dataset from multiple adaptors which differ in their filters/attributes could be mis - handled.
*/
private void loadAdaptorsFromRegistry() throws ConfigurationException {
Object[] elements = martreg.getElementsInOrder();
for (int i = 0, n = elements.length; i < n; i++) {
if (elements[i] instanceof MartLocation) {
addLocation( (MartLocation) elements[i]);
} else {
//virtualSchema
virtualSchema schema = (virtualSchema) elements[i];
MartLocation[] locs = schema.getMartLocations();
for (int j = 0, m = locs.length; j < m; j++) {
addLocation(locs[j]);
}
}
}
}
private void addLocation(MartLocation location) throws ConfigurationException {
if ( ( location.getType().equals(MartLocationBase.REGISTRYDB) )
|| (includeHiddenMembers)
|| (location.isVisible())
) {
if (location.getType().equals(MartLocationBase.REGISTRYFILE)) {
//create underlying MartRegistry objects with this, check against martreg list before creating an adaptor for it (may point to the same martreg document)
MartRegistry subreg = null;
try {
subreg =
MartRegistryXMLUtils.XMLStreamToMartRegistry(
InputSourceUtil.getStreamForURL(((RegistryFileLocation) location).getUrl()));
} catch (ConfigurationException e) {
throw e;
} catch (IOException e) {
throw new ConfigurationException(
"Caught IOException working with MartRegistryLocation Element URL: " + e.getMessage(),
e);
}
RegistryDSConfigAdaptor adaptor = new RegistryDSConfigAdaptor(subreg, url, ignoreCache, loadFully, includeHiddenMembers);
adaptor.setName(location.getName());
add(adaptor);
martRegs.add(subreg);
} else if (location.getType().equals(MartLocationBase.REGISTRYDB)) {
//create underlying MartRegistry objects with this, check against martreg list before creating an adaptor for it (may point to the same martreg document)
MartRegistry subreg =
MartRegistryXMLUtils.DataSourceToMartRegistry(((RegistryDBLocation) location).getDetailedDataSource());
RegistryDSConfigAdaptor adaptor = new RegistryDSConfigAdaptor(subreg, dsource, ignoreCache, loadFully, includeHiddenMembers);
adaptor.setName(location.getName());
add(adaptor);
martRegs.add(subreg);
} else if (location.getType().equals(MartLocationBase.URL)) {
if (((URLLocation) location).getUrl() != null){
URLDSConfigAdaptor adaptor =
new URLDSConfigAdaptor(((URLLocation) location).getUrl(), ignoreCache, includeHiddenMembers);
adaptor.setName(location.getName());
add(adaptor);
}
} else if (location.getType().equals(MartLocationBase.DATABASE)) {
DatabaseLocation dbloc = (DatabaseLocation) location;
String host = dbloc.getHost();
String user = dbloc.getUser();
String martUser = dbloc.getMartUser();
String instanceName = dbloc.getInstanceName();
String schema = dbloc.getSchema();
String port = dbloc.getPort();
String password = dbloc.getPassword();
String databaseType = dbloc.getDatabaseType();
String jdbcDriverClassName = DetailedDataSource.getJDBCDriverClassNameFor(databaseType);
String name = dbloc.getName();
// apply defaults only if both dbtype and jdbcdriver are null
if (databaseType == null && jdbcDriverClassName == null) {
databaseType = DetailedDataSource.DEFAULTDATABASETYPE;
jdbcDriverClassName = DetailedDataSource.DEFAULTDRIVER;
}
String connectionString = DetailedDataSource.connectionURL(databaseType, host, port, instanceName);
// use default name
if (name == null || "".equals(name))
name = connectionString;
//use the default poolsize of 10
DetailedDataSource dsource =
new DetailedDataSource(
databaseType,
host,
port,
instanceName,
schema,
connectionString,
user,
martUser,
password,
DetailedDataSource.DEFAULTPOOLSIZE,
jdbcDriverClassName,
name);
DatabaseDSConfigAdaptor adaptor =
new DatabaseDSConfigAdaptor(dsource, user, martUser, ignoreCache, loadFully, includeHiddenMembers, true);
adaptor.setName(location.getName());
add(adaptor);
} else
throw new ConfigurationException(
"Recieved unsupported MartLocation element of type : "
+ location.getType()
+ " in MartRegistry Document\n");
}
}
// /**
// * Adds adaptor.
// * @param adaptor adaptor to be added. Do not add an ancestor CompositeDSConfigAdaptor
// * to this instance or you will cause circular references when the getXXX() methods are called.
// */
// public void add(DSConfigAdaptor adaptor) {
// if (!adaptors.contains(adaptor))
// adaptors.add(adaptor);
// }
/**
* Returns a new MartRegistry object, with MartLocations for all of the adaptors present.
* @return MartRegistry object
* @throws ConfigurationException for all underlying Exceptions
*/
public MartRegistry getMartRegistry() throws ConfigurationException {
MartRegistry nmartreg = new MartRegistry();
for (Iterator iter = adaptors.iterator(); iter.hasNext();) {
DSConfigAdaptor adaptor = (DSConfigAdaptor) iter.next();
MartLocation[] martlocs = adaptor.getMartLocations();
for (int i = 0, n = martlocs.length; i < n; i++) {
nmartreg.addMartLocation(martlocs[i]);
}
}
return nmartreg;
}
/**
* Writes a MartRegistry object as MartRegistry.dtd compliant XML to a File.
* @param mr -- MartRegistry object to store to the file system
* @param file -- File to write XML
* @throws ConfigurationException for underlying Exceptions
*/
public static void StoreMartRegistry(MartRegistry mr, File file) throws ConfigurationException {
MartRegistryXMLUtils.MartRegistryToFile(mr, file);
}
/**
* Writes a MartRegistry object as a MartRegistry.dtd compliant XML to a DataBase
* @param mr -- MartRegistry object to store to the Database
* @param dsource -- DetailedDataSource containing connection to Database
* @throws ConfigurationException for all underlying exceptions
*/
public static void StoreMartRegistry(MartRegistry mr, DetailedDataSource dsource) throws ConfigurationException {
MartRegistryXMLUtils.storeMartRegistryDocumentToDataSource(
dsource,
MartRegistryXMLUtils.MartRegistryToDocument(mr),
true);
}
/**
* Allows Equality Comparisons manipulation of DSConfigAdaptor objects. Although
* any DSConfigAdaptor object can be compared with any other DSConfigAdaptor object, to provide
* consistency with the compareTo method, in practice, it is almost impossible for different DSVIewAdaptor
* implimentations to equal.
*
* Equality is based on the CompositeViewAdaptor hashCode, so that two URL
* sources specifying the same MartRegistry will equal.
*/
public boolean equals(Object o) {
return o instanceof DSConfigAdaptor && hashCode() == o.hashCode();
}
/**
* Calculates CompositeDSConfigAdaptor hashCode. Two MartRegistryAdaptors specifying
* the same MartLocation elements, regardless of their URL source, should
* have the same hashCode. A call to update on either should resolve any
* differences in actual DatasetConfig content.
* @see org.ensembl.mart.lib.config.CompositeDSConfigAdaptor#hashCode()
*/
public int hashCode() {
return super.hashCode();
}
/* (non-Javadoc)
* @see org.ensembl.mart.lib.config.DSConfigAdaptor#getName()
*/
public String getName() {
return super.getName();
}
}