/*
* Copyright 2016 the original author or authors.
*
* Licensed 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.hotswap.agent.plugin.hibernate3.session.proxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.impl.SessionFactoryImpl;
import org.hotswap.agent.javassist.util.proxy.MethodHandler;
import org.hotswap.agent.javassist.util.proxy.Proxy;
import org.hotswap.agent.javassist.util.proxy.ProxyFactory;
/**
* For Hibernate without EJB (EntityManager).
* <p/>
* TODO - Not tested, some additional Configuration cleanup may be necessary
*
* @author Jiri Bubnik
* @author alpapad@gmail.com
*/
@SuppressWarnings("restriction")
public class SessionFactoryProxy {
/** The proxied factories. */
private static Map<Configuration, SessionFactoryProxy> proxiedFactories = new HashMap<Configuration, SessionFactoryProxy>();
/**
* Gets the wrapper.
*
* @param configuration
* the configuration
* @return the wrapper
*/
public static SessionFactoryProxy getWrapper(Configuration configuration) {
synchronized (proxiedFactories) {
if (!proxiedFactories.containsKey(configuration)) {
proxiedFactories.put(configuration, new SessionFactoryProxy(configuration));
}
return proxiedFactories.get(configuration);
}
}
/**
* Refresh proxied factories.
*/
public static void refreshProxiedFactories() {
synchronized (proxiedFactories) {
for (SessionFactoryProxy wrapper : proxiedFactories.values()) {
try {
wrapper.refreshProxiedFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/** The configuration. */
private Configuration configuration;
/** The current instance. */
private volatile SessionFactory currentInstance;
/**
* Instantiates a new session factory proxy.
*
* @param configuration
* the configuration
*/
private SessionFactoryProxy(Configuration configuration) {
this.configuration = configuration;
}
/**
* Refresh proxied factory.
*
* @throws NoSuchMethodException
* the no such method exception
* @throws InvocationTargetException
* the invocation target exception
* @throws IllegalAccessException
* the illegal access exception
*/
public void refreshProxiedFactory() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ReInitializable r = ReInitializable.class.cast(configuration);
r.hotSwap();
currentInstance = r._buildSessionFactory();
}
/**
* Proxy.
*
* @param sessionFactory
* the session factory
* @return the session factory
*/
public SessionFactory proxy(SessionFactory sessionFactory) {
try {
this.currentInstance = sessionFactory;
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(SessionFactoryImpl.class);
factory.setInterfaces(new Class[] { SessionFactory.class, SessionFactoryImplementor.class });
MethodHandler handler = new MethodHandler() {
@Override
public Object invoke(Object self, Method overridden, Method forwarder, Object[] args) throws Throwable {
return overridden.invoke(currentInstance, args);
}
};
Object instance;
try {
Constructor<?> constructor = sun.reflect.ReflectionFactory.getReflectionFactory()//
.newConstructorForSerialization(factory.createClass(), Object.class.getDeclaredConstructor(new Class[0]));
instance = constructor.newInstance();
((Proxy) instance).setHandler(handler);
} catch (Exception e) {
e.printStackTrace();
throw new Error("Unable instantiate SessionFactory proxy", e);
}
return (SessionFactory) instance;
} catch (Exception e) {
e.printStackTrace();
throw new Error("Unable instantiate SessionFactory proxy", e);
}
}
}