| /* |
| * 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.Map; |
| |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.lib.util.collections.AbstractReferenceMap; |
| import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; |
| import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashSet; |
| import org.apache.openjpa.util.UserException; |
| |
| /** |
| * 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 persistent classes to meta structures; weak so the VM can GC classes |
| private static final Map<Class<?>,Meta> _metas = new ConcurrentReferenceHashMap( |
| AbstractReferenceMap.ReferenceStrength.WEAK, |
| AbstractReferenceMap.ReferenceStrength.HARD); |
| |
| // register class listeners |
| // Weak reference prevents OutOfMemeoryError as described in OPENJPA-2042 |
| private static final Collection<RegisterClassListener> _listeners = |
| new ConcurrentReferenceHashSet<>( |
| AbstractReferenceMap.ReferenceStrength.WEAK); |
| |
| /** |
| * 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 (Class<?> cls : _metas.keySet()) |
| rcl.register(cls); |
| } |
| } |
| |
| /** |
| * Removes a {@link RegisterClassListener}. |
| */ |
| public static boolean removeRegisterClassListener(RegisterClassListener rcl) { |
| synchronized (_listeners) { |
| return _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 (RegisterClassListener r : _listeners){ |
| if (r != null) { |
| r.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 (Class<?> pcClass : _metas.keySet()) { |
| if (pcClass.getClassLoader() == cl) { |
| _metas.remove(pcClass); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns a collection of class objects of the registered |
| * persistence-capable classes. |
| */ |
| public static Collection<Class<?>> getRegisteredTypes() { |
| return Collections.unmodifiableCollection(_metas.keySet()); |
| } |
| |
| /** |
| * Returns <code>true</code> if the given class 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 interface RegisterClassListener { |
| |
| 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; |
| } |
| } |
| } |