/* | |
* 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. | |
*/ | |
package org.apache.openjpa.enhance; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.Iterator; | |
import java.util.LinkedList; | |
import java.util.Map; | |
import org.apache.openjpa.lib.util.Localizer; | |
import org.apache.openjpa.lib.util.ReferenceMap; | |
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; | |
import org.apache.openjpa.util.UserException; | |
import org.apache.openjpa.util.InvalidStateException; | |
/** | |
* Tracks registered persistence-capable classes. | |
* | |
* @since 0.4.0 | |
* @author Abe White | |
*/ | |
public class PCRegistry { | |
// DO NOT ADD ADDITIONAL DEPENDENCIES TO THIS CLASS | |
private static final Localizer _loc = Localizer.forPackage | |
(PCRegistry.class); | |
// map of pc classes to meta structs; weak so the VM can GC classes | |
private static final Map _metas = new ConcurrentReferenceHashMap | |
(ReferenceMap.WEAK, ReferenceMap.HARD); | |
// register class listeners | |
private static final Collection _listeners = new LinkedList(); | |
/** | |
* Register a {@link RegisterClassListener}. | |
*/ | |
public static void addRegisterClassListener(RegisterClassListener rcl) { | |
if (rcl == null) | |
return; | |
// we have to be positive that every listener gets notified for | |
// every class, so lots of locking | |
synchronized (_listeners) { | |
_listeners.add(rcl); | |
} | |
synchronized (_metas) { | |
for (Iterator itr = _metas.keySet().iterator(); itr.hasNext();) | |
rcl.register((Class) itr.next()); | |
} | |
} | |
/** | |
* Removes a {@link RegisterClassListener}. | |
*/ | |
public static void removeRegisterClassListener(RegisterClassListener rcl) { | |
synchronized (_listeners) { | |
_listeners.remove(rcl); | |
} | |
} | |
/** | |
* Get the field names for a <code>PersistenceCapable</code> class. | |
*/ | |
public static String[] getFieldNames(Class pcClass) { | |
Meta meta = getMeta(pcClass); | |
return meta.fieldNames; | |
} | |
/** | |
* Get the field types for a <code>PersistenceCapable</code> class. | |
*/ | |
public static Class[] getFieldTypes(Class pcClass) { | |
Meta meta = getMeta(pcClass); | |
return meta.fieldTypes; | |
} | |
/** | |
* Return the persistent superclass for a <code>PersistenceCapable</code> | |
* class, or null if none. The superclass may or may not implement | |
* {@link PersistenceCapable}, depending on the access type of the class. | |
*/ | |
public static Class getPersistentSuperclass(Class pcClass) { | |
Meta meta = getMeta(pcClass); | |
return meta.pcSuper; | |
} | |
/** | |
* Create a new instance of the class and assign its state manager. | |
* The new instance has its flags set to <code>LOAD_REQUIRED</code>. | |
*/ | |
public static PersistenceCapable newInstance(Class pcClass, | |
StateManager sm, boolean clear) { | |
Meta meta = getMeta(pcClass); | |
return (meta.pc == null) ? null : meta.pc.pcNewInstance(sm, clear); | |
} | |
/** | |
* Create a new instance of the class and assign its state manager and oid. | |
* The new instance has its flags set to <code>LOAD_REQUIRED</code>. | |
*/ | |
public static PersistenceCapable newInstance(Class pcClass, | |
StateManager sm, Object oid, boolean clear) { | |
Meta meta = getMeta(pcClass); | |
return (meta.pc == null) ? null : meta.pc.pcNewInstance(sm, oid, clear); | |
} | |
/** | |
* Return the persistence-capable type for <code>type</code>. This might | |
* be a generated subclass of <code>type</code>. | |
* | |
* @since 1.1.0 | |
*/ | |
public static Class getPCType(Class type) { | |
Meta meta = getMeta(type); | |
return (meta.pc == null) ? null : meta.pc.getClass(); | |
} | |
/** | |
* Create a new identity object for the given | |
* <code>PersistenceCapable</code> class. | |
*/ | |
public static Object newObjectId(Class pcClass) { | |
Meta meta = getMeta(pcClass); | |
return (meta.pc == null) ? null : meta.pc.pcNewObjectIdInstance(); | |
} | |
/** | |
* Create a new identity object for the given | |
* <code>PersistenceCapable</code> class, using the <code>String</code> | |
* form of the constructor. | |
*/ | |
public static Object newObjectId(Class pcClass, String str) { | |
Meta meta = getMeta(pcClass); | |
return (meta.pc == null) ? null : meta.pc.pcNewObjectIdInstance(str); | |
} | |
/** | |
* Return the alias for the given type. | |
*/ | |
public static String getTypeAlias(Class pcClass) { | |
return getMeta(pcClass).alias; | |
} | |
/** | |
* Copy fields from an outside source to the key fields in the identity | |
* object. | |
*/ | |
public static void copyKeyFieldsToObjectId(Class pcClass, FieldSupplier fm, | |
Object oid) { | |
Meta meta = getMeta(pcClass); | |
if (meta.pc == null) | |
throw new UserException(_loc.get("copy-no-id", pcClass)); | |
meta.pc.pcCopyKeyFieldsToObjectId(fm, oid); | |
} | |
/** | |
* Copy fields to an outside source from the key fields in the identity | |
* object. | |
*/ | |
public static void copyKeyFieldsFromObjectId(Class pcClass, | |
FieldConsumer fm, Object oid) { | |
Meta meta = getMeta(pcClass); | |
if (meta.pc == null) | |
throw new UserException(_loc.get("copy-no-id", pcClass)); | |
meta.pc.pcCopyKeyFieldsFromObjectId(fm, oid); | |
} | |
/** | |
* Register metadata by class. | |
* | |
* @param fieldTypes managed field types | |
* @param fieldFlags managed field flags | |
* @param sup the most immediate persistent superclass | |
* @param pcClass the <code>PersistenceCapable</code> class | |
* @param fieldNames managed field names | |
* @param alias the class alias | |
* @param pc an instance of the class, if not abstract | |
*/ | |
public static void register(Class pcClass, String[] fieldNames, | |
Class[] fieldTypes, byte[] fieldFlags, Class sup, String alias, | |
PersistenceCapable pc) { | |
if (pcClass == null) | |
throw new NullPointerException(); | |
// we have to be positive that every listener gets notified for | |
// every class, so lots of locking | |
Meta meta = new Meta(pc, fieldNames, fieldTypes, sup, alias); | |
synchronized (_metas) { | |
_metas.put(pcClass, meta); | |
} | |
synchronized (_listeners) { | |
for (Iterator i = _listeners.iterator(); i.hasNext();) | |
((RegisterClassListener) i.next()).register(pcClass); | |
} | |
} | |
/** | |
* De-Register all metadata associated with the given ClassLoader. | |
* Allows ClassLoaders to be garbage collected. | |
* | |
* @param cl the ClassLoader | |
*/ | |
public static void deRegister(ClassLoader cl) { | |
synchronized (_metas) { | |
for (Iterator i = _metas.keySet().iterator(); i.hasNext();) { | |
Class pcClass = (Class) i.next(); | |
if (pcClass.getClassLoader() == cl) { | |
_metas.remove(pcClass); | |
} | |
} | |
} | |
} | |
/** | |
* Returns a collection of class objects of the registered | |
* persistence-capable classes. | |
*/ | |
public static Collection getRegisteredTypes() { | |
return Collections.unmodifiableCollection(_metas.keySet()); | |
} | |
/** | |
* Returns <code>true</code> if <code>cls</code> is already registered. | |
*/ | |
public static boolean isRegistered(Class cls) { | |
return _metas.containsKey(cls); | |
} | |
/** | |
* Look up the metadata for a <code>PersistenceCapable</code> class. | |
*/ | |
private static Meta getMeta(Class pcClass) { | |
Meta ret = (Meta) _metas.get(pcClass); | |
if (ret == null) | |
throw new IllegalStateException(_loc.get("no-meta", pcClass). | |
getMessage()); | |
return ret; | |
} | |
/** | |
* Listener for persistent class registration events. | |
*/ | |
public static interface RegisterClassListener { | |
public void register(Class cls); | |
} | |
/** | |
* This is a helper class to manage metadata per persistence-capable class. | |
*/ | |
private static class Meta { | |
public final PersistenceCapable pc; | |
public final String[] fieldNames; | |
public final Class[] fieldTypes; | |
public final Class pcSuper; | |
public final String alias; | |
public Meta(PersistenceCapable pc, String[] fieldNames, | |
Class[] fieldTypes, Class pcSuper, String alias) { | |
this.pc = pc; | |
this.fieldNames = fieldNames; | |
this.fieldTypes = fieldTypes; | |
this.pcSuper = pcSuper; | |
this.alias = alias; | |
} | |
} | |
} |