Package org.jpox.jdo

Source Code of org.jpox.jdo.JDOPersistenceManagerFactory

/**********************************************************************
Copyright (c) 2007 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.jpox.jdo;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.jdo.JDOException;
import javax.jdo.JDOUserException;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.listener.InstanceLifecycleListener;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;

import org.jpox.ClassLoaderResolver;
import org.jpox.ConnectionManagerImpl;
import org.jpox.api.ApiAdapterFactory;
import org.jpox.exceptions.ClassNotResolvedException;
import org.jpox.exceptions.JPOXException;
import org.jpox.metadata.PersistenceUnitMetaData;
import org.jpox.metadata.TransactionType;
import org.jpox.util.ClassUtils;
import org.jpox.util.JPOXLogger;
import org.jpox.util.StringUtils;

/**
* Implementation of a JDO PersistenceManagerFactory, used to obtain PersistenceManager instances.
*/
public class JDOPersistenceManagerFactory extends AbstractPersistenceManagerFactory
    implements PersistenceManagerFactory, ObjectFactory, Referenceable
{
    /** Datastore driver name property. */
    public static final String JDO_DATASTORE_DRIVERNAME_PROPERTY = "javax.jdo.option.ConnectionDriverName";

    /** Datastore URL property. */
    public static final String JDO_DATASTORE_URL_PROPERTY = "javax.jdo.option.ConnectionURL";

    /** Datastore connection username property. */
    public static final String JDO_DATASTORE_USERNAME_PROPERTY = "javax.jdo.option.ConnectionUserName";

    /** Datastore connection password property. */
    public static final String JDO_DATASTORE_PASSWORD_PROPERTY = "javax.jdo.option.ConnectionPassword";

    /** Mapping suffix property. */
    public static final String JDO_MAPPING_PROPERTY = "javax.jdo.option.Mapping";

    /** JDO Transaction type property. */
    public static final String JDO_TRANSACTION_TYPE_PROPERTY = "javax.jdo.option.TransactionType";

    /** "persistence-unit" name property. */
    public static final String JDO_PERSISTENCE_UNIT_NAME_PROPERTY = "javax.jdo.option.PersistenceUnitName";

    /**
     * Return a new PersistenceManagerFactoryImpl with options set according to the given Properties.
     * This method exists for JDO1 compliance whereas in JDO2 the method takes a Map.
     * @param overridingProps The Properties to initialize the PersistenceManagerFactory with.
     * @return A PersistenceManagerFactoryImpl with options set according to the given Properties.
     * @see javax.jdo.JDOHelper#getPersistenceManagerFactory(java.util.Map)
     */
    public synchronized static PersistenceManagerFactory getPersistenceManagerFactory(Properties overridingProps)
    {
        // Extract the properties into a Map allowing for a Properties object being used
        Map overridingMap = new HashMap();
        for (Enumeration e = overridingProps.propertyNames() ; e.hasMoreElements() ;)
        {
            // Make sure we handle default properties too (SUN Properties class oddness)
            String param = (String)e.nextElement();
            overridingMap.put(param, overridingProps.getProperty(param));
        }

        // Create the PMF and freeze it (JDO spec $11.7)
        final JDOPersistenceManagerFactory pmf = createInstance(overridingMap);
        pmf.freezeConfiguration();

        return pmf;
    }

    /**
     * Return a new PersistenceManagerFactoryImpl with options set according to the given Properties.
     * @param overridingProps The Map of properties to initialize the PersistenceManagerFactory with.
     * @return A PersistenceManagerFactoryImpl with options set according to the given Properties.
     * @see javax.jdo.JDOHelper#getPersistenceManagerFactory(java.util.Map)
     */
    public synchronized static PersistenceManagerFactory getPersistenceManagerFactory(Map overridingProps)
    {
        // Extract the properties into a Map allowing for a Properties object being used
        Map overridingMap = null;
        if (overridingProps instanceof Properties)
        {
            // Make sure we handle default properties too (SUN Properties class oddness)
            overridingMap = new HashMap();
            for (Enumeration e = ((Properties)overridingProps).propertyNames() ; e.hasMoreElements() ;)
            {
                String param = (String)e.nextElement();
                overridingMap.put(param, ((Properties)overridingProps).getProperty(param));
            }
        }
        else
        {
            overridingMap = overridingProps;
        }

        // Create the PMF and freeze it (JDO spec $11.7)
        final JDOPersistenceManagerFactory pmf = createInstance(overridingMap);
        pmf.freezeConfiguration();

        return pmf;
    }

    /**
     * Return a new PersistenceManagerFactoryImpl with options set according to the given properties and
     * given overrides.
     * @param overrides Map of properties to override the supplied props (if any)
     * @param props Map of properties to initialise the PMF with
     * @return A PersistenceManagerFactoryImpl with options set according to the given Properties
     */
    public synchronized static PersistenceManagerFactory getPersistenceManagerFactory(Map overrides, Map props)
    {
        // Extract the props into a Map allowing for a Properties object being used
        Map propsMap = null;
        if (props instanceof Properties)
        {
            // Make sure we handle default properties too (SUN Properties class oddness)
            propsMap = new HashMap();
            for (Enumeration e = ((Properties)props).propertyNames() ; e.hasMoreElements() ;)
            {
                String param = (String)e.nextElement();
                propsMap.put(param, ((Properties)props).getProperty(param));
            }
        }
        else
        {
            propsMap = props;
        }

        // Extract the overrides into a Map allowing for a Properties object being used
        Map overridesMap = null;
        if (overrides instanceof Properties)
        {
            // Make sure we handle default properties too (SUN Properties class oddness)
            overridesMap = new HashMap();
            for (Enumeration e = ((Properties)overrides).propertyNames() ; e.hasMoreElements() ;)
            {
                String param = (String)e.nextElement();
                overridesMap.put(param, ((Properties)overrides).getProperty(param));
            }
        }
        else
        {
            overridesMap = overrides;
        }

        // Set the properties of the PMF, taking propsMap+overridesMap
        Map overallMap = null;
        if (propsMap != null)
        {
            overallMap = new HashMap(propsMap);
        }
        else
        {
            overallMap = new HashMap();
        }
        if (overridesMap != null)
        {
            overallMap.putAll(overridesMap);
        }

        // Create the PMF and freeze it (JDO spec $11.7)
        final JDOPersistenceManagerFactory pmf = createInstance(overallMap);
        pmf.freezeConfiguration();

        return pmf;
    }

    /**
     * Constructs a new PersistenceManagerFactoryImpl.
     */
    public JDOPersistenceManagerFactory()
    {
        super();
        initialiseProperties(null);
    }

    /**
     * Constructs a new PersistenceManagerFactoryImpl.
     * @param props Persistent properties
     */
    public JDOPersistenceManagerFactory(Map props)
    {
        super();
        initialiseProperties(props);
    }

    /**
     * Convenience method to create a new PMF of this type.
     * TODO When we remove org.jpox.PersistenceManagerFactoryImpl remove this too.
     * @return The PMF
     */
    public static JDOPersistenceManagerFactory createInstance(Map props)
    {
        return new JDOPersistenceManagerFactory(props);
    }

    /**
     * Convenience method to set the API and properties that a PMF will use.
     * Process followed here is as follows :-
     * <ul>
     * <li>Apply any properties that affect startup resources (e.g plugin manager)</li>
     * <li>Create the OMFCOntext, which sets the default properties for JPOX as a whole</li>
     * <li>Set the API, and set the defult properties for the API as a whole</li>
     * <li>Apply user properties</li>
     * </ul>
     * @param props The properties to use for this PMF
     */
    protected void initialiseProperties(Map props)
    {
        // Apply any PMF properties that affect startup (before creating OMFContext)
        if (props != null)
        {
            Map startupProps = null;
            if (props.containsKey("org.jpox.plugin.pluginRegistryClassName"))
            {
                if (startupProps == null)
                {
                    startupProps = new HashMap();
                }
                startupProps.put("org.jpox.plugin.pluginRegistryClassName",
                    props.get("org.jpox.plugin.pluginRegistryClassName"));
            }
            if (props.containsKey("org.jpox.plugin.pluginRegistryBundleCheck"))
            {
                if (startupProps == null)
                {
                    startupProps = new HashMap();
                }
                startupProps.put("org.jpox.plugin.pluginRegistryBundleCheck",
                    props.get("org.jpox.plugin.pluginRegistryBundleCheck"));
            }
            if (props.containsKey("org.jpox.classLoaderResolverName"))
            {
                if (startupProps == null)
                {
                    startupProps = new HashMap();
                }
                startupProps.put("org.jpox.classLoaderResolverName",
                    props.get("org.jpox.classLoaderResolverName"));
            }
            if (startupProps != null)
            {
                try
                {
                    // TODO At this point we don't know about the properties of these names since defaults not loaded
                    // Have commented out warning in PersistenceConfiguration for now
                    setOptions(startupProps);
                }
                catch (JPOXException jpe)
                {
                    // Only throw JDOException and subclasses
                    throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
                }
            }
        }

        // Initialise the OMFContext and the ConnectionManager for J2SE
        initialiseOMFContext();
        omfContext.setConnectionManager(new ConnectionManagerImpl(omfContext));

        // Determine the API to be used by the PMF and apply its default props to the PMF
        String api = "JDO"; // Default to JDO unless specified
        if (props != null && props.get("org.jpox.persistenceApiName") != null)
        {
            api = (String)props.get("org.jpox.persistenceApiName");
        }
        omfContext.setApi(api); // Set the API used by the context
        setOptions(ApiAdapterFactory.getInstance().getApiAdapter(api).getDefaultFactoryProperties());

        // Generate the properties to apply to the PMF
        Map pmfProps = new HashMap();

        // J2SE : Use "ResourceLocal" transactions by default
        pmfProps.put(JDO_TRANSACTION_TYPE_PROPERTY, TransactionType.RESOURCE_LOCAL.toString());

        PersistenceUnitMetaData pumd = null;
        if (props != null)
        {
            String persistenceUnitName =
                (String)props.get(JDO_PERSISTENCE_UNIT_NAME_PROPERTY);
            if (persistenceUnitName != null)
            {
                // Specified to use a "persistence-unit", so take any props defined for the unit
                try
                {
                    pumd = omfContext.getMetaDataManager().getMetaDataForPersistenceUnit(persistenceUnitName);
                    if (pumd != null)
                    {
                        // Add the properties for the unit
                        if (pumd.getProperties() != null)
                        {
                            pmfProps.putAll(pumd.getProperties());
                        }
                    }
                    else
                    {
                        throw new JDOUserException(LOCALISER_JDO.msg("012004", persistenceUnitName));
                    }

                    if (omfContext.getApi().equalsIgnoreCase("JPA"))
                    {
                        pumd.clearJarFiles(); // Dont use JARs when in J2SE for JPA
                    }
                }
                catch (JPOXException jpe)
                {
                    throw new JDOUserException(LOCALISER_JDO.msg("012005", persistenceUnitName));
                }
            }
        }

        // Append on any user properties
        if (props != null)
        {
            pmfProps.putAll(props);
        }

        // Apply the properties to the PMF
        try
        {
            setOptions(pmfProps);
        }
        catch (JPOXException jpe)
        {
            // Only throw JDOException and subclasses
            throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
        }

        if (pumd != null)
        {
            // Initialise the MetaDataManager with all files/classes for this persistence-unit
            // This is done now that all PMF properties are set (including the persistence-unit props)
            try
            {
                omfContext.getMetaDataManager().initialise(pumd, omfContext.getClassLoaderResolver(null));
            }
            catch (JPOXException jpe)
            {
                throw new JDOException(jpe.getMessage(),jpe);
            }
        }

        if (props != null)
        {
            // Process any lifecycle listeners defined in persistent properties
            Iterator propsIter = props.keySet().iterator();
            while (propsIter.hasNext())
            {
                String key = (String)propsIter.next();
                if (key.startsWith("javax.jdo.listener.InstanceLifecycleListener"))
                {
                    String listenerClsName = key.substring(45);
                    String listenerClasses = (String)props.get(key);
                    ClassLoaderResolver clr = omfContext.getClassLoaderResolver(null);
                    Class listenerCls = null;
                    try
                    {
                        listenerCls = clr.classForName(listenerClsName);
                    }
                    catch (ClassNotResolvedException cnre)
                    {
                        throw new JDOUserException(LOCALISER_JDO.msg("012022", listenerClsName));
                    }

                    InstanceLifecycleListener listener = null;

                    // Find method getInstance()
                    Method method = ClassUtils.getMethodForClass(listenerCls, "getInstance", null);
                    if (method != null)
                    {
                        // Create instance via getInstance()
                        try
                        {
                            listener = (InstanceLifecycleListener)method.invoke(null, null);
                        }
                        catch (Exception e)
                        {
                            throw new JDOUserException(LOCALISER_JDO.msg("012021", listenerClsName), e);
                        }
                    }
                    else
                    {
                        // Try default constructor
                        try
                        {
                            listener = (InstanceLifecycleListener)listenerCls.newInstance();
                        }
                        catch (Exception e)
                        {
                            throw new JDOUserException(LOCALISER_JDO.msg("012020", listenerClsName), e);
                        }
                    }

                    Class[] classes = null;
                    if (!StringUtils.isWhitespace(listenerClasses))
                    {
                        String[] classNames = StringUtils.split(listenerClasses, ",");
                        classes = new Class[classNames.length];
                        for (int i=0;i<classNames.length;i++)
                        {
                            classes[i] = clr.classForName(classNames[i]);
                        }
                    }

                    addInstanceLifecycleListener(listener, classes);
                }
            }
        }
    }

    /**
     * Freezes the current configuration.
     * @throws JPOXException if the configuration was invalid or inconsistent in some way
     */
    protected void freezeConfiguration()
    {
        if (configurable)
        {
            if (omfContext == null)
            {
                // User has instantiated a PMF via the default constructor and JavaBean setters,
                // so make sure we have the OMFContext etc ready
                initialiseOMFContext();
                omfContext.setConnectionManager(new ConnectionManagerImpl(omfContext));
            }
            super.freezeConfiguration();
        }
    }

    /**
     * Get an instance of <tt>PersistenceManager</tt> from this factory. The instance has default values for options.
     * <p>After the first use of getPersistenceManager, no "set" methods will succeed.</p>
     * @return a <tt>PersistenceManager</tt> instance with default options.
     */
    public synchronized PersistenceManager getPersistenceManager()
    {
        // Just relay to other getPersistenceManager() method
        return getPersistenceManager(this.getPersistenceConfiguration().getStringProperty("org.jpox.ConnectionUserName"),
            this.getPersistenceConfiguration().getStringProperty("org.jpox.ConnectionPassword"));
    }

    /**
     * Get an instance of <tt>PersistenceManager</tt> from this factory.
     * The instance has default values for options. The parameters userid/password are used when obtaining
     * datastore connections from the connection pool.
     * <p>After the first use of getPersistenceManager, no "set" methods will succeed.</p>
     * @param userName  the user name for the connection
     * @param password  the password for the connection
     * @return <tt>PersistenceManager</tt> instance with default options.
     */
    public synchronized PersistenceManager getPersistenceManager(String userName, String password)
    {
        assertIsOpen();

        // Freeze the PMF config now that we are handing out PM's
        freezeConfiguration();

        PersistenceManager pm = new JDOPersistenceManager(this, userName, password);

        if (lifecycleListeners != null)
        {
            // Add PMF lifecycle listeners to the PM
            Iterator listenerIter = lifecycleListeners.iterator();
            while (listenerIter.hasNext())
            {
                LifecycleListenerForClass listener = (LifecycleListenerForClass) listenerIter.next();
                pm.addInstanceLifecycleListener(listener.getListener(), listener.getClasses());
            }
        }

        getPmCache().add(pm);

        return pm;
    }

    /**
     * Equality operator.
     * @param obj Object to compare against
     * @return Whether the objects are the same.
     */
    public synchronized boolean equals(Object obj)
    {
        if (obj == this)
        {
            return true;
        }

        if (!(obj instanceof JDOPersistenceManagerFactory))
        {
            return false;
        }

        return super.equals(obj);
    }

    /**
     * Create a PMF using the (JNDI) location or reference information specified.
     * @param obj The object
     * @param name Name of the object relative to the context
     * @param ctx The context
     * @param env properties used for creating the object
     * @return The PMF instance
     * @throws Exception If an error occurs generating the referenced object
     */
    public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable env)
    throws Exception
    {
        JDOPersistenceManagerFactory pmf = null;
        if (JPOXLogger.NAMING.isDebugEnabled())
        {
            JPOXLogger.NAMING.debug("Creating PersistenceManagerFactory instance via JNDI with values "+
                                    "[object] " + (obj == null ? "" : obj.toString()) + " " +
                                    "[name] " + (name == null ? "" : name.toString()) + " " +
                                    "[context] " + (ctx == null ? "" : ctx.toString()) + " " +
                                    "[env] " + (env == null ? "" : env.toString()) + " ");
        }

        if (obj instanceof Reference)
        {
            Reference ref = (Reference) obj;
            if (ref.getClassName().equals(JDOClassNameConstants.JDOPersistenceManagerFactory) ||
                ref.getClassName().equals(JDOClassNameConstants.JAVAX_JDO_PersistenceManagerFactory))
            {
                // Extract the properties to use for PMF creation
                Properties p = new Properties();
                for (Enumeration e = ref.getAll(); e.hasMoreElements();)
                {
                    StringRefAddr sra = (StringRefAddr) e.nextElement();
                    p.setProperty(sra.getType(), (String) sra.getContent());
                }

                // Create the PMF
                pmf = createInstance(p);

                // Freeze the PMF config now that we are handing out PM's : see JDO 1.0.1 [11.7]
                pmf.freezeConfiguration();

                if (JPOXLogger.NAMING.isDebugEnabled())
                {
                    JPOXLogger.NAMING.debug(LOCALISER_JDO.msg("012006", name.toString()));
                }
            }
            else
            {
                JPOXLogger.NAMING.warn(LOCALISER_JDO.msg("012007",
                    ref.getClassName(), JDOClassNameConstants.JDOPersistenceManagerFactory));
            }
        }
        else
        {
            JPOXLogger.NAMING.warn(LOCALISER_JDO.msg("012008", (obj.getClass().getName())));
        }
        return pmf;
    }

    /**
     * Retrieves the (JNDI) reference of this PMF object.
     * @return The reference
     */
    public Reference getReference()
    {
        Reference rc = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try
        {
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            rc = new Reference(JDOClassNameConstants.JAVAX_JDO_PersistenceManagerFactory,
                JDOClassNameConstants.JDOPersistenceManagerFactory, null);
           
            Map p = getOptions();
            for (Iterator i = p.keySet().iterator(); i.hasNext();)
            {
                String key = (String) i.next();
                if (p.get(key) instanceof String)
                {
                    String value = (String) p.get(key);
                    rc.add(new StringRefAddr(key, value));
                    if (JPOXLogger.NAMING.isDebugEnabled())
                    {
                        JPOXLogger.NAMING.debug(LOCALISER_JDO.msg("012009", key, value));
                    }
                }
                else if (p.get(key) instanceof Long)
                {
                    String value = "" + p.get(key);
                    rc.add(new StringRefAddr(key, value));
                    if (JPOXLogger.NAMING.isDebugEnabled())
                    {
                        JPOXLogger.NAMING.debug(LOCALISER_JDO.msg("012009", key, value));
                    }
                }
                else if (p.get(key) instanceof Integer)
                {
                    String value = "" + p.get(key);
                    rc.add(new StringRefAddr(key, value));
                    if (JPOXLogger.NAMING.isDebugEnabled())
                    {
                        JPOXLogger.NAMING.debug(LOCALISER_JDO.msg("012009", key, value));
                    }
                }
                else if (p.get(key) instanceof Boolean)
                {
                    String value = (((Boolean)p.get(key)).booleanValue() ? "true" : "false");
                    rc.add(new StringRefAddr(key, value));
                    if (JPOXLogger.NAMING.isDebugEnabled())
                    {
                        JPOXLogger.NAMING.debug(LOCALISER_JDO.msg("012009", key, value));
                    }
                }
                else
                {
                    JPOXLogger.NAMING.warn(LOCALISER_JDO.msg("012010", key));
                }
            }
            if (JPOXLogger.NAMING.isDebugEnabled())
            {
                if (p.isEmpty())
                {
                    JPOXLogger.NAMING.debug(LOCALISER_JDO.msg("012011"));
                }
            }
        }
        catch (IOException ex)
        {
            JPOXLogger.NAMING.error(ex.getMessage());
            throw new JPOXException(ex.getMessage(),ex);
        }
        return rc;
    }

    /**
     * Accessor for the PersistenceManager proxy object
     * @return The PMF proxy
     */
    public PersistenceManager getPersistenceManagerProxy()
    {
        throw new UnsupportedOperationException("PMF.getPersistenceManagerProxy() not yet implemented");
    }
}
TOP

Related Classes of org.jpox.jdo.JDOPersistenceManagerFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.