org.babyfish.hibernate.proxy.FrozenLazyInitializerImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of babyfish-hibernate Show documentation
Show all versions of babyfish-hibernate Show documentation
The hibernate enhancement project of BabyFish.
The newest version!
/*
* BabyFish, Object Model Framework for Java and JPA.
* https://github.com/babyfish-ct/babyfish
*
* Copyright (c) 2008-2015, Tao Chen
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* Please visit "http://opensource.org/licenses/LGPL-3.0" to know more.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*/
package org.babyfish.hibernate.proxy;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyObject;
import org.babyfish.collection.FrozenContext;
import org.babyfish.hibernate.model.metadata.HibernateMetadatas;
import org.babyfish.hibernate.model.metadata.HibernateObjectModelMetadata;
import org.babyfish.lang.Arguments;
import org.babyfish.lang.Combiner;
import org.babyfish.lang.Combiners;
import org.babyfish.lang.Func;
import org.babyfish.lang.UncheckedException;
import org.babyfish.model.ObjectModel;
import org.babyfish.model.ObjectModelFactory;
import org.babyfish.model.ObjectModelFactoryFactory;
import org.babyfish.model.event.ScalarEvent;
import org.babyfish.model.event.ScalarListener;
import org.babyfish.modificationaware.event.AttributeScope;
import org.babyfish.modificationaware.event.EventAttributeContext;
import org.babyfish.modificationaware.event.ModificationEventHandleException;
import org.babyfish.modificationaware.event.PropertyVersion;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.proxy.pojo.BasicLazyInitializer;
/**
* @author Tao Chen
*/
public class FrozenLazyInitializerImpl implements FrozenLazyInitializer, MethodHandler, Serializable {
private static final long serialVersionUID = -3172051759799034702L;
private static final Combiner SCALAR_LISTENER_COMBINER =
Combiners.of(ScalarListener.class);
private static final Object AK_SCALAR_LISTENER = new Object();
private static final Object[] EMPTY_ARGS = new Object[0];
private static final Object AK_MODIFIYING_EXECUTED = new Object();
private static final Object AK_FROZENCONTEXT = new Object();
private static final Field GET_IDENTIFIER_METHOD_FIELD;
private static final Field SET_IDENTIFIER_METHOD_FIELD;
private static final Field PERSISTENT_CLASS_FIELD;
protected HibernateProxy owner;
protected LazyInitializer lazyInitializer;
protected transient FrozenContext> idFrozenContext;
protected transient HibernateObjectModelMetadata objectModelMetadata;
protected transient ObjectModelFactory omFactory;
protected transient ScalarListener scalarListener;
protected transient Method getIdentifierMethod;
protected transient Method setIdentifierMethod;
private transient Object oldTarget;
private transient boolean disableSetTargetIdentifier;
private transient boolean disableTargetListener;
protected FrozenLazyInitializerImpl(HibernateProxy owner) {
ProxyObject proxyObject = (ProxyObject)owner;
MethodHandler handler = proxyObject.getHandler();
if (!(handler instanceof LazyInitializer)) {
Arguments.mustBeInstanceOfValue(
"((" +
ProxyObject.class.getName() +
")owner).getHandler()",
handler,
LazyInitializer.class);
}
Class> persistentClass = getPersistentClass((BasicLazyInitializer)handler);
LazyInitializer lazyInitializer = owner.getHibernateLazyInitializer();
if (lazyInitializer instanceof FrozenLazyInitializer) {
throw new AssertionError();
}
this.owner = owner;
this.lazyInitializer = lazyInitializer;
this.objectModelMetadata = HibernateMetadatas.of(persistentClass);
this.initTransient(persistentClass);
proxyObject.setHandler(this);
}
public static FrozenLazyInitializer getFrozenLazyInitializer(
HibernateProxy hibernateProxy) {
return getFrozenLazyInitializer(
hibernateProxy,
null);
}
protected static FrozenLazyInitializer getFrozenLazyInitializer(
HibernateProxy hibernateProxy,
Func frozenLazyInitializerCreator) {
ProxyObject proxyObject = (ProxyObject)hibernateProxy;
MethodHandler handler = proxyObject.getHandler();
if (handler instanceof FrozenLazyInitializer) {
return (FrozenLazyInitializer)handler;
}
if (frozenLazyInitializerCreator != null) {
return frozenLazyInitializerCreator.run(hibernateProxy);
}
return new FrozenLazyInitializerImpl(hibernateProxy);
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.initTransient(null);
}
@SuppressWarnings("unchecked")
private void initTransient(Class> persistentClass) {
LazyInitializer rawLazyInitializer = this.lazyInitializer;
if (persistentClass == null) {
persistentClass = getPersistentClass((BasicLazyInitializer)rawLazyInitializer);
}
HibernateObjectModelMetadata objectModelMetadata = HibernateMetadatas.of(persistentClass);
this.objectModelMetadata = objectModelMetadata;
this.omFactory =
(ObjectModelFactory)
ObjectModelFactoryFactory
.factoryOf(objectModelMetadata.getObjectModelClass());
try {
this.getIdentifierMethod = (Method)GET_IDENTIFIER_METHOD_FIELD.get(rawLazyInitializer);
this.setIdentifierMethod = (Method)SET_IDENTIFIER_METHOD_FIELD.get(rawLazyInitializer);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new AssertionError();
}
if (!rawLazyInitializer.isUninitialized()) {
ObjectModel targetOM =
this
.omFactory
.get(rawLazyInitializer.getImplementation());
ScalarListener listener = this.new TargetScalarListener();
targetOM.removeScalarListener(listener);
targetOM.addScalarListener(listener);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void freezeIdentifier(FrozenContext> ctx) {
this.idFrozenContext = FrozenContext.combine(
(FrozenContext)this.idFrozenContext,
(FrozenContext)ctx);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void unfreezeIdentifier(FrozenContext> ctx) {
this.idFrozenContext = FrozenContext.remove(
(FrozenContext)this.idFrozenContext,
(FrozenContext)ctx);
}
@Override
public void addScalarListener(ScalarListener listener) {
this.scalarListener = SCALAR_LISTENER_COMBINER.combine(this.scalarListener, listener);
}
@Override
public void removeScalarListener(ScalarListener listener) {
this.scalarListener = SCALAR_LISTENER_COMBINER.remove(this.scalarListener, listener);
}
@Override
public Serializable getIdentifier() {
if (!this.isUninitialized()) {
try {
return
(Serializable)
this.getIdentifierMethod
.invoke(this.lazyInitializer.getImplementation(), EMPTY_ARGS);
} catch (IllegalAccessException | IllegalArgumentException ex) {
throw new AssertionError(ex);
} catch (InvocationTargetException ex) {
throw UncheckedException.rethrow(ex.getTargetException());
}
}
return this.lazyInitializer.getIdentifier();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void setIdentifier(Serializable id) {
FrozenContext ctx = (FrozenContext)this.idFrozenContext;
FrozenContext.suspendFreezing(ctx, this.owner);
try {
this.setRawIdentifier(id);
} finally {
FrozenContext.resumeFreezing(ctx);
}
}
private void setRawIdentifier(Serializable id) {
this.lazyInitializer.setIdentifier(id);
if (!this.isUninitialized() && !this.disableSetTargetIdentifier) {
try {
Method setIdentifierMethod = this.setIdentifierMethod;
if (!setIdentifierMethod.isAccessible()) {
setIdentifierMethod.setAccessible(true);
}
this.disableTargetListener = true;
try {
setIdentifierMethod.invoke(this.getImplementation(), new Object[] { id });
} finally {
this.disableTargetListener = false;
}
} catch (IllegalAccessException | IllegalArgumentException ex) {
throw new AssertionError();
} catch (InvocationTargetException ex) {
UncheckedException.rethrow(ex.getTargetException());
}
}
}
@Override
public void setImplementation(Object target) {
LazyInitializer rawLazyInitializer = this.lazyInitializer;
Object oldTarget =
rawLazyInitializer.isUninitialized() ?
null :
rawLazyInitializer.getImplementation();
if (target != oldTarget) {
ScalarListener listener = this.new TargetScalarListener();
if (oldTarget != null) {
this.omFactory.get(oldTarget).removeScalarListener(listener);
}
rawLazyInitializer.setImplementation(target);
this.oldTarget = target;
if (target != null) {
ObjectModel targetOM = this.omFactory.get(target);
targetOM.removeScalarListener(listener); //remove the duplicated listener.
targetOM.addScalarListener(listener);
}
}
}
@Override
public void initialize() throws HibernateException {
LazyInitializer rawLazyInitializer = this.lazyInitializer;
Object oldTarget =
rawLazyInitializer.isUninitialized() ?
null :
rawLazyInitializer.getImplementation();
rawLazyInitializer.initialize();
Object target = rawLazyInitializer.getImplementation();
if (oldTarget != target) {
ScalarListener listener = this.new TargetScalarListener();
if (oldTarget != null) {
this.omFactory.get(oldTarget).removeScalarListener(listener);
}
this.oldTarget = target;
if (target != null) {
ObjectModel targetOM = this.omFactory.get(target);
targetOM.removeScalarListener(listener); //remove the duplicated listener.
targetOM.addScalarListener(listener);
}
}
}
@Override
public Object getImplementation() {
Object oldTarget = this.oldTarget;
Object target = this.lazyInitializer.getImplementation();
if (oldTarget != target) {
ScalarListener listener = this.new TargetScalarListener();
if (oldTarget != null) {
this.omFactory.get(oldTarget).removeScalarListener(listener);
}
this.oldTarget = target;
if (target != null) {
ObjectModel targetOM = this.omFactory.get(target);
targetOM.removeScalarListener(listener); //remove the duplicated listener.
targetOM.addScalarListener(listener);
}
}
return target;
}
@Override
public Object getImplementation(SessionImplementor session)
throws HibernateException {
Object oldTarget = this.oldTarget;
Object target = this.lazyInitializer.getImplementation(session);
if (oldTarget != target) {
ScalarListener listener = this.new TargetScalarListener();
if (oldTarget != null) {
this.omFactory.get(oldTarget).removeScalarListener(listener);
}
this.oldTarget = target;
if (target != null) {
ObjectModel targetOM = this.omFactory.get(target);
targetOM.removeScalarListener(listener); //remove the duplicated listener.
targetOM.addScalarListener(listener);
}
}
return target;
}
@Override
public String getEntityName() {
return this.lazyInitializer.getEntityName();
}
@SuppressWarnings("rawtypes")
@Override
public Class getPersistentClass() {
return this.lazyInitializer.getPersistentClass();
}
@Override
public boolean isUninitialized() {
return this.lazyInitializer.isUninitialized();
}
@Override
public boolean isReadOnlySettingAvailable() {
return this.lazyInitializer.isReadOnlySettingAvailable();
}
@Override
public boolean isReadOnly() {
return this.lazyInitializer.isReadOnly();
}
@Override
public void setReadOnly(boolean readOnly) {
this.lazyInitializer.setReadOnly(readOnly);
}
@Override
public SessionImplementor getSession() {
return this.lazyInitializer.getSession();
}
@Override
public void setSession(SessionImplementor session)
throws HibernateException {
this.lazyInitializer.setSession(session);
}
@Override
public void unsetSession() {
this.lazyInitializer.unsetSession();
}
@Override
public void setUnwrap(boolean unwrap) {
this.lazyInitializer.setUnwrap(unwrap);
}
@Override
public boolean isUnwrap() {
return this.lazyInitializer.isUnwrap();
}
@Override
public Object invoke(
Object self,
Method thisMethod,
Method proceed,
Object[] args) throws Throwable {
if (thisMethod.getName().equals("getHibernateLazyInitializer")) {
return this;
} else if (thisMethod.equals(this.getIdentifierMethod)) {
//Very important!!!
//Hibernate invoke thisMethod.invoke(target, args) here if the proxy is loaded.
//But babyfish do the same operation in this.getIdentifier(),
//Becasue the behaviors of getIdentfier() and setIdentifier(Serializable)
//must be same. (see the comment of next else if)
return this.getIdentifier();
} else if (thisMethod.equals(this.setIdentifierMethod)) {
//Very important!!!
//Hibernate invoke thisMethod.invoke(target, args) here.
//But babyfish do the same operation in this.setIdentifier(Serializable),
//this is very important, because the "ctx.resumeFreezing()" in this.setIdentifier()
//need the id of the target if the proxy is loaded.
this.setIdentifier((Serializable)args[0]);
}
return ((MethodHandler)this.lazyInitializer).invoke(
self,
thisMethod,
proceed,
args);
}
protected void executeModifying(ScalarEvent e) {
Throwable finalThrowable = null;
try {
this.onModifying(e);
} catch (Throwable ex) {
finalThrowable = ex;
}
try {
this.raiseModifying(e);
} catch (Throwable ex) {
if (finalThrowable == null) {
finalThrowable = ex;
}
}
if (finalThrowable != null) {
throw new ModificationEventHandleException(false, e, finalThrowable);
}
}
protected void executeModified(ScalarEvent e) {
Throwable finalThrowable = null;
try {
this.raiseModified(e);
} catch (Throwable ex) {
finalThrowable = ex;
}
try {
this.onModified(e);
} catch (Throwable ex) {
if (finalThrowable == null) {
finalThrowable = ex;
}
}
if (finalThrowable != null) {
throw new ModificationEventHandleException(true, e, finalThrowable);
}
}
protected void onModifying(ScalarEvent e) throws Throwable {
}
protected void onModified(ScalarEvent e) throws Throwable {
}
protected void raiseModifying(ScalarEvent e) throws Throwable {
ScalarListener scalarListener = this.scalarListener;
if (scalarListener != null) {
e
.getAttributeContext(AttributeScope.LOCAL)
.addAttribute(AK_SCALAR_LISTENER, scalarListener);
scalarListener.modifying(e);
}
}
protected void raiseModified(ScalarEvent e) throws Throwable {
ScalarListener scalarListener =
(ScalarListener)
e
.getAttributeContext(AttributeScope.LOCAL)
.removeAttribute(AK_SCALAR_LISTENER);
if (scalarListener != null) {
scalarListener.modified(e);
}
}
private static Class> getPersistentClass(BasicLazyInitializer basicLazyInitializer) {
try {
return (Class>)PERSISTENT_CLASS_FIELD.get(basicLazyInitializer);
} catch (IllegalAccessException ex) {
throw new AssertionError(ex);
}
}
private final class TargetScalarListener implements ScalarListener {
@SuppressWarnings("unchecked")
@Override
public void modifying(ScalarEvent e) {
FrozenLazyInitializerImpl declaring = FrozenLazyInitializerImpl.this;
if (!declaring.disableTargetListener) {
ObjectModelFactory omFactory = declaring.omFactory;
LazyInitializer rawLazyInitializer = declaring.lazyInitializer;
EventAttributeContext localAttributeContext = e.getAttributeContext(AttributeScope.LOCAL);
if (rawLazyInitializer.isUninitialized() ||
omFactory.get(rawLazyInitializer.getImplementation()) != e.getSource()) {
((ObjectModel)e.getSource()).removeScalarListener(this);
return;
}
localAttributeContext.addAttribute(AK_MODIFIYING_EXECUTED, true);
if (e.getProperty() == declaring.objectModelMetadata.getEntityIdProperty()) {
FrozenContext