+/**\r
+* Copyright (C) 2007 EDIT\r
+* European Distributed Institute of Taxonomy \r
+* http://www.e-taxonomy.eu\r
+* \r
+* The contents of this file are subject to the Mozilla Public License Version 1.1\r
+* See LICENSE.TXT at the top of this package for the full license terms.\r
+*/\r
+\r
package eu.etaxonomy.cdm.database;\r
\r
+import static eu.etaxonomy.cdm.common.XmlHelp.getBeansRoot;\r
+import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlBean;\r
+import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlValueProperty;\r
+import static eu.etaxonomy.cdm.common.XmlHelp.saveToXml;\r
+\r
import java.io.File;\r
import java.io.FileInputStream;\r
import java.io.FileNotFoundException;\r
import java.io.FileOutputStream;\r
-import java.io.FilenameFilter;\r
+import java.io.IOException;\r
import java.util.ArrayList;\r
import java.util.Enumeration;\r
import java.util.Iterator;\r
import java.util.List;\r
import java.util.Properties;\r
\r
+import javax.sql.DataSource;\r
+\r
import org.apache.log4j.Logger;\r
-import org.hibernate.cache.CacheProvider;\r
-import org.hibernate.cache.NoCacheProvider;\r
+import org.hibernate.cache.internal.NoCachingRegionFactory;\r
+import org.hibernate.cache.spi.RegionFactory;\r
import org.jdom.Attribute;\r
import org.jdom.Document;\r
import org.jdom.Element;\r
import org.springframework.beans.factory.config.PropertiesFactoryBean;\r
import org.springframework.beans.factory.support.AbstractBeanDefinition;\r
import org.springframework.beans.factory.support.RootBeanDefinition;\r
-import org.springframework.jdbc.datasource.DriverManagerDataSource;\r
+\r
+import com.mchange.v2.c3p0.ComboPooledDataSource;\r
\r
import eu.etaxonomy.cdm.api.application.CdmApplicationUtils;\r
+import eu.etaxonomy.cdm.common.CdmUtils;\r
import eu.etaxonomy.cdm.common.XmlHelp;\r
-\r
-import static eu.etaxonomy.cdm.common.XmlHelp.getRoot;\r
-import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlBean;\r
-import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlValueProperty;\r
-import static eu.etaxonomy.cdm.common.XmlHelp.saveToXml;\r
+import eu.etaxonomy.cdm.database.types.IDatabaseType;\r
+import eu.etaxonomy.cdm.model.name.NomenclaturalCode;\r
\r
\r
/**\r
* class to access an CdmDataSource\r
*/\r
-public class CdmPersistentDataSource {\r
+public class CdmPersistentDataSource extends CdmDataSourceBase{\r
private static final Logger logger = Logger.getLogger(CdmPersistentDataSource.class);\r
\r
public static final String DATASOURCE_BEAN_POSTFIX = "DataSource";\r
public final static String DATASOURCE_FILE_NAME = "cdm.datasources.xml";\r
+ public final static String DATASOURCE_PATH = "/eu/etaxonomy/cdm/";\r
+ \r
private final static Format format = Format.getPrettyFormat(); \r
\r
public enum DbProperties{\r
DRIVER_CLASS,\r
URL,\r
+ SERVER, \r
+ DATABASE,\r
+ PORT,\r
+ MODE,\r
+ FILEPATH,\r
USERNAME,\r
- PASSWORD;\r
+ PASSWORD, \r
+ NOMENCLATURAL_CODE;\r
\r
@Override\r
public String toString(){\r
return "driverClassName";\r
case URL:\r
return "url";\r
+ case SERVER:\r
+ return "server";\r
+ case DATABASE:\r
+ return "database";\r
+ case PORT:\r
+ return "port";\r
+ case MODE:\r
+ return "mode";\r
+ case FILEPATH:\r
+ return "filePath";\r
case USERNAME:\r
return "username";\r
case PASSWORD:\r
return "password";\r
+ case NOMENCLATURAL_CODE:\r
+ return "nomenclaturalCode";\r
default: \r
throw new IllegalArgumentException( "Unknown enumeration type" );\r
}\r
}\r
}\r
- \r
- public enum HBM2DDL{\r
- VALIDATE,\r
- UPDATE,\r
- CREATE,\r
- CREATE_DROP;\r
\r
- @Override\r
- public String toString(){\r
- switch (this){\r
- case VALIDATE:\r
- return "validate";\r
- case UPDATE:\r
- return "update";\r
- case CREATE:\r
- return "create";\r
- case CREATE_DROP:\r
- return "create-drop";\r
- default: \r
- throw new IllegalArgumentException( "Unknown enumeration type" );\r
- }\r
- }\r
- }\r
+ /**\r
+ * The Datasource class that Spring will use to set up the connection to the database\r
+ */\r
+ private static String dataSourceClassName = ComboPooledDataSource.class.getName();\r
+ // we used dbcps BasicDataSource before\r
+// private static String dataSourceClassName = BasicDataSource.class.getName();\r
\r
//name\r
protected String dataSourceName;\r
/**\r
* Returns the default CdmDataSource\r
* @return the default CdmDataSource\r
+ * @throws DataSourceNotFoundException \r
*/\r
- public final static CdmPersistentDataSource NewDefaultInstance(){\r
- try {\r
- return NewInstance("default");\r
- } catch (DataSourceNotFoundException e) {\r
- logger.error("Default datasource does not exist in config file");\r
- return null;\r
- }\r
+ public final static CdmPersistentDataSource NewDefaultInstance() throws DataSourceNotFoundException {\r
+ return NewInstance("default");\r
}\r
\r
\r
/**\r
* Returns the default CdmDataSource\r
* @return the default CdmDataSource\r
+ * @throws DataSourceNotFoundException \r
*/\r
- public final static CdmPersistentDataSource NewLocalHsqlInstance(){\r
- try {\r
- return NewInstance("localDefaultHsql");\r
- } catch (DataSourceNotFoundException e) {\r
- logger.error("Local datasource does not exist in config file");\r
- return null;\r
- }\r
+ public final static CdmPersistentDataSource NewLocalHsqlInstance() throws DataSourceNotFoundException{\r
+ return NewInstance("localDefaultHsql");\r
}\r
\r
/**\r
* @param strDataSource\r
* @return\r
*/\r
- public final static CdmPersistentDataSource NewInstance(String dataSourceName) \r
- throws DataSourceNotFoundException{\r
+ public final static CdmPersistentDataSource NewInstance(String dataSourceName) throws DataSourceNotFoundException{\r
if (exists(dataSourceName)){\r
return new CdmPersistentDataSource(dataSourceName);\r
}else{\r
\r
\r
\r
+ public String getDatabase() {\r
+ return getDatabaseProperty(DbProperties.DATABASE);\r
+ }\r
+\r
+\r
+ public String getFilePath() {\r
+ //TODO null\r
+ return getDatabaseProperty(DbProperties.FILEPATH);\r
+ }\r
+\r
+\r
+ public H2Mode getMode() {\r
+ //TODO null\r
+ return H2Mode.fromString(getDatabaseProperty(DbProperties.MODE));\r
+ }\r
+ \r
+\r
+ /* (non-Javadoc)\r
+ * @see eu.etaxonomy.cdm.database.ICdmDataSource#getNomenclaturalCode()\r
+ */\r
+ public NomenclaturalCode getNomenclaturalCode() {\r
+ // TODO null\r
+ return NomenclaturalCode.fromString(getDatabaseProperty(DbProperties.NOMENCLATURAL_CODE));\r
+ }\r
+\r
+ public int getPort() {\r
+ String port = CdmUtils.Nz(getDatabaseProperty(DbProperties.PORT));\r
+ if ("".equals(port)){\r
+ return -1;\r
+ }else{\r
+ //TODO exception if non integer\r
+ return Integer.valueOf(port);\r
+ }\r
+ }\r
+\r
+\r
+ public String getServer() {\r
+ return getDatabaseProperty(DbProperties.SERVER);\r
+ }\r
+\r
/**\r
* Returns the database type of the data source. \r
* @return the database type of the data source. Null if the bean or the driver class property does not exist or the driver class is unknown.\r
}\r
}\r
}\r
+ \r
+ \r
+ /**\r
+ * Returns the database type of the data source. \r
+ * @return the database type of the data source. Null if the bean or the driver class property does not exist or the driver class is unknown.\r
+ */\r
+ protected String getDatabaseProperty(DbProperties property){\r
+ Element bean = getDatasourceBeanXml(this.dataSourceName);\r
+ String url;\r
+ String result = null;\r
+ if (bean != null){\r
+ result = getPropertyValue(bean, property.toString());\r
+ if (result == null){ //test if property is database, server or port which are included in the url\r
+ url = getPropertyValue(bean, DbProperties.URL.toString());\r
+ DatabaseTypeEnum dbTypeEnum = getDatabaseType();\r
+ if (dbTypeEnum != null){\r
+ IDatabaseType dbType = dbTypeEnum.getDatabaseType();\r
+ if (property.equals(DbProperties.DATABASE)){\r
+ result = dbType.getDatabaseNameByConnectionString(url);\r
+ }else if(property.equals(DbProperties.SERVER)){\r
+ result = dbType.getServerNameByConnectionString(url);\r
+ }else if(property.equals(DbProperties.PORT)){\r
+ result = String.valueOf(dbType.getPortByConnectionString(url));\r
+ }else{\r
+ logger.debug("Unknown property: " + property);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return result; \r
+ }\r
+ \r
+ private String getPropertyValue(Element bean, String property){\r
+ Element driverProp = XmlHelp.getFirstAttributedChild(bean, "property", "name", property);\r
+ if (driverProp == null){\r
+ logger.debug("Unknown property: " + property);\r
+ return null;\r
+ }else{\r
+ String strProperty = driverProp.getAttributeValue("value");\r
+ return strProperty;\r
+ }\r
+ }\r
+ \r
\r
\r
/**\r
* Returns the list of properties that are defined in the datasource \r
* @return \r
*/\r
+ @SuppressWarnings("unchecked")\r
public List<Attribute> getDatasourceAttributes(){\r
List<Attribute> result = new ArrayList<Attribute>();\r
Element bean = getDatasourceBeanXml(this.dataSourceName);\r
}\r
\r
/**\r
- * Returns a BeanDefinition object of type DriverManagerDataSource that contains\r
+ * Returns a BeanDefinition object of type DataSource that contains\r
* datsource properties (url, username, password, ...)\r
* @return\r
*/\r
+ @SuppressWarnings("unchecked")\r
public BeanDefinition getDatasourceBean(){\r
DatabaseTypeEnum dbtype = DatabaseTypeEnum.getDatabaseEnumByDriverClass(getDatasourceProperty(DbProperties.DRIVER_CLASS));\r
\r
- AbstractBeanDefinition bd = new RootBeanDefinition(dbtype.getDriverManagerDataSourceClass());\r
+ AbstractBeanDefinition bd = new RootBeanDefinition(dbtype.getDataSourceClass());\r
//attributes\r
Iterator<Attribute> iterator = getDatasourceAttributes().iterator();\r
while(iterator.hasNext()){\r
* @param showSql\r
* @return\r
*/\r
- public BeanDefinition getHibernatePropertiesBean(HBM2DDL hbm2dll){\r
+ public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll){\r
boolean showSql = false;\r
boolean formatSql = false;\r
- Class<? extends CacheProvider> cacheProviderClass = NoCacheProvider.class;\r
- return getHibernatePropertiesBean(hbm2dll, showSql, formatSql, cacheProviderClass);\r
+ boolean registerSearchListener = false;\r
+ Class<? extends RegionFactory> cacheProviderClass = NoCachingRegionFactory.class;\r
+ return getHibernatePropertiesBean(hbm2dll, showSql, formatSql, registerSearchListener, cacheProviderClass);\r
}\r
\r
\r
* @param showSql\r
* @return\r
*/\r
- public BeanDefinition getHibernatePropertiesBean(HBM2DDL hbm2dll, Boolean showSql, Boolean formatSql, Class<? extends CacheProvider> cacheProviderClass){\r
+ public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll, Boolean showSql, Boolean formatSql, Boolean registerSearchListener, Class<? extends RegionFactory> cacheProviderClass){\r
//Hibernate default values\r
if (hbm2dll == null){\r
- hbm2dll = HBM2DDL.VALIDATE;\r
+ hbm2dll = DbSchemaValidation.VALIDATE;\r
}\r
if (showSql == null){\r
showSql = false;\r
formatSql = false;\r
}\r
if (cacheProviderClass == null){\r
- cacheProviderClass = NoCacheProvider.class;\r
+ cacheProviderClass = NoCachingRegionFactory.class;\r
}\r
- \r
+ if(registerSearchListener == null){\r
+ registerSearchListener = false;\r
+ }\r
+ \r
DatabaseTypeEnum dbtype = getDatabaseType();\r
AbstractBeanDefinition bd = new RootBeanDefinition(PropertiesFactoryBean.class);\r
MutablePropertyValues hibernateProps = new MutablePropertyValues();\r
Properties props = new Properties();\r
props.setProperty("hibernate.hbm2ddl.auto", hbm2dll.toString());\r
props.setProperty("hibernate.dialect", dbtype.getHibernateDialect());\r
- props.setProperty("hibernate.cache.provider_class", cacheProviderClass.getName());\r
+ props.setProperty("hibernate.cache.region.factory_class", cacheProviderClass.getName());\r
props.setProperty("hibernate.show_sql", String.valueOf(showSql));\r
props.setProperty("hibernate.format_sql", String.valueOf(formatSql));\r
+ props.setProperty("hibernate.search.autoregister_listeners", String.valueOf(registerSearchListener));\r
\r
hibernateProps.addPropertyValue("properties",props);\r
bd.setPropertyValues(hibernateProps);\r
\r
\r
/**\r
- * Saves or updates the datasource to the datasource config file.\r
- * Uses default port.\r
- * @param strDataSourceName name of the datasource (without postfix DataSource)\r
- * @param databaseTypeEnum\r
- * @param server\r
- * @param database\r
- * @param username\r
- * @param password\r
- * @return the CdmDataSource, null if not successful.\r
- */\r
- public static CdmPersistentDataSource save(String strDataSourceName, DatabaseTypeEnum databaseTypeEnum, String server, String database, \r
- String username, String password){\r
- return save(strDataSourceName, databaseTypeEnum, server, database, \r
- databaseTypeEnum.getDefaultPort(), username, password);\r
- }\r
- \r
- /**\r
- * Saves or updates the datasource to the datasource config file.\r
- * @param strDataSourceName name of the datasource (without postfix DataSource)\r
+ * \r
+ * @param strDataSourceName\r
* @param databaseTypeEnum\r
* @param server\r
* @param database\r
* @param port\r
* @param username\r
* @param password\r
- * @return the CdmDataSource, null if not successful.\r
+ * @param dataSourceClass\r
+ * @param initMethod\r
+ * @param destroyMethod\r
+ * @param startSilent\r
+ * @param startServer\r
+ * @param filePath\r
+ * @param mode\r
+ * @return\r
*/\r
- public static CdmPersistentDataSource save(String strDataSourceName, DatabaseTypeEnum databaseTypeEnum, String server, String database, \r
- int port, String username, String password){\r
- Class<? extends DriverManagerDataSource> driverManagerDataSource = DriverManagerDataSource.class;\r
- return save(strDataSourceName, databaseTypeEnum, server, database, port, username, password, driverManagerDataSource, null, null, null, null, null);\r
- }\r
- \r
- \r
- public static CdmPersistentDataSource saveLocalHsqlDb(String strDataSourceName, String databasePath, String databaseName, String username, String password){\r
- DatabaseTypeEnum databaseTypeEnum = DatabaseTypeEnum.HSqlDb;\r
- Class<? extends DriverManagerDataSource> driverManagerDataSource = LocalHsqldb.class;\r
- String server = "localhost";\r
- int port = databaseTypeEnum.getDefaultPort();\r
- return save(strDataSourceName, databaseTypeEnum, server, databaseName, port, username, password, driverManagerDataSource, "init", "destroy", true, true, databasePath);\r
- }\r
- \r
- //\r
private static CdmPersistentDataSource save(String strDataSourceName, \r
DatabaseTypeEnum databaseTypeEnum, \r
String server, \r
String database, \r
- int port, \r
+ String port, \r
String username, \r
String password, \r
- Class<? extends DriverManagerDataSource> driverManagerDataSource,\r
+ Class<? extends DataSource> dataSourceClass,\r
String initMethod,\r
String destroyMethod,\r
Boolean startSilent,\r
Boolean startServer, \r
- String databasePath\r
+ String filePath,\r
+ H2Mode mode,\r
+ NomenclaturalCode code\r
){\r
+ \r
+ int portNumber = "".equals(port) ? databaseTypeEnum.getDefaultPort() : Integer.valueOf(port);\r
+ \r
+ ICdmDataSource dataSource = new CdmDataSource(databaseTypeEnum, server, database, portNumber, username, password, filePath, mode, code);\r
+ \r
//root\r
- Element root = getRoot(getDataSourceInputStream());\r
+ Element root = getBeansRoot(getDataSourceInputStream());\r
if (root == null){\r
return null;\r
}\r
if (bean != null){\r
bean.detach(); //delete old version if necessary\r
}\r
- bean = insertXmlBean(root, getBeanName(strDataSourceName), driverManagerDataSource.getName());\r
+ bean = insertXmlBean(root, getBeanName(strDataSourceName), dataSourceClass.getName());\r
//attributes\r
bean.setAttribute("lazy-init", "true");\r
if (initMethod != null) {bean.setAttribute("init-method", initMethod);}\r
\r
//set properties\r
insertXmlValueProperty(bean, "driverClassName", databaseTypeEnum.getDriverClassName());\r
- insertXmlValueProperty(bean, "url", databaseTypeEnum.getConnectionString(server, database, port));\r
+ \r
+ insertXmlValueProperty(bean, "url", databaseTypeEnum.getConnectionString(dataSource));\r
if (username != null) {insertXmlValueProperty(bean, "username", username );}\r
if (password != null) {insertXmlValueProperty(bean, "password", password );}\r
if (startSilent != null) {insertXmlValueProperty(bean, "startSilent", startSilent.toString() );}\r
if (startServer != null) {insertXmlValueProperty(bean, "startServer", startServer.toString() );}\r
- if (startServer != null) {insertXmlValueProperty(bean, "databasePath", databasePath );}\r
+ if (filePath != null) {insertXmlValueProperty(bean, "filePath", filePath );}\r
+ if (mode != null) {insertXmlValueProperty(bean, "mode", mode.toString() );}\r
+ if (code != null) {insertXmlValueProperty(bean, "nomenclaturalCode", code.name());}\r
\r
//save\r
saveToXml(root.getDocument(), getResourceDirectory(), DATASOURCE_FILE_NAME, format );\r
}\r
}\r
\r
- \r
+ /**\r
+ * @param strDataSourceName\r
+ * @param dataSource\r
+ * @param code \r
+ * @return\r
+ * the updated dataSource, null if not succesful\r
+ */\r
+ public static CdmPersistentDataSource update(String strDataSourceName,\r
+ ICdmDataSource dataSource) throws DataSourceNotFoundException, IllegalArgumentException{\r
+ delete(CdmPersistentDataSource.NewInstance(strDataSourceName));\r
+ return save(strDataSourceName, dataSource);\r
+ }\r
+\r
+ /**\r
+ * Saves a datasource to the datasource config file. If strDataSourceName differs a new dataSource\r
+ * will be created in config file. Use update() of real update functionality.\r
+ * \r
+ * @param strDataSourceName\r
+ * @param dataSource\r
+ * @return\r
+ */\r
+ public static CdmPersistentDataSource save(String strDataSourceName,\r
+ ICdmDataSource dataSource) throws IllegalArgumentException{\r
+ \r
+ if(dataSource.getDatabaseType() == null){\r
+ new IllegalArgumentException("Database type not specified");\r
+ }\r
+ \r
+ if(dataSource.getDatabaseType().equals(DatabaseTypeEnum.H2)){\r
+ Class<? extends DataSource> dataSourceClass = LocalH2.class;\r
+ if(dataSource.getMode() == null){\r
+ new IllegalArgumentException("H2 mode not specified");\r
+ }\r
+ return save(\r
+ strDataSourceName, \r
+ dataSource.getDatabaseType(), \r
+ "localhost", \r
+ getCheckedDataSourceParameter(dataSource.getDatabase()), \r
+ dataSource.getDatabaseType().getDefaultPort() + "", \r
+ getCheckedDataSourceParameter(dataSource.getUsername()), \r
+ getCheckedDataSourceParameter(dataSource.getPassword()), \r
+ dataSourceClass, \r
+ null, null, null, null, \r
+ getCheckedDataSourceParameter(dataSource.getFilePath()), \r
+ dataSource.getMode(),\r
+ dataSource.getNomenclaturalCode());\r
+ }else{\r
+ \r
+ Class<? extends DataSource> dataSourceClass;\r
+ try {\r
+ dataSourceClass = (Class<? extends DataSource>) Class.forName(dataSourceClassName);\r
+ \r
+ CdmPersistentDataSource persistendDatasource = save(\r
+ strDataSourceName, \r
+ dataSource.getDatabaseType(), \r
+ getCheckedDataSourceParameter(dataSource.getServer()), \r
+ getCheckedDataSourceParameter(dataSource.getDatabase()), \r
+ dataSource.getPort() + "", \r
+ getCheckedDataSourceParameter(dataSource.getUsername()), \r
+ getCheckedDataSourceParameter(dataSource.getPassword()), \r
+ dataSourceClass, \r
+ null, null, null, null, null, null,\r
+ dataSource.getNomenclaturalCode());\r
+ \r
+ return persistendDatasource;\r
+ } catch (ClassNotFoundException e) {\r
+ logger.error("DataSourceClass not found - stopping application", e);\r
+ System.exit(-1);\r
+ }\r
+ // will never be reached\r
+ return null;\r
+ }\r
+ }\r
+\r
+ private static String getCheckedDataSourceParameter(String parameter) throws IllegalArgumentException{ \r
+ if(parameter != null){\r
+ return parameter;\r
+ }else{\r
+ new IllegalArgumentException("Non obsolete paramater was assigned a null value: " + parameter);\r
+ return null;\r
+ }\r
+ }\r
+\r
/**\r
* Deletes a dataSource\r
* @param dataSource\r
* Returns a list of all datasources stored in the datasource config file\r
* @return all existing data sources\r
*/\r
+ @SuppressWarnings("unchecked")\r
static public List<CdmPersistentDataSource> getAllDataSources(){\r
List<CdmPersistentDataSource> dataSources = new ArrayList<CdmPersistentDataSource>();\r
\r
- Element root = getRoot(getDataSourceInputStream());\r
+ Element root = getBeansRoot(getDataSourceInputStream());\r
if (root == null){\r
return null;\r
}else{\r
return dataSources;\r
}\r
\r
+ public String getUsername(){\r
+ return getDatasourceProperty(DbProperties.USERNAME);\r
+ }\r
\r
+ public String getPassword(){\r
+ return getDatasourceProperty(DbProperties.PASSWORD);\r
+ }\r
+\r
+\r
/* (non-Javadoc)\r
* @see java.lang.Object#toString()\r
*/\r
*/\r
private static Element getDatasourceBeanXml(String strDataSourceName){\r
FileInputStream inStream = getDataSourceInputStream();\r
- Element root = getRoot(inStream);\r
+ Element root = getBeansRoot(inStream);\r
if (root == null){\r
return null;\r
}else{\r
if (xmlBean == null){\r
//TODO warn or info\r
logger.debug("Unknown Element 'bean id=" +strDataSourceName + "' ");\r
- };\r
+ }\r
return xmlBean;\r
}\r
}\r
\r
// returns the directory containing the resources \r
private static String getResourceDirectory(){\r
- File f = CdmApplicationUtils.getWritableResourceDir();\r
- return f.getPath();\r
+ try {\r
+ File f = CdmApplicationUtils.getWritableResourceDir();\r
+ return f.getPath();\r
+ } catch (IOException e) {\r
+ logger.error(e);\r
+ throw new RuntimeException(e);\r
+ }\r
}\r
\r
static private FileInputStream fileInputStream(File file){\r
}\r
}\r
\r
- \r
- /**\r
- * Filter class to define datasource file format\r
- */\r
- private static class DataSourceFileNameFilter implements FilenameFilter{\r
- public boolean accept(File dir, String name) {\r
- return (name.endsWith(DATASOURCE_FILE_NAME));\r
- }\r
- }\r
- \r
public boolean equals(Object obj){\r
if (obj == null){\r
return false;\r