/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.hibernate.console;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.DOMWriter;
import org.eclipse.datatools.connectivity.IConnectionProfile;
import org.eclipse.datatools.connectivity.ProfileManager;
import org.eclipse.osgi.util.NLS;
import org.hibernate.console.preferences.ConsoleConfigurationPreferences;
import org.hibernate.console.preferences.ConsoleConfigurationPreferences.ConfigurationMode;
import org.hibernate.util.xpl.DTDEntityResolver;
//import org.hibernate.util.ConfigHelper;
import org.hibernate.util.xpl.ReflectHelper;
import org.hibernate.util.xpl.StringHelper;
import org.hibernate.util.xpl.XMLHelper;
import org.jboss.tools.hibernate.exception.MappingException;
import org.jboss.tools.hibernate.runtime.spi.HibernateException;
import org.jboss.tools.hibernate.runtime.spi.IConfiguration;
import org.jboss.tools.hibernate.runtime.spi.IEnvironment;
import org.jboss.tools.hibernate.runtime.spi.INamingStrategy;
import org.jboss.tools.hibernate.runtime.spi.IService;
import org.jboss.tools.hibernate.runtime.spi.ServiceLookup;
import org.w3c.dom.Document;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;
public class ConfigurationFactory {
public static final String FAKE_TM_LOOKUP = "org.hibernate.console.FakeTransactionManagerLookup"; //$NON-NLS-1$
private ConsoleConfigurationPreferences prefs;
private Map<String, FakeDelegatingDriver> fakeDrivers;
private IService service;
private IEnvironment environment;
public ConfigurationFactory(ConsoleConfigurationPreferences prefs,
Map<String, FakeDelegatingDriver> fakeDrivers) {
this.prefs = prefs;
this.fakeDrivers = fakeDrivers;
service = ServiceLookup.findService(prefs.getHibernateVersion());
environment = service.getEnvironment();
}
public ConsoleConfigurationPreferences getPreferences() {
return prefs;
}
public IConfiguration createConfiguration(IConfiguration localCfg, boolean includeMappings) {
Properties properties = prefs.getProperties();
if (properties != null) {
// in case the transaction manager is empty then we need to inject a faketm since
// hibernate will still try and instantiate it.
String str = properties.getProperty(environment.getTransactionManagerStrategy());
if (str != null && StringHelper.isEmpty(str)) {
properties.setProperty(environment.getTransactionManagerStrategy(), FAKE_TM_LOOKUP);
// properties.setProperty( "hibernate.transaction.factory_class", "");
}
}
if (localCfg == null) {
localCfg = buildConfiguration(properties, includeMappings);
} else {
// Properties origProperties = cfg.getProperties();
// origProperties.putAll(properties);
// cfg.setProperties(origProperties);
// TODO: this is actually only for jdbc reveng...
// localCfg = configureStandardConfiguration( includeMappings, localCfg, properties );
}
// here both setProperties and configxml have had their chance to tell which databasedriver
// is needed.
registerFakeDriver(localCfg.getProperty(environment.getDriver()));
// autoConfigureDialect(localCfg); Disabled for now since it causes very looong timeouts for
// non-running databases + i havent been needed until now...
// TODO: jpa configuration ?
if (includeMappings) {
File[] mappingFiles = prefs.getMappingFiles();
for (int i = 0; i < mappingFiles.length; i++) {
File hbm = mappingFiles[i];
localCfg = localCfg.addFile(hbm);
}
}
// TODO: HBX-
localCfg.setProperty("hibernate.temp.use_jdbc_metadata_defaults", "false"); //$NON-NLS-1$//$NON-NLS-2$
localCfg.setProperty(environment.getHBM2DDLAuto(), "false"); //$NON-NLS-1$
// to fix: JBIDE-5839 & JBIDE-5997 - setup this property: false is default value
// to make hibernate tools diff hibernate versions compatible:
// if the property not set get NoSuchMethodError with FullTextIndexEventListener
if (localCfg.getProperty("hibernate.search.autoregister_listeners") == null) { //$NON-NLS-1$
localCfg.setProperty("hibernate.search.autoregister_listeners", "true"); //$NON-NLS-1$ //$NON-NLS-2$
}
if (localCfg.getProperty("hibernate.validator.apply_to_ddl") == null) { //$NON-NLS-1$
localCfg.setProperty("hibernate.validator.apply_to_ddl", "false"); //$NON-NLS-1$ //$NON-NLS-2$
}
return localCfg;
}
@SuppressWarnings("unused")
// autoConfigureDialect(localCfg); Disabled for now since it causes very looong timeouts for
// non-running databases + i havent been needed until now...
private void autoConfigureDialect(IConfiguration localCfg) {
if (localCfg.getProperty(environment.getDialect()) == null) {
String dialect = ConnectionProfileUtil.autoDetectDialect(service, localCfg.getProperties());
if (dialect != null){
localCfg.setProperty(environment.getDialect(), dialect);
}
}
}
// TODO: delegate to some extension point
private IConfiguration buildConfiguration(Properties properties, boolean includeMappings) {
IConfiguration localCfg = null;
if (prefs.getConfigurationMode().equals(ConfigurationMode.ANNOTATIONS)) {
try {
localCfg = buildAnnotationConfiguration();
localCfg = configureStandardConfiguration(includeMappings, localCfg, properties);
} catch (HibernateConsoleRuntimeException he) {
throw he;
} catch (Exception e) {
throw new HibernateConsoleRuntimeException(
ConsoleMessages.ConsoleConfiguration_could_not_load_annotationconfiguration,
e);
}
} else if (prefs.getConfigurationMode().equals(ConfigurationMode.JPA)) {
try {
localCfg = buildJPAConfiguration(getPreferences().getPersistenceUnitName(),
properties, prefs.getEntityResolverName(), includeMappings);
} catch (HibernateConsoleRuntimeException he) {
throw he;
} catch (Exception e) {
throw new HibernateConsoleRuntimeException(
ConsoleMessages.ConsoleConfiguration_could_not_load_jpa_configuration, e);
}
} else {
localCfg = service.newDefaultConfiguration();
localCfg = configureStandardConfiguration(includeMappings, localCfg, properties);
}
return localCfg;
}
private IConfiguration buildAnnotationConfiguration() throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
return service.newAnnotationConfiguration();
}
private IConfiguration buildJPAConfiguration(String persistenceUnit, Properties properties,
String entityResolver, boolean includeMappings) {
if (StringHelper.isEmpty(persistenceUnit)) {
persistenceUnit = null;
}
try {
Map<Object, Object> overrides = new HashMap<Object, Object>();
if (properties != null) {
overrides.putAll(properties);
}
if (StringHelper.isNotEmpty(prefs.getNamingStrategy())) {
overrides.put("hibernate.ejb.naming_strategy", prefs.getNamingStrategy()); //$NON-NLS-1$
}
if (StringHelper.isNotEmpty(prefs.getDialectName())) {
overrides.put(environment.getDialect(), prefs.getDialectName());
}
if (!includeMappings) {
overrides.put("hibernate.archive.autodetection", "none"); //$NON-NLS-1$//$NON-NLS-2$
}
if (StringHelper.isEmpty((String) overrides.get("javax.persistence.validation.mode"))) {//$NON-NLS-1$
overrides.put("javax.persistence.validation.mode", "none"); //$NON-NLS-1$//$NON-NLS-2$
}
IConfiguration invoke = service.newJpaConfiguration(entityResolver, persistenceUnit, overrides);
changeDatasourceProperties(invoke);
invoke = configureConnectionProfile(invoke);
return invoke;
// Class hibernatePersistanceProviderClass = ReflectHelper.classForName("org.hibernate.jpa.HibernatePersistenceProvider", ConsoleConfiguration.class);
// Object hibernatePersistanceProvider = hibernatePersistanceProviderClass.newInstance();
//
// Method getEntityManagerFactoryBuilderOrNull = hibernatePersistanceProviderClass.getDeclaredMethod(
// "getEntityManagerFactoryBuilderOrNull",
// new Class[] { String.class, Map.class });
// getEntityManagerFactoryBuilderOrNull.setAccessible(true);
// Object entityManagerFactoryBuilder =
// getEntityManagerFactoryBuilderOrNull.invoke(
// hibernatePersistanceProvider,
// new Object[] { persistenceUnit, overrides});
//
// if (entityManagerFactoryBuilder == null) {
// throw new HibernateConsoleRuntimeException(
// "Persistence unit not found: '" +
// persistenceUnit +
// "'.");
// }
//
// Method build =
// entityManagerFactoryBuilder.getClass().getMethod(
// "build", new Class[0]);
// build.invoke(entityManagerFactoryBuilder, null);
//
// Method getHibernateConfiguration =
// entityManagerFactoryBuilder.getClass().getMethod(
// "getHibernateConfiguration", new Class[0]);
// return (Configuration)getHibernateConfiguration.invoke(
// entityManagerFactoryBuilder, null);
} catch (HibernateConsoleRuntimeException he) {
throw he;
} catch (Exception e) {
throw new HibernateConsoleRuntimeException(
ConsoleMessages.ConsoleConfiguration_could_not_create_jpa_based_configuration,
e);
}
}
private IConfiguration configureStandardConfiguration(final boolean includeMappings,
IConfiguration localCfg, Properties properties) {
if (properties != null) {
localCfg = localCfg.setProperties(properties);
}
EntityResolver entityResolver = new DTDEntityResolver(service);
if (StringHelper.isNotEmpty(prefs.getEntityResolverName())) {
try {
entityResolver = (EntityResolver) ReflectHelper.classForName(
prefs.getEntityResolverName()).newInstance();
} catch (Exception c) {
throw new HibernateConsoleRuntimeException(
ConsoleMessages.ConsoleConfiguration_could_not_configure_entity_resolver
+ prefs.getEntityResolverName(), c);
}
}
localCfg.setEntityResolver(entityResolver);
if (StringHelper.isNotEmpty(prefs.getNamingStrategy())) {
try {
INamingStrategy ns =
service.newNamingStrategy(
prefs.getNamingStrategy());
localCfg.setNamingStrategy(ns);
} catch (Exception c) {
throw new HibernateConsoleRuntimeException(
ConsoleMessages.ConsoleConfiguration_could_not_configure_naming_strategy
+ prefs.getNamingStrategy(), c);
}
}
localCfg = loadConfigurationXML(localCfg, includeMappings, entityResolver);
changeDatasourceProperties(localCfg);
localCfg = configureConnectionProfile(localCfg);
// replace dialect if it is set in preferences
if (StringHelper.isNotEmpty(prefs.getDialectName())) {
localCfg.setProperty(environment.getDialect(), prefs.getDialectName());
}
if (StringHelper.isEmpty(localCfg.getProperty("javax.persistence.validation.mode"))) {//$NON-NLS-1$
localCfg.setProperty("javax.persistence.validation.mode", "none"); //$NON-NLS-1$//$NON-NLS-2$
}
return localCfg;
}
@SuppressWarnings("unchecked")
private IConfiguration loadConfigurationXML(IConfiguration localCfg, boolean includeMappings,
EntityResolver entityResolver) {
File configXMLFile = prefs.getConfigXMLFile();
if (!includeMappings) {
org.dom4j.Document doc;
XMLHelper xmlHelper = new XMLHelper();
InputStream stream = null;
String resourceName = "<unknown>"; //$NON-NLS-1$
if (configXMLFile != null) {
resourceName = configXMLFile.toString();
try {
stream = new FileInputStream(configXMLFile);
} catch (FileNotFoundException e1) {
throw new HibernateConsoleRuntimeException(
ConsoleMessages.ConsoleConfiguration_could_not_access + configXMLFile,
e1);
}
} else {
resourceName = "/hibernate.cfg.xml"; //$NON-NLS-1$
if (checkHibernateResoureExistence(resourceName)) {
stream = getResourceAsStream(resourceName); // simulate hibernate's
// default look up
} else {
return localCfg;
}
}
try {
List<SAXParseException> errors = new ArrayList<SAXParseException>();
doc = xmlHelper.createSAXReader(resourceName, errors, entityResolver).read(
new InputSource(stream));
if (errors.size() != 0) {
throw new MappingException(
ConsoleMessages.ConsoleConfiguration_invalid_configuration, errors
.get(0));
}
List<Node> list = doc.getRootElement()
.element("session-factory").elements("mapping"); //$NON-NLS-1$ //$NON-NLS-2$
for (Node element : list) {
element.getParent().remove(element);
}
DOMWriter dw = new DOMWriter();
Document document = dw.write(doc);
return localCfg.configure(document);
} catch (DocumentException e) {
throw new HibernateException(
ConsoleMessages.ConsoleConfiguration_could_not_parse_configuration
+ resourceName, e);
} finally {
try {
if (stream != null)
stream.close();
} catch (IOException ioe) {
// log.warn( "could not close input stream for: " + resourceName, ioe );
}
}
} else {
if (configXMLFile != null) {
return localCfg.configure(configXMLFile);
} else {
IConfiguration resultCfg = localCfg;
if (checkHibernateResoureExistence("/hibernate.cfg.xml")) { //$NON-NLS-1$
resultCfg = localCfg.configure();
}
return resultCfg;
}
}
}
private boolean checkHibernateResoureExistence(String resource) {
InputStream is = null;
try {
is = getResourceAsStream(resource);
} catch (HibernateException e) {
// just ignore
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
// ignore
}
}
return (is != null);
}
private void changeDatasourceProperties(IConfiguration localCfg){
final Properties invokeProperties = localCfg.getProperties();
// set this property to null!
if (invokeProperties.containsKey(environment.getDataSource())){
invokeProperties.setProperty(environment.getTransactionManagerStrategy(), FAKE_TM_LOOKUP);
invokeProperties.put(environment.getConnectionProvider(), service.getDriverManagerConnectionProviderClass().getName());
invokeProperties.remove(environment.getDataSource());
localCfg.setProperties(invokeProperties);
}
}
private IConfiguration configureConnectionProfile(IConfiguration localCfg) {
String connProfileName = prefs.getConnectionProfileName();
if (connProfileName == null) {
return localCfg;
}
IConnectionProfile profile = ProfileManager.getInstance().getProfileByName(
connProfileName);
if (profile != null) {
localCfg.addProperties(ConnectionProfileUtil.getHibernateConnectionProperties(service, profile));
} else {
String out = NLS.bind(
ConsoleMessages.ConsoleConfiguration_connection_profile_not_found,
connProfileName);
throw new HibernateConsoleRuntimeException(out);
}
return localCfg;
}
/**
* DriverManager checks what classloader a class is loaded from thus we register a FakeDriver
* that we know is loaded "properly" which delegates all it class to the real driver. By doing
* so we can convince DriverManager that we can use any dynamically loaded driver.
*
* @param driverClassName
*/
@SuppressWarnings("unchecked")
private void registerFakeDriver(String driverClassName) {
if (driverClassName != null) {
try {
Class<Driver> driverClass = (Class<Driver>)ReflectHelper.classForName(driverClassName);
if (!fakeDrivers.containsKey(driverClassName)) { // To avoid "double registration"
FakeDelegatingDriver fakeDelegatingDriver = new FakeDelegatingDriver(
driverClass.newInstance());
DriverManager.registerDriver(fakeDelegatingDriver);
fakeDrivers.put(driverClassName, fakeDelegatingDriver);
}
} catch (ClassNotFoundException e) {
String out =
NLS.bind(ConsoleMessages.ConsoleConfiguration_problems_while_loading_database_driverclass, driverClassName);
throw new HibernateConsoleRuntimeException(out, e);
} catch (InstantiationException e) {
String out =
NLS.bind(ConsoleMessages.ConsoleConfiguration_problems_while_loading_database_driverclass, driverClassName);
throw new HibernateConsoleRuntimeException(out, e);
} catch (IllegalAccessException e) {
String out =
NLS.bind(ConsoleMessages.ConsoleConfiguration_problems_while_loading_database_driverclass, driverClassName);
throw new HibernateConsoleRuntimeException(out, e);
} catch (SQLException e) {
String out =
NLS.bind(ConsoleMessages.ConsoleConfiguration_problems_while_loading_database_driverclass, driverClassName);
throw new HibernateConsoleRuntimeException(out, e);
}
}
}
private InputStream getResourceAsStream(String resource) {
String stripped = resource.startsWith("/") ? //$NON-NLS-1$
resource.substring(1) : resource;
InputStream stream = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader!=null) {
stream = classLoader.getResourceAsStream( stripped );
}
if ( stream == null ) {
stream = environment.getClass().getResourceAsStream( resource );
}
if ( stream == null ) {
stream = environment.getClass().getClassLoader().getResourceAsStream( stripped );
}
if ( stream == null ) {
throw new HibernateException( resource + " not found" ); //$NON-NLS-1$
}
return stream;
}
}