/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsmodel.spi; import java.lang.reflect.Method; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.db.ExternalDatabaseFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.db.jdbc.JDBCExternalDatabaseFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassRepositoryFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.classfile.CFExternalClassRepositoryFactory; /** * */ public class DefaultSPIManager implements SPIManager { /** * preferences allow the user to override the default SPI implementations */ private Preferences preferences; public static final String SPI_PREFERENCES_NODE = "spi"; public static final String DEFAULTS_PREFERENCES_NODE = "defaults"; public static final String PROJECTS_PREFERENCES_NODE = "projects"; /** * the project's name is used to look up any project-specific settings * in the preferences */ private String projectName; /** * class repository */ private ExternalClassRepositoryFactory externalClassRepositoryFactory; public static final String EXTERNAL_CLASS_REPOSITORY_FACTORY_CLASS_NAME_PREFERENCE = "external class repository factory class"; public static final String EXTERNAL_CLASS_REPOSITORY_FACTORY_CLASS_NAME_PREFERENCE_DEFAULT = CFExternalClassRepositoryFactory.class.getName(); public static final String EXTERNAL_CLASS_REPOSITORY_FACTORY_STATIC_METHOD_NAME_PREFERENCE = "external class repository factory static method"; public static final String EXTERNAL_CLASS_REPOSITORY_FACTORY_STATIC_METHOD_NAME_PREFERENCE_DEFAULT = "instance"; /** * database */ private ExternalDatabaseFactory externalDatabaseFactory; public static final String EXTERNAL_DATABASE_FACTORY_CLASS_NAME_PREFERENCE = "external database factory class"; public static final String EXTERNAL_DATABASE_FACTORY_CLASS_NAME_PREFERENCE_DEFAULT = JDBCExternalDatabaseFactory.class.getName(); public static final String EXTERNAL_DATABASE_FACTORY_STATIC_METHOD_NAME_PREFERENCE = "external database factory static method"; public static final String EXTERNAL_DATABASE_FACTORY_STATIC_METHOD_NAME_PREFERENCE_DEFAULT = "instance"; /** * Construct an SPI manager for the specified project. The various * factories can be configured via the specified preferences node. */ public DefaultSPIManager(Preferences preferences, String projectName) { super(); this.preferences = preferences.node(SPI_PREFERENCES_NODE); this.projectName = projectName; } // ********** class repository ********** /** * @see SPIManager#getExternalClassRepositoryFactory() */ public ExternalClassRepositoryFactory getExternalClassRepositoryFactory() { if (this.externalClassRepositoryFactory == null) { this.externalClassRepositoryFactory = this.buildExternalClassRepositoryFactory(); } return this.externalClassRepositoryFactory; } private ExternalClassRepositoryFactory buildExternalClassRepositoryFactory() { return (ExternalClassRepositoryFactory) this.buildFactory(this.externalClassRepositoryFactoryClassName(), this.externalClassRepositoryFactoryStaticMethodName()); } private String externalClassRepositoryFactoryClassName() { return this.value(EXTERNAL_CLASS_REPOSITORY_FACTORY_CLASS_NAME_PREFERENCE, EXTERNAL_CLASS_REPOSITORY_FACTORY_CLASS_NAME_PREFERENCE_DEFAULT); } private String externalClassRepositoryFactoryStaticMethodName() { return this.value(EXTERNAL_CLASS_REPOSITORY_FACTORY_STATIC_METHOD_NAME_PREFERENCE, EXTERNAL_CLASS_REPOSITORY_FACTORY_STATIC_METHOD_NAME_PREFERENCE_DEFAULT); } // ********** database ********** /** * @see SPIManager#getExternalDatabaseFactory() */ public ExternalDatabaseFactory getExternalDatabaseFactory() { if (this.externalDatabaseFactory == null) { this.externalDatabaseFactory = this.buildExternalDatabaseFactory(); } return this.externalDatabaseFactory; } private ExternalDatabaseFactory buildExternalDatabaseFactory() { return (ExternalDatabaseFactory) this.buildFactory(this.externalDatabaseFactoryClassName(), this.externalDatabaseFactoryStaticMethodName()); } private String externalDatabaseFactoryClassName() { return this.value(EXTERNAL_DATABASE_FACTORY_CLASS_NAME_PREFERENCE, EXTERNAL_DATABASE_FACTORY_CLASS_NAME_PREFERENCE_DEFAULT); } private String externalDatabaseFactoryStaticMethodName() { return this.value(EXTERNAL_DATABASE_FACTORY_STATIC_METHOD_NAME_PREFERENCE, EXTERNAL_DATABASE_FACTORY_STATIC_METHOD_NAME_PREFERENCE_DEFAULT); } // ********** common code ********** /** * return the user-specified project-specific setting; * absent that, return the user-specified default setting; * absent that, return the system-specified default setting */ private String value(String key, String defaultValue) { String value = defaultValue; // spi/defaults/foo value = this.preferences.node(DEFAULTS_PREFERENCES_NODE).get(key, value); try { // spi/projects/Project Name/foo if (this.preferences.node(PROJECTS_PREFERENCES_NODE).nodeExists(this.projectName)) { value = this.preferences.node(PROJECTS_PREFERENCES_NODE).node(this.projectName).get(key, value); } } catch (BackingStoreException ex) { throw new RuntimeException(ex); } return value; } private Object buildFactory(String factoryClassName, String factoryStaticMethodName) { try { // first load the factory class // (for now, the factory class must be loadable by this class's classloader; // but we could configure a URLClassLoader with a classpath and use that...) Class factoryClass = Class.forName(factoryClassName); // then get the method Method factoryStaticMethod = factoryClass.getMethod(factoryStaticMethodName, new Class[0]); // then invoke the method and return the result return factoryStaticMethod.invoke(null, new Object[0]); } catch (Throwable t) { // if any of the above code fails, throw a runtime exception throw new RuntimeException(t); } } }