All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.datanucleus.AbstractNucleusContext Maven / Gradle / Ivy

Go to download

DataNucleus Core provides the primary components of a heterogenous Java persistence solution. It supports persistence API's being layered on top of the core functionality.

There is a newer version: 6.0.9
Show newest version
/**********************************************************************
Copyright (c) 2014 Andy Jefferson and others. All rights reserved.
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.

Contributors:
    ...
**********************************************************************/
package org.datanucleus;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.datanucleus.api.ApiAdapter;
import org.datanucleus.api.ApiAdapterFactory;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.MetaDataListener;
import org.datanucleus.metadata.MetaDataManager;
import org.datanucleus.plugin.PluginManager;
import org.datanucleus.properties.CorePropertyValidator;
import org.datanucleus.store.types.TypeManager;
import org.datanucleus.store.types.TypeManagerImpl;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;

/**
 * Base implementation of a NucleusContext, providing configuration, metadata management, type management, plugin management and ClassLoader services.
 */
public abstract class AbstractNucleusContext implements NucleusContext
{
    /** Configuration for this context. */
    protected final Configuration config;

    /** Manager for plug-ins. */
    protected final PluginManager pluginManager;

    /** MetaDataManager for handling the MetaData. */
    protected MetaDataManager metaDataManager = null;

    /** API adapter used by the context. **/
    protected final ApiAdapter apiAdapter;

    /** Manager for java types. */
    protected TypeManager typeManager;

    /** Name of the class providing the ClassLoaderResolver. */
    protected final String classLoaderResolverClassName;

    /** Map of the ClassLoaderResolver, keyed by the clr class and the primaryLoader name. */
    protected transient Map classLoaderResolverMap = new ConcurrentHashMap<>();

    /** Default ClassLoaderResolver, when no primaryLoader is specified. */
    protected ClassLoaderResolver defaultCLR = null;

    public static final Set STARTUP_PROPERTIES = new HashSet<>();

    static
    {
        STARTUP_PROPERTIES.add(PropertyNames.PROPERTY_PLUGIN_REGISTRY_CLASSNAME);
        STARTUP_PROPERTIES.add(PropertyNames.PROPERTY_PLUGIN_REGISTRYBUNDLECHECK);
        STARTUP_PROPERTIES.add(PropertyNames.PROPERTY_PLUGIN_ALLOW_USER_BUNDLES);
        STARTUP_PROPERTIES.add(PropertyNames.PROPERTY_PLUGIN_VALIDATEPLUGINS);
        STARTUP_PROPERTIES.add(PropertyNames.PROPERTY_CLASSLOADER_RESOLVER_NAME);
        STARTUP_PROPERTIES.add(PropertyNames.PROPERTY_PERSISTENCE_XML_FILENAME);
        STARTUP_PROPERTIES.add(PropertyNames.PROPERTY_CLASSLOADER_PRIMARY);
        STARTUP_PROPERTIES.add(PropertyNames.PROPERTY_METADATA_LISTENER_OBJECT);
    }

    public AbstractNucleusContext(String apiName, Map startupProps, PluginManager pluginMgr)
    {
        this.pluginManager = (pluginMgr != null) ? pluginMgr : PluginManager.createPluginManager(startupProps, this.getClass().getClassLoader());

        // Create Configuration (with defaults for plugins), and impose any startup properties
        this.config = new Configuration(this);
        if (startupProps != null && !startupProps.isEmpty())
        {
            this.config.setPersistenceProperties(startupProps);
        }

        // Set the name of class loader resolver
        String clrName = config.getStringProperty(PropertyNames.PROPERTY_CLASSLOADER_RESOLVER_NAME);
        if ("datanucleus".equalsIgnoreCase(clrName))
        {
            classLoaderResolverClassName = ClassLoaderResolverImpl.class.getName();
        }
        else
        {
            // Fallback to the plugin mechanism
            if (clrName != null)
            {
                classLoaderResolverClassName = pluginManager.getAttributeValueForExtension("org.datanucleus.classloader_resolver", "name", clrName, "class-name");
                if (classLoaderResolverClassName == null)
                {
                    // User has specified a classloader_resolver plugin that has not registered
                    throw new NucleusUserException(Localiser.msg("001001", clrName)).setFatal();
                }
            }
            else
            {
                classLoaderResolverClassName = null;
            }
        }

        // Initialise API, and set defaults for properties for the API
        if (apiName != null)
        {
            this.apiAdapter = ApiAdapterFactory.getInstance().getApiAdapter(apiName, pluginManager);
            this.config.setDefaultProperties(apiAdapter.getDefaultFactoryProperties());
        }
        else
        {
            this.apiAdapter = null;
        }
    }

    @Override
    public void applyDefaultProperties(Configuration conf)
    {
        conf.addDefaultProperty(PropertyNames.PROPERTY_PLUGIN_REGISTRY_CLASSNAME, null, null, null, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_PLUGIN_ALLOW_USER_BUNDLES, null, true, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_PLUGIN_VALIDATEPLUGINS, null, false, false, false);
        conf.addDefaultProperty(PropertyNames.PROPERTY_PLUGIN_REGISTRYBUNDLECHECK, null, "EXCEPTION", CorePropertyValidator.class.getName(), false, false);
        conf.addDefaultProperty(PropertyNames.PROPERTY_CLASSLOADER_RESOLVER_NAME, null, null, null, false, false);
        conf.addDefaultProperty(PropertyNames.PROPERTY_CLASSLOADER_PRIMARY, null, null, null, false, false);

        // MetaData
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_IGNORE_METADATA_FOR_MISSING_CLASSES, null, false, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_ALWAYS_DETACHABLE, null, false, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_XML_VALIDATE, null, false, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_XML_NAMESPACE_AWARE, null, true, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_AUTOREGISTER, null, true, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_ALLOW_XML, null, true, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_ALLOW_ANNOTATIONS, null, true, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_DEFAULT_NULLABLE, null, true, true, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_ALLOW_LOAD_AT_RUNTIME, null, true, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_SUPPORT_ORM, null, null, false, false);
        conf.addDefaultProperty(PropertyNames.PROPERTY_METADATA_JDO_SUFFIX, null, "jdo", null, false, false);
        conf.addDefaultProperty(PropertyNames.PROPERTY_METADATA_ORM_SUFFIX, null, "orm", null, false, false);
        conf.addDefaultProperty(PropertyNames.PROPERTY_METADATA_JDOQUERY_SUFFIX, null, "jdoquery", null, false, false);
        conf.addDefaultProperty(PropertyNames.PROPERTY_METADATA_DEFAULT_INHERITANCE_STRATEGY, null, "JDO2", CorePropertyValidator.class.getName(), false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_EMBEDDED_PC_FLAT, null, true, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_USE_DISCRIMINATOR_FOR_SINGLE_TABLE, null, false, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_USE_DISCRIMINATOR_DEFAULT_CLASS_NAME, null, true, false, false);
        conf.addDefaultBooleanProperty(PropertyNames.PROPERTY_METADATA_JAVAX_VALIDATION_SHORTCUTS, null, false, false, false);
    }

    @Override
    public synchronized void initialise()
    {
        logConfiguration();
    }

    @Override
    public void close()
    {
        if (typeManager != null)
        {
            typeManager.close();
        }
    }

    @Override
    public ApiAdapter getApiAdapter()
    {
        return apiAdapter;
    }

    @Override
    public String getApiName()
    {
        return apiAdapter != null ? apiAdapter.getName() : null;
    }

    @Override
    public Configuration getConfiguration()
    {
        return config;
    }

    @Override
    public PluginManager getPluginManager()
    {
        return pluginManager;
    }

    @Override
    public synchronized MetaDataManager getMetaDataManager()
    {
        if (metaDataManager == null)
        {
            String apiName = getApiName();
            try
            {
                metaDataManager = (MetaDataManager)pluginManager.createExecutableExtension("org.datanucleus.metadata_manager", new String[]{"name"}, new String[]{apiName}, 
                    "class", new Class[] {ClassConstants.NUCLEUS_CONTEXT}, new Object[]{this});
                if (metaDataManager != null && config.hasProperty(PropertyNames.PROPERTY_METADATA_LISTENER_OBJECT))
                {
                    MetaDataListener mdl = (MetaDataListener)config.getProperty(PropertyNames.PROPERTY_METADATA_LISTENER_OBJECT);
                    metaDataManager.registerListener(mdl);
                }
            }
            catch (Exception e)
            {
                throw new NucleusException(Localiser.msg("008010", apiName, e.getMessage()), e);
            }
            if (metaDataManager == null)
            {
                throw new NucleusException(Localiser.msg("008009", apiName));
            }
        }
    
        return metaDataManager;
    }

    @Override
    public boolean supportsORMMetaData()
    {
        return true;
    }

    @Override
    public TypeManager getTypeManager()
    {
        if (typeManager == null)
        {
            this.typeManager = new TypeManagerImpl(this);
        }
        return typeManager;
    }

    @Override
    public ClassLoaderResolver getClassLoaderResolver(ClassLoader primaryLoader)
    {
        if (primaryLoader == null && defaultCLR != null)
        {
            return defaultCLR;
        }

        // Set the key we will refer to this loader by
        String resolverName = config.getStringProperty(PropertyNames.PROPERTY_CLASSLOADER_RESOLVER_NAME);
        String key = resolverName!=null ? resolverName : "datanucleus";
        if (primaryLoader != null)
        {
            key += ":[" + StringUtils.toJVMIDString(primaryLoader) + "]"; 
        }

        ClassLoaderResolver clr = null;
        if (classLoaderResolverMap != null)
        {
            clr = classLoaderResolverMap.get(key);
            if (clr != null)
            {
                // Return the cached loader resolver
                return clr;
            }
        }
        else
        {
            classLoaderResolverMap = new ConcurrentHashMap();
        }

        // Create the ClassLoaderResolver of the required type with this primary loader
        if (resolverName == null)
        {
            // Use built-in ClassLoaderResolver
            clr = new ClassLoaderResolverImpl(primaryLoader);
        }
        else
        {
            // User-type ClassLoaderResolver
            try
            {
                clr = (ClassLoaderResolver)pluginManager.createExecutableExtension("org.datanucleus.classloader_resolver", "name", resolverName, 
                    "class-name", new Class[] {ClassLoader.class}, new Object[] {primaryLoader});
            }
            catch (ClassNotFoundException cnfe)
            {
                throw new NucleusUserException(Localiser.msg("001002", classLoaderResolverClassName), cnfe).setFatal();
            }
            catch (Exception e)
            {
                throw new NucleusUserException(Localiser.msg("001003", classLoaderResolverClassName), e).setFatal();
            }
        }

        // Add user ClassLoader if defined
        ClassLoader userCL = (ClassLoader)config.getProperty(PropertyNames.PROPERTY_CLASSLOADER_PRIMARY);
        if (userCL != null)
        {
            clr.registerUserClassLoader(userCL);
        }

        if (primaryLoader == null && primaryLoader == null)
        {
            defaultCLR = clr;
        }
        else
        {
            classLoaderResolverMap.put(key, clr);
        }

        return clr;
    }

    /**
     * Method to log the configuration of this context.
     */
    protected void logConfiguration()
    {
        if (NucleusLogger.PERSISTENCE.isDebugEnabled())
        {
            NucleusLogger.PERSISTENCE.debug("================= NucleusContext ===============");
            String javaVersion = System.getProperty("java.version");
            if (StringUtils.isWhitespace(javaVersion))
            {
                javaVersion = "unknown";
            }
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("008000", pluginManager.getVersionForBundle("org.datanucleus"), javaVersion, System.getProperty("os.name")));
            NucleusLogger.PERSISTENCE.debug("Persistence API : " + getApiName());
            if (config.hasPropertyNotNull(PropertyNames.PROPERTY_PERSISTENCE_UNIT_NAME))
            {
                NucleusLogger.PERSISTENCE.debug("Persistence-Unit : " + config.getStringProperty(PropertyNames.PROPERTY_PERSISTENCE_UNIT_NAME));
            }
            NucleusLogger.PERSISTENCE.debug("Plugin Registry : " + pluginManager.getRegistryClassName());

            Object primCL = config.getProperty(PropertyNames.PROPERTY_CLASSLOADER_PRIMARY);
            String clrName = config.getStringProperty(PropertyNames.PROPERTY_CLASSLOADER_RESOLVER_NAME);
            if (clrName == null)
            {
                clrName = "default";
            }
            NucleusLogger.PERSISTENCE.debug("ClassLoading : " + clrName + (primCL != null ? ("primary=" + primCL) : ""));

            logConfigurationDetails();

            NucleusLogger.PERSISTENCE.debug("================================================");
        }
    }

    /**
     * Convenience method so that extending implementations can log their own configuration.
     */
    protected abstract void logConfigurationDetails();
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy