Log the purposes of nested UOWs as well as the parent. Create a serialization proxy for mapped objects.
This commit is contained in:
parent
52dab5872c
commit
c3f9b83770
5 changed files with 70 additions and 22 deletions
|
@ -44,6 +44,7 @@ public abstract class AbstractUnitOfWork<E extends Exception> implements UnitOfW
|
|||
private final AbstractUnitOfWork<E> parent;
|
||||
private final Table<String, String, Either<Object, List<Facet>>> cache = HashBasedTable.create();
|
||||
protected String purpose;
|
||||
protected List<String> nestedPurposes = new ArrayList<String>();
|
||||
protected int cacheHits = 0;
|
||||
protected int cacheMisses = 0;
|
||||
protected int databaseLookups = 0;
|
||||
|
@ -90,6 +91,11 @@ public abstract class AbstractUnitOfWork<E extends Exception> implements UnitOfW
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPurpose() {
|
||||
return purpose;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitOfWork setPurpose(String purpose) {
|
||||
this.purpose = purpose;
|
||||
|
@ -137,10 +143,11 @@ public abstract class AbstractUnitOfWork<E extends Exception> implements UnitOfW
|
|||
double daf = (dat / e) * 100;
|
||||
da = String.format(" consuming %,.3fms for data access, or %,2.2f%% of total UOW time.", dat, daf);
|
||||
}
|
||||
String x = nestedPurposes.stream().distinct().collect(Collectors.joining(", "));
|
||||
String n = nested.stream().map(uow -> String.valueOf(uow.hashCode())).collect(Collectors.joining(", "));
|
||||
String s = String.format(Locale.US, "UOW(%s%s) %s in %,.3fms%s%s%s%s", hashCode(),
|
||||
String s = String.format(Locale.US, "UOW(%s%s) %s in %,.3fms%s%s%s%s%s", hashCode(),
|
||||
(nested.size() > 0 ? ", [" + n + "]" : ""), what, e, cache, database, da,
|
||||
(purpose == null ? "" : " " + purpose));
|
||||
(purpose == null ? "" : " " + purpose), (nestedPurposes.isEmpty()) ? "" : ", " + x);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -277,7 +284,7 @@ public abstract class AbstractUnitOfWork<E extends Exception> implements UnitOfW
|
|||
|
||||
// Merge cache and statistics into parent if there is one.
|
||||
parent.mergeCache(cache);
|
||||
|
||||
if (purpose != null) {parent.nestedPurposes.add(purpose);}
|
||||
parent.cacheHits += cacheHits;
|
||||
parent.cacheMisses += cacheMisses;
|
||||
parent.databaseLookups += databaseLookups;
|
||||
|
|
|
@ -311,8 +311,12 @@ public final class HelenusSession extends AbstractSessionOperations implements C
|
|||
}
|
||||
|
||||
public synchronized UnitOfWork begin(UnitOfWork parent) {
|
||||
try {
|
||||
Class<? extends UnitOfWork> clazz = unitOfWorkClass;
|
||||
Constructor<? extends UnitOfWork> ctor = clazz.getConstructor(HelenusSession.class, UnitOfWork.class);
|
||||
UnitOfWork uow = ctor.newInstance(this, parent);
|
||||
if (LOG.isInfoEnabled() && uow.getPurpose() == null) {
|
||||
StringBuilder purpose = null;
|
||||
if (LOG.isInfoEnabled()) {
|
||||
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||
int frame = 2;
|
||||
if (trace[2].getMethodName().equals("begin")) {
|
||||
|
@ -321,12 +325,6 @@ public final class HelenusSession extends AbstractSessionOperations implements C
|
|||
purpose = new StringBuilder().append(trace[frame].getClassName()).append(".")
|
||||
.append(trace[frame].getMethodName()).append("(").append(trace[frame].getFileName()).append(":")
|
||||
.append(trace[frame].getLineNumber()).append(")");
|
||||
}
|
||||
try {
|
||||
Class<? extends UnitOfWork> clazz = unitOfWorkClass;
|
||||
Constructor<? extends UnitOfWork> ctor = clazz.getConstructor(HelenusSession.class, UnitOfWork.class);
|
||||
UnitOfWork uow = ctor.newInstance(this, parent);
|
||||
if (LOG.isInfoEnabled() && purpose != null) {
|
||||
uow.setPurpose(purpose.toString());
|
||||
}
|
||||
if (parent != null) {
|
||||
|
|
|
@ -61,6 +61,7 @@ public interface UnitOfWork<X extends Exception> extends AutoCloseable {
|
|||
|
||||
List<Facet> cacheEvict(List<Facet> facets);
|
||||
|
||||
String getPurpose();
|
||||
UnitOfWork setPurpose(String purpose);
|
||||
|
||||
void addDatabaseTime(String name, Stopwatch amount);
|
||||
|
|
|
@ -15,16 +15,21 @@
|
|||
*/
|
||||
package net.helenus.core.reflect;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.helenus.core.Helenus;
|
||||
import net.helenus.mapping.annotation.Transient;
|
||||
import net.helenus.mapping.value.ValueProviderMap;
|
||||
import net.helenus.support.HelenusException;
|
||||
|
||||
public class MapperInvocationHandler<E> implements InvocationHandler, Serializable {
|
||||
|
@ -50,14 +55,20 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
|
|||
int.class);
|
||||
constructor.setAccessible(true);
|
||||
|
||||
// Now we need to lookup and invoke special the default method on the interface
|
||||
// class.
|
||||
// Now we need to lookup and invoke special the default method on the interface class.
|
||||
final Class<?> declaringClass = method.getDeclaringClass();
|
||||
Object result = constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
|
||||
.unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new SerializationProxy(this);
|
||||
}
|
||||
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Proxy required.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
|
||||
|
@ -96,13 +107,20 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
|
|||
return iface.getSimpleName() + ": " + src.toString();
|
||||
}
|
||||
|
||||
if ("writeReplace".equals(methodName)) {
|
||||
return new SerializationProxy(this);
|
||||
}
|
||||
|
||||
if ("readObject".equals(methodName)) {
|
||||
throw new InvalidObjectException("Proxy required.");
|
||||
}
|
||||
|
||||
if ("dsl".equals(methodName)) {
|
||||
return Helenus.dsl(iface);
|
||||
}
|
||||
|
||||
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
|
||||
// return Collections.unmodifiableMap(src);
|
||||
return src;
|
||||
return src; // return Collections.unmodifiableMap(src);
|
||||
}
|
||||
|
||||
Object value = src.get(methodName);
|
||||
|
@ -132,4 +150,27 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
|
|||
|
||||
return value;
|
||||
}
|
||||
|
||||
static class SerializationProxy implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5617583940055969353L;
|
||||
|
||||
private final Class<?> iface;
|
||||
private final Map<String, Object> src;
|
||||
|
||||
public SerializationProxy(MapperInvocationHandler mapper) {
|
||||
this.iface = mapper.iface;
|
||||
if (mapper.src instanceof ValueProviderMap) {
|
||||
this.src = new HashMap<String, Object>(mapper.src.size());
|
||||
this.src.putAll(src);
|
||||
} else {
|
||||
this.src = mapper.src;
|
||||
}
|
||||
}
|
||||
|
||||
Object readResolve() throws ObjectStreamException {
|
||||
return Helenus.map(iface, src);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package net.helenus.core.reflect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -28,7 +29,7 @@ public enum ReflectionMapperInstantiator implements MapperInstantiator {
|
|||
public <E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
|
||||
|
||||
MapperInvocationHandler<E> handler = new MapperInvocationHandler<E>(iface, src);
|
||||
E proxy = (E) Proxy.newProxyInstance(classLoader, new Class[]{iface, MapExportable.class}, handler);
|
||||
E proxy = (E) Proxy.newProxyInstance(classLoader, new Class[]{iface, MapExportable.class, Serializable.class}, handler);
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue