blob: 435ccfa987668881b755628ef3d4603a2a01f502 [file] [log] [blame]
/*
* 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.persistence;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collection;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.apache.openjpa.enhance.PCRegistry;
import org.apache.openjpa.kernel.Broker;
import org.apache.openjpa.kernel.BrokerFactory;
import org.apache.openjpa.kernel.BrokerImpl.StateManagerId;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.util.ApplicationIds;
import org.apache.openjpa.util.BigDecimalId;
import org.apache.openjpa.util.BigIntegerId;
import org.apache.openjpa.util.ByteId;
import org.apache.openjpa.util.CharId;
import org.apache.openjpa.util.DoubleId;
import org.apache.openjpa.util.FloatId;
import org.apache.openjpa.util.Id;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.IntId;
import org.apache.openjpa.util.LongId;
import org.apache.openjpa.util.ObjectId;
import org.apache.openjpa.util.OpenJPAId;
import org.apache.openjpa.util.ShortId;
import org.apache.openjpa.util.StringId;
import org.apache.openjpa.util.UserException;
/**
* Helper class for switching between OpenJPA's JPA facade and the underlying
* Broker kernel.
*
* @since 1.0.0
*/
public class JPAFacadeHelper {
public static final String EM_KEY =
"org.apache.openjpa.persistence.EntityManager";
public static final String EMF_KEY =
"org.apache.openjpa.persistence.EntityManagerFactory";
private static final Localizer _loc =
Localizer.forPackage(JPAFacadeHelper.class);
public static OpenJPAEntityManagerFactory toEntityManagerFactory(
BrokerFactory factory) {
if (factory == null)
return null;
factory.lock();
try {
OpenJPAEntityManagerFactory emf = (OpenJPAEntityManagerFactory)
factory.getUserObject(EMF_KEY);
if (emf == null) {
emf = EntityManagerFactoryValue.newFactory(factory);
factory.putUserObject(EMF_KEY, emf);
}
return emf;
} catch (Exception e) {
throw PersistenceExceptions.toPersistenceException(e);
} finally {
factory.unlock();
}
}
/**
* Return the underlying broker factory for the given persistence manager
* factory facade.
*/
public static BrokerFactory toBrokerFactory(EntityManagerFactory emf) {
if (emf == null)
return null;
if (!(emf instanceof EntityManagerFactoryImpl)) {
Class c = emf.getClass();
try {
// either cast here may fail
emf = (EntityManagerFactoryImpl) ((OpenJPAEntityManagerFactory)
emf).getUserObject(EMF_KEY);
} catch (ClassCastException cce) {
throw new ArgumentException(_loc.get(
"cant-convert-brokerfactory", c), null, null, false);
}
}
return ((EntityManagerFactoryImpl) emf).getBrokerFactory();
}
/**
* Return a persistence manager facade to the given broker retaining
* previously associated persistence context type.
*/
public static OpenJPAEntityManager toEntityManager(Broker broker) {
if (broker == null)
return null;
broker.lock();
try {
OpenJPAEntityManager em = (OpenJPAEntityManager)
broker.getUserObject(EM_KEY);
if (em == null) {
EntityManagerFactoryImpl emf = (EntityManagerFactoryImpl)
toEntityManagerFactory(broker.getBrokerFactory());
em = emf.newEntityManagerImpl(broker);
broker.putUserObject(EM_KEY, em);
}
return em;
} catch (Exception e) {
throw PersistenceExceptions.toPersistenceException(e);
} finally {
broker.unlock();
}
}
/**
* Return the underlying broker for the given entity manager facade.
*/
public static Broker toBroker(EntityManager em) {
if (em == null)
return null;
if (!(em instanceof EntityManagerImpl)) {
Class c = em.getClass();
try {
// either cast here may fail
em = (EntityManagerImpl) ((OpenJPAEntityManager) em).
getUserObject(EM_KEY);
} catch (ClassCastException cce) {
throw new ArgumentException(_loc.get("cant-convert-broker", c),
new Throwable[] { cce }, null, false);
}
}
return ((EntityManagerImpl) em).getBroker();
}
/**
* Returns the {@link org.apache.openjpa.meta.ClassMetaData} associated with
* the persistent object <code>o</code>.
*/
public static ClassMetaData getMetaData(Object o) {
if (o == null)
return null;
EntityManager em = OpenJPAPersistence.getEntityManager(o);
return (em == null) ? null : getMetaData(em,
ImplHelper.getManagedInstance(o).getClass());
}
/**
* Returns the {@link org.apache.openjpa.meta.ClassMetaData} associated
* with the persistent type <code>cls</code>.
*/
public static ClassMetaData getMetaData(EntityManager em, Class cls) {
if (em == null)
throw new NullPointerException("em == null");
OpenJPAEntityManagerSPI kem = (OpenJPAEntityManagerSPI)
OpenJPAPersistence.cast(em);
try {
return kem.getConfiguration().getMetaDataRepositoryInstance().
getMetaData(cls, kem.getClassLoader(), false);
} catch (Exception e) {
throw PersistenceExceptions.toPersistenceException(e);
}
}
/**
* Returns the {@link org.apache.openjpa.meta.ClassMetaData} associated
* with the persistent type <code>cls</code>.
*/
public static ClassMetaData getMetaData(EntityManagerFactory emf,
Class cls) {
if (emf == null)
throw new NullPointerException("emf == null");
OpenJPAEntityManagerFactorySPI emfSPI =
(OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.cast(emf);
try {
return emfSPI.getConfiguration().getMetaDataRepositoryInstance().
getMetaData(cls, null, false);
} catch (Exception e) {
throw PersistenceExceptions.toPersistenceException(e);
}
}
/**
* Translate from a OpenJPA identity object to a Persistence one.
*/
public static Object fromOpenJPAObjectId(Object oid) {
if (oid instanceof OpenJPAId)
return ((OpenJPAId) oid).getIdObject();
return oid;
}
/**
* Translate from a Persistence identity object to a OpenJPA one. If the provided oid isn't of the expected type
* a UserException will be thrown.
*/
public static Object toOpenJPAObjectId(ClassMetaData meta, Object oid) {
if (oid == null || meta == null)
return null;
if (oid instanceof OpenJPAId) {
return oid;
}
Class<?> cls = meta.getDescribedType();
FieldMetaData[] pks = meta.getPrimaryKeyFields();
Object expected = meta.getObjectIdType();
try {
switch (meta.getIdentityType()) {
case ClassMetaData.ID_DATASTORE:
if (oid instanceof String && ((String) oid).startsWith(StateManagerId.STRING_PREFIX))
return new StateManagerId((String) oid);
return new Id(cls, ((Number) oid).longValue());
case ClassMetaData.ID_APPLICATION:
if (ImplHelper.isAssignable(meta.getObjectIdType(), oid.getClass())) {
if (!meta.isOpenJPAIdentity() && meta.isObjectIdTypeShared())
return new ObjectId(cls, oid);
return oid;
}
if (meta.getIdClass() == null) {
expected = pks[0].getDeclaredType();
} else {
expected = meta.getIdClass();
}
// stringified app id?
if (oid instanceof String
&& !meta.getRepository().getConfiguration().getCompatibilityInstance().getStrictIdentityValues()
&& !Modifier.isAbstract(cls.getModifiers()))
return PCRegistry.newObjectId(cls, (String) oid);
Object[] arr = (oid instanceof Object[]) ? (Object[]) oid : new Object[] { oid };
Object rtrn = ApplicationIds.fromPKValues(arr, meta);
if (rtrn != null && meta.getObjectIdType() != null) {
if (rtrn instanceof ObjectId) {
// embedded id and composite id with a derived id that
// uses an embedded id
if (pks.length > 0 && (pks[0].isEmbedded() || pks[0].isTypePC())) {
Class idClass = meta.getIdClass();
if (pks[0].getDeclaredType().equals(oid.getClass()) || idClass != null
&& idClass.equals(oid.getClass())) {
return rtrn;
}
}
} else {
if (!(rtrn instanceof StringId) || rtrn instanceof StringId && oid instanceof String) {
return rtrn;
}
}
}
default:
throw new UserException(_loc.get("invalid-oid", new Object[] { expected, oid.getClass() }));
}
} catch (RuntimeException re) {
if (expected == null)
throw new UserException(_loc.get("invalid-oid", new Object[] { Number.class, oid.getClass() }));
throw new UserException(_loc.get("invalid-oid", new Object[] { expected, oid.getClass() }));
}
}
/**
* Return an array of OpenJPA oids for the given native oid array.
*/
public static Object[] toOpenJPAObjectIds(ClassMetaData meta,
Object... oids) {
if (oids == null || oids.length == 0)
return oids;
// since the class if fixed for all oids, we can tell if we have to
// translate the array based on whether the first oid needs translating
Object oid = toOpenJPAObjectId(meta, oids[0]);
if (oid == oids[0])
return oids;
Object[] copy = new Object[oids.length];
copy[0] = oid;
for (int i = 1; i < oids.length; i++)
copy[i] = toOpenJPAObjectId(meta, oids[i]);
return copy;
}
/**
* Return a collection of OpenJPA oids for the given native oid collection.
*/
public static Collection<Object> toOpenJPAObjectIds(ClassMetaData meta, Collection<Object> oids) {
if (oids == null || oids.size() == 0) {
return oids;
}
return Arrays.asList(toOpenJPAObjectIds(meta, oids.toArray()));
}
/**
* Translate from a OpenJPA identity class to a native one.
*/
public static Class fromOpenJPAObjectIdClass(Class oidClass) {
if (oidClass == null)
return null;
if (oidClass == Id.class)
return Long.class;
if (oidClass == ByteId.class)
return Byte.class;
if (oidClass == CharId.class)
return Character.class;
if (oidClass == DoubleId.class)
return Double.class;
if (oidClass == FloatId.class)
return Float.class;
if (oidClass == IntId.class)
return Integer.class;
if (oidClass == LongId.class)
return Long.class;
if (oidClass == ShortId.class)
return Short.class;
if (oidClass == StringId.class)
return String.class;
if (oidClass == BigDecimalId.class)
return BigDecimal.class;
if (oidClass == BigIntegerId.class)
return BigInteger.class;
return oidClass;
}
}