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

javax.jdo.spi.JDOImplHelper Maven / Gradle / Ivy

Go to download

The Java Data Objects (JDO) API is a standard interface-based Java model abstraction of persistence, developed as Java Specification Request 243 under the auspices of the Java Community Process.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/*
 * JDOImplHelper.java
 *
 */

package javax.jdo.spi;

import org.xml.sax.ErrorHandler;

import javax.jdo.LegacyJava;
import javax.jdo.LegacyJava.SecurityManager;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;
import java.security.PrivilegedAction;

import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Currency;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import javax.jdo.*;
import javax.xml.parsers.DocumentBuilderFactory;

/** This class is a helper class for JDO implementations.  It contains methods
 * to register metadata for persistence-capable classes and to perform common
 * operations needed by implementations, not by end users.
 * 

JDOImplHelper allows construction of instances of * persistence-capable classes without using reflection. *

Persistence-capable classes register themselves via a static method * at class load time. * There is no security restriction on this access. JDO implementations * get access to the functions provided by this class only if they are * authorized by the security manager. To avoid having every call go through * the security manager, only the call to get an instance is checked. Once an * implementation * has an instance, any of the methods can be invoked without security checks. * @version 2.1 * */ public class JDOImplHelper extends java.lang.Object { /** This synchronized HashMap contains a static mapping of * PersistenceCapable class to * metadata for the class used for constructing new instances. New entries * are added by the static method in each PersistenceCapable * class. Entries are never removed. */ private static Map registeredClasses = Collections.synchronizedMap(new HashMap ()); /** This Set contains all classes that have registered for setStateManager * permissions via authorizeStateManagerClass. * Only the key is used in order to maintain a weak set of classes. */ private static final Map authorizedStateManagerClasses = new WeakHashMap(); /** This list contains the registered listeners for * RegisterClassEvents. */ private static final List listeners = new ArrayList(); /** The list of registered StateInterrogation instances */ private static List stateInterrogations = new ArrayList(); /** The singleton JDOImplHelper instance. */ private static JDOImplHelper jdoImplHelper = new JDOImplHelper(); /** The Internationalization message helper. */ private final static I18NHelper msg = I18NHelper.getInstance ("javax.jdo.Bundle"); //NOI18N /** The DateFormat pattern. */ private static String dateFormatPattern; /** The default DateFormat instance. */ private static DateFormat dateFormat; /** * The DocumentBuilderFactory used during jdoconfig.xml parsing. */ private static DocumentBuilderFactory documentBuilderFactory; /** * The ErrorHandler used during jdoconfig.xml parsing. */ private static ErrorHandler errorHandler; /** * JDO standard properties that the user can configure. */ public static final Set USER_CONFIGURABLE_STANDARD_PROPERTIES = createUserConfigurableStandardProperties(); private static Set createUserConfigurableStandardProperties() { Set props = new HashSet(); props.add(Constants.PROPERTY_CONNECTION_DRIVER_NAME); props.add(Constants.PROPERTY_CONNECTION_FACTORY2_NAME); props.add(Constants.PROPERTY_CONNECTION_FACTORY_NAME); props.add(Constants.PROPERTY_CONNECTION_PASSWORD); props.add(Constants.PROPERTY_CONNECTION_URL); props.add(Constants.PROPERTY_CONNECTION_USER_NAME); props.add(Constants.PROPERTY_COPY_ON_ATTACH); props.add(Constants.PROPERTY_DATASTORE_READ_TIMEOUT_MILLIS); props.add(Constants.PROPERTY_DATASTORE_WRITE_TIMEOUT_MILLIS); props.add(Constants.PROPERTY_DETACH_ALL_ON_COMMIT); props.add(Constants.PROPERTY_IGNORE_CACHE); props.add(Constants.PROPERTY_INSTANCE_LIFECYCLE_LISTENER); props.add(Constants.PROPERTY_MAPPING); props.add(Constants.PROPERTY_MAPPING_CATALOG); props.add(Constants.PROPERTY_MAPPING_SCHEMA); props.add(Constants.PROPERTY_MULTITHREADED); props.add(Constants.PROPERTY_NAME); props.add(Constants.PROPERTY_NONTRANSACTIONAL_READ); props.add(Constants.PROPERTY_NONTRANSACTIONAL_WRITE); props.add(Constants.PROPERTY_OPTIMISTIC); props.add(Constants.PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS); props.add(Constants.PROPERTY_PERSISTENCE_UNIT_NAME); props.add(Constants.PROPERTY_READONLY); props.add(Constants.PROPERTY_RESTORE_VALUES); props.add(Constants.PROPERTY_RETAIN_VALUES); props.add(Constants.PROPERTY_SERVER_TIME_ZONE_ID); props.add(Constants.PROPERTY_SPI_RESOURCE_NAME); props.add(Constants.PROPERTY_TRANSACTION_ISOLATION_LEVEL); props.add(Constants.PROPERTY_TRANSACTION_TYPE); return Collections.unmodifiableSet(props); } static final String JAVAX_JDO_PREFIX_LOWER_CASED = Constants.JAVAX_JDO_PREFIX.toLowerCase(); static final String PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER_LOWER_CASED = Constants.PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER.toLowerCase(); static final Set USER_CONFIGURABLE_STANDARD_PROPERTIES_LOWER_CASED = createUserConfigurableStandardPropertiesLowerCased(); static Set createUserConfigurableStandardPropertiesLowerCased() { Set mixedCased = createUserConfigurableStandardProperties(); Set lowerCased = new HashSet(mixedCased.size()); for (String propertyName : mixedCased) { lowerCased.add(propertyName.toLowerCase()); } return Collections.unmodifiableSet(lowerCased); } /** Register the default DateFormat instance. */ static { jdoImplHelper.registerDateFormat(getDateTimeInstance()); } /** Creates new JDOImplHelper */ private JDOImplHelper() { } /** Get an instance of JDOImplHelper. This method * checks that the caller is authorized for * JDOPermission("getMetadata"), and if not, throws * SecurityException. * @return an instance of JDOImplHelper. * @throws SecurityException if the caller is not authorized for * JDOPermission("getMetadata"). */ public static JDOImplHelper getInstance() throws SecurityException { SecurityManager sec = LegacyJava.getSecurityManager(); if (sec != null) { // throws exception if caller is not authorized sec.checkPermission (JDOPermission.GET_METADATA); } return jdoImplHelper; } /** Get the field names for a PersistenceCapable class. The * order of fields is the natural ordering of the String class * (without considering localization). * @param pcClass the PersistenceCapable class. * @return the field names for the class. */ public String[] getFieldNames (Class pcClass) { Meta meta = getMeta (pcClass); return meta.getFieldNames(); } /** Get the field types for a PersistenceCapable class. The * order of fields is the same as for field names. * @param pcClass the PersistenceCapable class. * @return the field types for the class. */ public Class[] getFieldTypes (Class pcClass) { Meta meta = getMeta (pcClass); return meta.getFieldTypes(); } /** Get the field flags for a PersistenceCapable class. The * order of fields is the same as for field names. * @param pcClass the PersistenceCapable class. * @return the field types for the class. */ public byte[] getFieldFlags (Class pcClass) { Meta meta = getMeta (pcClass); return meta.getFieldFlags(); } /** Get the persistence-capable superclass for a * PersistenceCapable class. * @param pcClass the PersistenceCapable class. * @return The PersistenceCapable superclass for this class, * or null if there isn't one. */ public Class getPersistenceCapableSuperclass (Class pcClass) { Meta meta = getMeta (pcClass); return meta.getPersistenceCapableSuperclass(); } /** Create a new instance of the class and assign its * jdoStateManager. The new instance has its * jdoFlags set to LOAD_REQUIRED. * @see PersistenceCapable#jdoNewInstance(StateManager sm) * @param pcClass the PersistenceCapable class. * @param sm the StateManager which will own the new instance. * @return the new instance, or null if the class is not * registered. */ public PersistenceCapable newInstance (Class pcClass, StateManager sm) { Meta meta = getMeta (pcClass); PersistenceCapable pcInstance = meta.getPC(); return pcInstance == null?null:pcInstance.jdoNewInstance(sm); } /** Create a new instance of the class and assign its * jdoStateManager and key values from the ObjectId. If the * oid parameter is null, no key values are copied. * The new instance has its jdoFlags set to * LOAD_REQUIRED. * @see PersistenceCapable#jdoNewInstance(StateManager sm, Object oid) * @param pcClass the PersistenceCapable class. * @param sm the StateManager which will own the new instance. * @return the new instance, or null if the class is not * registered. * @param oid the ObjectId instance from which to copy key field values. */ public PersistenceCapable newInstance (Class pcClass, StateManager sm, Object oid) { Meta meta = getMeta (pcClass); PersistenceCapable pcInstance = meta.getPC(); return pcInstance == null?null:pcInstance.jdoNewInstance(sm, oid); } /** Create a new instance of the ObjectId class of this * PersistenceCapable class. * It is intended only for application identity. This method should * not be called for classes that use single field identity; * newObjectIdInstance(Class, Object) should be used instead. * If the class has been * enhanced for datastore identity, or if the class is abstract, * null is returned. * @param pcClass the PersistenceCapable class. * @return the new ObjectId instance, or null if the class * is not registered. */ public Object newObjectIdInstance (Class pcClass) { Meta meta = getMeta (pcClass); PersistenceCapable pcInstance = meta.getPC(); return pcInstance == null?null:pcInstance.jdoNewObjectIdInstance(); } /** Create a new instance of the class used by the parameter Class * for JDO identity, using the * key constructor of the object id class. It is intended for single * field identity. The identity * instance returned has no relationship with the values of the primary key * fields of the persistence-capable instance on which the method is called. * If the key is the wrong class for the object id class, null is returned. *

For classes that use single field identity, if the parameter is * of one of the following types, the behavior must be as specified: *

  • Number or Character: the * parameter must be the single field * type or the wrapper class of the primitive field type; the parameter * is passed to the single field identity constructor *
  • ObjectIdFieldSupplier: the field value * is fetched from the ObjectIdFieldSupplier and passed to the * single field identity constructor *
  • String: the String is passed to the * single field identity constructor *
* @return the new ObjectId instance, or null * if the class is not registered. * @param obj the Object form of the object id * @param pcClass the PersistenceCapable class. * @since 2.0 */ public Object newObjectIdInstance (Class pcClass, Object obj) { Meta meta = getMeta (pcClass); PersistenceCapable pcInstance = meta.getPC(); return (pcInstance == null)?null:pcInstance.jdoNewObjectIdInstance(obj); } /** Copy fields from an outside source to the key fields in the ObjectId. * This method is generated in the PersistenceCapable class to * generate a call to the field manager for each key field in the ObjectId. *

For example, an ObjectId class that has three key fields * (int id, String name, and * Float salary) would have the method generated: *

* void jdoCopyKeyFieldsToObjectId (Object oid, ObjectIdFieldSupplier fm) { *
oid.id = fm.fetchIntField (0); *
oid.name = fm.fetchStringField (1); *
oid.salary = fm.fetchObjectField (2); *
}
*

The implementation is responsible for implementing the * ObjectIdFieldSupplier to provide the values for the key * fields. * @param pcClass the PersistenceCapable Class. * @param oid the ObjectId target of the copy. * @param fm the field manager that supplies the field values. */ public void copyKeyFieldsToObjectId (Class pcClass, PersistenceCapable.ObjectIdFieldSupplier fm, Object oid) { Meta meta = getMeta (pcClass); PersistenceCapable pcInstance = meta.getPC(); if (pcInstance == null) { throw new JDOFatalInternalException (msg.msg( "ERR_AbstractClassNoIdentity", pcClass.getName())); //NOI18N } pcInstance.jdoCopyKeyFieldsToObjectId(fm, oid); } /** Copy fields to an outside source from the key fields in the ObjectId. * This method is generated in the PersistenceCapable class to * generate a call to the field manager for each key field in the ObjectId. * For example, an ObjectId class that has three key fields * (int id, String name, and * Float salary) would have the method generated: *

void jdoCopyKeyFieldsFromObjectId *
(PersistenceCapable oid, ObjectIdFieldConsumer fm) { *
fm.storeIntField (0, oid.id); *
fm.storeStringField (1, oid.name); *
fm.storeObjectField (2, oid.salary); *
}
*

The implementation is responsible for implementing the * ObjectIdFieldConsumer to store the values for the key * fields. * @param pcClass the PersistenceCapable class * @param oid the ObjectId source of the copy. * @param fm the field manager that receives the field values. */ public void copyKeyFieldsFromObjectId (Class pcClass, PersistenceCapable.ObjectIdFieldConsumer fm, Object oid) { Meta meta = getMeta (pcClass); PersistenceCapable pcInstance = meta.getPC(); if (pcInstance == null) { throw new JDOFatalInternalException (msg.msg( "ERR_AbstractClassNoIdentity", pcClass.getName())); //NOI18N } pcInstance.jdoCopyKeyFieldsFromObjectId(fm, oid); } /** Register metadata by class. The registration will be done in the * class named JDOImplHelper loaded by the same or an * ancestor class loader as the PersistenceCapable class * performing the registration. * * @param pcClass the PersistenceCapable class * used as the key for lookup. * @param fieldNames an array of String field names for * persistent and transactional fields * @param fieldTypes an array of Class field types * @param fieldFlags the Field Flags for persistent and transactional fields * @param pc an instance of the PersistenceCapable class * @param persistenceCapableSuperclass the most immediate superclass that is * PersistenceCapable */ public static void registerClass (Class pcClass, String[] fieldNames, Class[] fieldTypes, byte[] fieldFlags, Class persistenceCapableSuperclass, PersistenceCapable pc) { if (pcClass == null) throw new NullPointerException(msg.msg("ERR_NullClass")); //NOI18N Meta meta = new Meta (fieldNames, fieldTypes, fieldFlags, persistenceCapableSuperclass, pc); registeredClasses.put (pcClass, meta); // handle class registration listeners synchronized (listeners) { if (!listeners.isEmpty()) { RegisterClassEvent event = new RegisterClassEvent( jdoImplHelper, pcClass, fieldNames, fieldTypes, fieldFlags, persistenceCapableSuperclass); for (Iterator i = listeners.iterator(); i.hasNext();) { RegisterClassListener crl = (RegisterClassListener)i.next(); if (crl != null) { crl.registerClass(event); } } } } } /** * Unregister metadata by class loader. This method unregisters all * registered PersistenceCapable classes loaded by the * specified class loader. Any attempt to get metadata for unregistered * classes will result in a JDOFatalUserException. * @param cl the class loader. * @since 1.0.2 */ public void unregisterClasses (ClassLoader cl) { SecurityManager sec = LegacyJava.getSecurityManager(); if (sec != null) { // throws exception if caller is not authorized sec.checkPermission (JDOPermission.MANAGE_METADATA); } synchronized(registeredClasses) { for (Iterator i = registeredClasses.keySet().iterator(); i.hasNext();) { Class pcClass = (Class)i.next(); // Note, the pc class was registered by calling the static // method JDOImplHelper.registerClass. This means the // JDOImplHelper class loader is the same as or an ancestor // of the class loader of the pc class. In this case method // getClassLoader does not perform a security check for // RuntimePermission("getClassLoader") and thus we do not // need a privileged block for the getClassLoader call. if ((pcClass != null) && (pcClass.getClassLoader() == cl)) { // unregister pc class, if its class loader is the // specified one. i.remove(); } } } } /** * Unregister metadata by class. This method unregisters the specified * class. Any further attempt to get metadata for the specified class will * result in a JDOFatalUserException. * @param pcClass the PersistenceCapable class to be * unregistered. * @since 1.0.2 */ public void unregisterClass (Class pcClass) { if (pcClass == null) throw new NullPointerException(msg.msg("ERR_NullClass")); //NOI18N SecurityManager sec = LegacyJava.getSecurityManager(); if (sec != null) { // throws exception if caller is not authorized sec.checkPermission (JDOPermission.MANAGE_METADATA); } registeredClasses.remove(pcClass); } /** * Add the specified RegisterClassListener to the listener * list. * @param crl the listener to be added */ public void addRegisterClassListener (RegisterClassListener crl) { HashSet alreadyRegisteredClasses = null; synchronized (listeners) { listeners.add(crl); // Make a copy of the existing set of registered classes. // Between these two lines of code, any number of new class // registrations might occur, and will then all wait until this // synchronized block completes. Some of the class registrations // might be delivered twice to the newly registered listener. alreadyRegisteredClasses = new HashSet (registeredClasses.keySet()); } // new registrations will call the new listener while the following // occurs notify the new listener about already-registered classes for (Iterator it = alreadyRegisteredClasses.iterator(); it.hasNext();) { Class pcClass = (Class)it.next(); Meta meta = getMeta (pcClass); RegisterClassEvent event = new RegisterClassEvent( this, pcClass, meta.getFieldNames(), meta.getFieldTypes(), meta.getFieldFlags(), meta.getPersistenceCapableSuperclass()); crl.registerClass (event); } } /** * Remove the specified RegisterClassListener from the listener * list. * @param crl the listener to be removed */ public void removeRegisterClassListener (RegisterClassListener crl) { synchronized (listeners) { listeners.remove(crl); } } /** * Returns a collection of class objects of the registered * persistence-capable classes. * @return registered persistence-capable classes */ public Collection getRegisteredClasses() { return Collections.unmodifiableCollection(registeredClasses.keySet()); } /** Look up the metadata for a PersistenceCapable class. * @param pcClass the Class. * @return the Meta for the Class. */ private static Meta getMeta (Class pcClass) { Meta ret = (Meta) registeredClasses.get (pcClass); if (ret == null) { throw new JDOFatalUserException( msg.msg ("ERR_NoMetadata", pcClass.getName())); //NOI18N } return ret; } /** Register a class authorized to replaceStateManager. The caller of * this method must be authorized for JDOPermission("setStateManager"). * During replaceStateManager, a persistence-capable class will call * the corresponding checkAuthorizedStateManager and the class of the * instance of the parameter must have been registered. * @param smClass a Class that is authorized for * JDOPermission("setStateManager"). * @throws SecurityException if the caller is not authorized for * JDOPermission("setStateManager"). * @since 1.0.1 */ public static void registerAuthorizedStateManagerClass (Class smClass) throws SecurityException { if (smClass == null) throw new NullPointerException(msg.msg("ERR_NullClass")); //NOI18N SecurityManager sm = LegacyJava.getSecurityManager(); if (sm != null) { sm.checkPermission(JDOPermission.SET_STATE_MANAGER); } synchronized (authorizedStateManagerClasses) { authorizedStateManagerClasses.put(smClass, null); } } /** Register classes authorized to replaceStateManager. The caller of * this method must be authorized for JDOPermission("setStateManager"). * During replaceStateManager, a persistence-capable class will call * the corresponding checkAuthorizedStateManager and the class of the * instance of the parameter must have been registered. * @param smClasses a Collection of Classes that are authorized for * JDOPermission("setStateManager"). * @throws SecurityException if the caller is not authorized for * JDOPermission("setStateManager"). * @since 1.0.1 */ public static void registerAuthorizedStateManagerClasses ( Collection smClasses) throws SecurityException { SecurityManager sm = LegacyJava.getSecurityManager(); if (sm != null) { sm.checkPermission(JDOPermission.SET_STATE_MANAGER); synchronized (authorizedStateManagerClasses) { for (Iterator it = smClasses.iterator(); it.hasNext();) { Object smClass = it.next(); if (!(smClass instanceof Class)) { throw new ClassCastException( msg.msg("ERR_StateManagerClassCast", //NOI18N smClass.getClass().getName())); } registerAuthorizedStateManagerClass((Class)it.next()); } } } } /** * Register a DocumentBuilderFactory instance for use in parsing the * resource(s) META-INF/jdoconfig.xml. The default is governed by the * semantics of DocumentBuilderFactory.newInstance(). * * @param factory the DocumentBuilderFactory instance to use * @since 2.1 */ public synchronized void registerDocumentBuilderFactory( DocumentBuilderFactory factory) { documentBuilderFactory = factory; } /** * Return the registered instance of DocumentBuilderFactory. * @return the DocumentBuilderFactory if registered; null otherwise * @since 2.1 */ public static DocumentBuilderFactory getRegisteredDocumentBuilderFactory() { return documentBuilderFactory; } /** * Register an ErrorHandler instance for use in parsing the * resource(s) META-INF/jdoconfig.xml. The default is an ErrorHandler * that throws on error or fatalError and ignores warnings. * * @param handler the ErrorHandler instance to use * @since 2.1 */ public synchronized void registerErrorHandler(ErrorHandler handler) { errorHandler = handler; } /** * Return the registered instance of ErrorHandler. * @return the registered ErrorHandler if registered; null otherwise * @since 2.1 */ public static ErrorHandler getRegisteredErrorHandler() { return errorHandler; } /** Check that the parameter instance is of a class that is authorized for * JDOPermission("setStateManager"). This method is called by the * replaceStateManager method in persistence-capable classes. * A class that is passed as the parameter to replaceStateManager must be * authorized for JDOPermission("setStateManager"). To improve performance, * first the set of authorized classes is checked, and if not present, a * regular permission check is made. The regular permission check requires * that all callers on the stack, including the persistence-capable class * itself, must be authorized for JDOPermission("setStateManager"). * @param sm an instance of StateManager whose class is to be checked. * @since 1.0.1 */ public static void checkAuthorizedStateManager (StateManager sm) { checkAuthorizedStateManagerClass(sm.getClass()); } /** Check that the parameter instance is a class that is authorized for * JDOPermission("setStateManager"). This method is called by the * constructors of JDO Reference Implementation classes. * @param smClass a Class to be checked for JDOPermission("setStateManager") * @since 1.0.1 */ public static void checkAuthorizedStateManagerClass (Class smClass) { final SecurityManager scm = LegacyJava.getSecurityManager(); if (scm == null) { // if no security manager, no checking. return; } synchronized(authorizedStateManagerClasses) { if (authorizedStateManagerClasses.containsKey(smClass)) { return; } } // if not already authorized, perform "long" security checking. scm.checkPermission(JDOPermission.SET_STATE_MANAGER); } /** * Construct an instance of a key class using a String as input. * This is a helper interface for use with ObjectIdentity. * Classes without a String constructor (such as those in java.lang * and java.util) will use this interface for constructing new instances. * The result might be a singleton or use some other strategy. */ public interface StringConstructor { /** * Construct an instance of the class for which this instance * is registered. * @param s the parameter for construction * @return the constructed object */ public Object construct(String s); } /** * Special StringConstructor instances for use with specific * classes that have no public String constructor. The Map is * keyed on class instance and the value is an instance of * StringConstructor. */ static final Map stringConstructorMap = new HashMap(); /** * * Register special StringConstructor instances. These instances * are for constructing instances from String parameters where there * is no String constructor for them. * @param cls the class to register a StringConstructor for * @param sc the StringConstructor instance * @return the previous StringConstructor registered for this class */ public Object registerStringConstructor(Class cls, StringConstructor sc) { synchronized(stringConstructorMap) { return stringConstructorMap.put(cls, sc); } } /** Register the default special StringConstructor instances. */ static { if (isClassLoadable("java.util.Currency")) { jdoImplHelper.registerStringConstructor( Currency.class, new StringConstructor() { public Object construct(String s) { try { return Currency.getInstance(s); } catch (IllegalArgumentException ex) { throw new javax.jdo.JDOUserException(msg.msg( "EXC_CurrencyStringConstructorIllegalArgument", //NOI18N s), ex); } catch (Exception ex) { throw new JDOUserException(msg.msg( "EXC_CurrencyStringConstructorException"), //NOI18N ex); } } }); } jdoImplHelper.registerStringConstructor(Locale.class, new StringConstructor() { public Object construct(String s) { try { return getLocale(s); } catch (Exception ex) { throw new JDOUserException(msg.msg( "EXC_LocaleStringConstructorException"), ex); //NOI18N } } }); jdoImplHelper.registerStringConstructor(Date.class, new StringConstructor() { public synchronized Object construct(String s) { try { // first, try the String as a Long return new Date(Long.parseLong(s)); } catch (NumberFormatException ex) { // not a Long; try the formatted date ParsePosition pp = new ParsePosition(0); Date result = dateFormat.parse(s, pp); if (result == null) { throw new JDOUserException (msg.msg( "EXC_DateStringConstructor", new Object[] //NOI18N {s, pp.getErrorIndex(), dateFormatPattern})); } return result; } } }); } /** * Parse the String to a Locale. * @param s the name of the Locale * @return the Locale corresponding to the name */ private static Locale getLocale(String s) { String lang = s; int firstUnderbar = s.indexOf('_'); if (firstUnderbar == -1) { // nothing but language return new Locale(lang); } lang = s.substring(0, firstUnderbar); String country; int secondUnderbar = s.indexOf('_', firstUnderbar + 1); if (secondUnderbar == -1) { // nothing but language, country country = s.substring(firstUnderbar + 1); return new Locale(lang, country); } country = s.substring(firstUnderbar + 1, secondUnderbar); String variant = s.substring(secondUnderbar + 1); return new Locale(lang, country, variant); } /** * Determine if a class is loadable in the current environment. * @param className the fully-qualified name of the class * @return true if the class can be loaded; false otherwise */ private static boolean isClassLoadable(String className) { try { Class.forName(className); return true; } catch (ClassNotFoundException ex) { return false; } } /** * Construct an instance of the parameter class, using the keyString * as an argument to the constructor. If the class has a StringConstructor * instance registered, use it. If not, try to find a constructor for * the class with a single String argument. Otherwise, throw a * JDOUserException. * @param className the name of the class * @param keyString the String parameter for the constructor * @return the result of construction */ public static Object construct(String className, String keyString) { StringConstructor stringConstructor; try { Class keyClass = Class.forName(className); synchronized(stringConstructorMap) { stringConstructor = (StringConstructor) stringConstructorMap.get(keyClass); } if (stringConstructor != null) { return stringConstructor.construct(keyString); } else { Constructor keyConstructor = keyClass.getConstructor(new Class[]{String.class}); return keyConstructor.newInstance(new Object[]{keyString}); } } catch (JDOException ex) { throw ex; } catch (Exception ex) { /* ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException */ throw new JDOUserException( msg.msg("EXC_ObjectIdentityStringConstruction", //NOI18N new Object[] {ex.toString(), className, keyString}), ex); } } /** * Get the DateFormat instance for the default locale from the VM. * This requires the following privileges for JDOImplHelper in the * security permissions file: * permission java.util.PropertyPermission "user.country", "read"; * permission java.util.PropertyPermission "user.timezone", "read,write"; * permission java.util.PropertyPermission "java.home", "read"; * If these permissions are not present, or there is some other * problem getting the default date format, a simple formatter is returned. * @since 2.1 * @return the default date-time formatter */ static DateFormat getDateTimeInstance() { DateFormat result = null; try { result = doPrivileged ( new PrivilegedAction () { public DateFormat run () { return DateFormat.getDateTimeInstance(); } } ); } catch (Exception ex) { result = DateFormat.getInstance(); } return result; } @SuppressWarnings("unchecked") private static T doPrivileged(PrivilegedAction privilegedAction) { try { return (T) LegacyJava.doPrivilegedAction.invoke(null, privilegedAction); } catch (IllegalAccessException | InvocationTargetException e) { if (e.getCause() instanceof RuntimeException) { throw (RuntimeException) e.getCause(); } throw new JDOFatalInternalException(e.getMessage()); } } /** * Register a DateFormat instance for use with constructing Date * instances. The default is the default DateFormat instance. * If the new instance implements SimpleDateFormat, get its pattern * for error messages. * @since 2.0 * @param df the DateFormat instance to use */ public synchronized void registerDateFormat(DateFormat df) { dateFormat = df; if (df instanceof SimpleDateFormat) { dateFormatPattern = ((SimpleDateFormat)df).toPattern(); } else { dateFormatPattern = msg.msg("MSG_unknown"); //NOI18N } } /** This is a helper class to manage metadata per persistence-capable * class. The information is used at runtime to provide field names and * field types to the JDO Model. * * This is the value of the HashMap which * relates the PersistenceCapable Class * as a key to the metadata. */ static class Meta { /** Construct an instance of Meta. * @param fieldNames An array of String * @param fieldTypes An array of Class * @param fieldFlags an array of int * @param persistenceCapableSuperclass the most immediate * PersistenceCapable superclass * @param pc An instance of the PersistenceCapable class */ Meta (String[] fieldNames, Class[] fieldTypes, byte[] fieldFlags, Class persistenceCapableSuperclass, PersistenceCapable pc) { this.fieldNames = fieldNames; this.fieldTypes = fieldTypes; this.fieldFlags = fieldFlags; this.persistenceCapableSuperclass = persistenceCapableSuperclass; this.pc = pc; } /** This is an array of field names used * for the Model at runtime. The field * is passed by the static class initialization. */ String[] fieldNames; /** Get the field names from the metadata. * @return the array of field names. */ String[] getFieldNames() { return fieldNames; } /** This is an array of field types used * for the Model at runtime. The field * is passed by the static class initialization. */ Class[] fieldTypes; /** Get the field types from the metadata. * @return the array of field types. */ Class[] getFieldTypes() { return fieldTypes; } /** This is an array of field flags used * for the Model at runtime. The field * is passed by the static class initialization. */ byte[] fieldFlags; /** Get the field types from the metadata. * @return the array of field types. */ byte[] getFieldFlags() { return fieldFlags; } /** This is the Class instance of the * PersistenceCapable superclass. */ Class persistenceCapableSuperclass; /** Return the PersistenceCapable superclass. * @return the PersistenceCapable superclass */ Class getPersistenceCapableSuperclass() { return persistenceCapableSuperclass; } /** This is an instance of PersistenceCapable, * used at runtime to create new instances. */ PersistenceCapable pc; /** Get an instance of the PersistenceCapable class. * @return an instance of the PersistenceCapable Class. */ PersistenceCapable getPC() { return pc; } /** Return the string form of the metadata. * @return the string form */ public String toString() { return "Meta-" + pc.getClass().getName(); //NOI18N } } /** * Add a StateInterrogation to the list. Create a new list * in case there is an iterator open on the original list. * @param si the StateInterrogation to add */ public synchronized void addStateInterrogation(StateInterrogation si) { List newList = new ArrayList(stateInterrogations); newList.add(si); stateInterrogations = newList; } /** * Remove a StateInterrogation from the list. Create a new list * in case there is an iterator open on the original list. * @param si the StateInterrogation to remove */ public synchronized void removeStateInterrogation(StateInterrogation si) { List newList = new ArrayList(stateInterrogations); newList.remove(si); stateInterrogations = newList; } /** * Return an Iterator over all StateInterrogation instances. * Synchronize to avoid add/remove/iterate conflicts. * @return an Iterator over all StateInterrogation instances. */ private synchronized Iterator getStateInterrogationIterator() { return stateInterrogations.iterator(); } /** * Mark a non-binary-compatible instance dirty. Delegate to all * registered StateInterrogation instances until one of them * handles the call. * @param pc the instance to mark dirty * @param fieldName the field to mark dirty */ public void nonBinaryCompatibleMakeDirty(Object pc, String fieldName) { Iterator sit = getStateInterrogationIterator(); while (sit.hasNext()) { StateInterrogation si = (StateInterrogation)sit.next(); try { if (si.makeDirty(pc, fieldName)) return; } catch (Throwable t) { continue; // ignore exceptions from errant StateInterrogations } } } /** * Determine the state of a non-binary-compatible instance. * Delegate to all registered StateInterrogation instances until * one of them handles the call (returns a non-null Boolean * with the answer). * The caller provides the stateless "method object" that does * the actual call to the StateInterrogation instance. * @param pc the instance to be checked * @param sibr the method object that delegates to the * non-binary-compatible implementation * @return Boolean.TRUE if the instance satisfies the state interrogation; * Boolean.FALSE if the instance does not satisfy the interrogation; * or null if the implementation does not manage the class of the instance */ public boolean nonBinaryCompatibleIs(Object pc, StateInterrogationBooleanReturn sibr) { Iterator sit = getStateInterrogationIterator(); while (sit.hasNext()) { StateInterrogation si = (StateInterrogation)sit.next(); Boolean result; try { result = sibr.is(pc, si); } catch (Throwable t) { continue; // ignore exceptions from errant StateInterrogations } if (result != null) return result.booleanValue(); } return false; } /** * Return an object associated with a non-binary-compatible instance. * Delegate to all registered StateInterrogation instances until * one of them handles the call (returns a non-null answer). * The caller provides the stateless "method object" that does * the actual call to the StateInterrogation instance. * @param pc the instance whose associated object is needed * @param sibr the method object that delegates to the * non-binary-compatible implementation * @return the associated object or null if the implementation does not * manage the class of the instance */ public Object nonBinaryCompatibleGet(Object pc, StateInterrogationObjectReturn sibr) { Iterator sit = getStateInterrogationIterator(); while (sit.hasNext()) { StateInterrogation si = (StateInterrogation)sit.next(); Object result; try { result = sibr.get(pc, si); } catch (Throwable t) { continue; // ignore exceptions from errant StateInterrogations } if (result != null) return result; } return null; } /** This is an interface used to interrogate the state of an instance * that does not implement PersistenceCapable. It is used for the * methods that return a boolean value. */ public static interface StateInterrogationBooleanReturn { /** * Interrogate the state of the instance * @param pc the instance * @param si the method object * @return the state of the instance or null */ public Boolean is(Object pc, StateInterrogation si); } /** This is an interface used to interrogate the state of an instance * that does not implement PersistenceCapable. It is used for the * methods that return an Object value. */ public static interface StateInterrogationObjectReturn { /** * Return the associated instance. * @param pc the instance * @param si the method object * @return the associated object or null */ public Object get(Object pc, StateInterrogation si); } /** * Examines the given map for keys beginning with the JDO standard prefix, * {@link Constants#JAVAX_JDO_PREFIX}. If any property keys are found with * that prefix but are unknown to this version of the JDO standard, a * JDOUserException is thrown with a message indicating the unknown * property. Keys that are not strings are ignored, as are string keys * beginning with * {@link Constants#PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER} or not * beginning with {@link Constants#JAVAX_JDO_PREFIX}. * @param properties The properties to examine. * @see Constants#JAVAX_JDO_PREFIX * @since 3.1 */ public static void assertOnlyKnownStandardProperties(Map properties) { if (properties == null || properties.isEmpty()) return; List exceptions = new ArrayList(); StringBuilder unknowns = new StringBuilder(); for (Object key : properties.keySet()) { if (!(key instanceof String)) { continue; // ignore keys not of type string } String s = ((String) key).toLowerCase(); // compare case-insensitively if (!s.startsWith(JAVAX_JDO_PREFIX_LOWER_CASED)) { continue; // ignore vendor-specific keys } if (s.startsWith(PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER_LOWER_CASED)) { continue; // ignore listener class names } if (!USER_CONFIGURABLE_STANDARD_PROPERTIES_LOWER_CASED.contains(s)) { exceptions.add(new JDOUserException(msg.msg( "EXC_UnknownStandardProperty", s))); if (exceptions.size() > 1) { unknowns.append(","); } unknowns.append(s); } } if (exceptions.size() == 1) { throw exceptions.get(0); } else if (exceptions.size() > 1) { throw new JDOUserException(msg.msg("EXC_UnknownStandardProperties", unknowns.toString()), exceptions.toArray(new JDOUserException[] {})); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy