/*
* 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;
import org.hotswap.agent.annotation.FileEvent;
import org.hotswap.agent.annotation.Init;
import org.hotswap.agent.annotation.LoadEvent;
import org.hotswap.agent.annotation.Maven;
import org.hotswap.agent.annotation.OnClassFileEvent;
import org.hotswap.agent.annotation.OnClassLoadEvent;
import org.hotswap.agent.annotation.OnResourceFileEvent;
import org.hotswap.agent.annotation.Plugin;
import org.hotswap.agent.annotation.Versions;
import org.hotswap.agent.command.Command;
import org.hotswap.agent.command.ReflectionCommand;
import org.hotswap.agent.command.Scheduler;
import org.hotswap.agent.javassist.CtClass;
import org.hotswap.agent.logging.AgentLogger;
import org.hotswap.agent.util.AnnotationHelper;
/**
* Reload Hibernate configuration after entity create/change.
*
* @author Jiri Bubnik
* @author alpapad@gmail.com
*/
@Plugin(name = "Hibernate3", //
group = "groupHibernate",
description = "Reload Hibernate configuration after entity create/change.", //
testedVersions = { "3.6" }, //
expectedVersions = { "3.6" }, //
supportClass = { Hibernate3Transformers.class })
@Versions(maven = { @Maven(value = "[3.0,4.0)", artifactId = "hibernate-core", groupId = "org.hibernate") })
public class Hibernate3Plugin {
/** The Constant ENTITY_ANNOTATION. */
private static final String ENTITY_ANNOTATION = "javax.persistence.Entity";
/** The logger. */
private static AgentLogger LOGGER = AgentLogger.getLogger(Hibernate3Plugin.class);
/** The scheduler. */
@Init
Scheduler scheduler;
/** The app class loader. */
@Init
ClassLoader appClassLoader;
/** The version. */
String version;
/** The reload session factory command. */
// refresh command
private final Command reloadSessionFactoryCommand = new ReflectionCommand(this, Hibernate3RefreshCommand.class.getName(), "reloadSessionFactory");
/**
* Plugin initialization properties (from Hibernate3JPAHelper or
* SessionFactoryProxy).
*/
@Init
public void init() {
LOGGER.info("Hibernate3 Session plugin initialized", version);
}
/** The enabled. */
boolean enabled = true;
/**
* Disable plugin (if environment is JPA)
*
* Need to re-think this: Maybe use OverrideConfig to hold this info?.
*/
public void disable() {
LOGGER.info("Disabling Hibernate3 Session plugin since JPA is active");
this.enabled = false;
}
/**
* Sets the version.
*
* @param v
* the new version
*/
public void setVersion(String v) {
this.version = v;
LOGGER.info("Hibernate Core version '{}'", version);
}
/**
* Reload after entity class change. It covers also @Entity annotation
* removal.
*
* @param clazz
* the clazz
* @param original
* the original
*/
@OnClassLoadEvent(classNameRegexp = ".*", events = LoadEvent.REDEFINE)
public void entityReload(CtClass clazz, Class<?> original) {
// TODO list of entity/resource files is known to hibernate,
// better to check this list
if (AnnotationHelper.hasAnnotation(original, ENTITY_ANNOTATION) || AnnotationHelper.hasAnnotation(clazz, ENTITY_ANNOTATION)) {
LOGGER.debug("Entity reload class {}, original classloader {}", clazz.getName(), original.getClassLoader());
refresh(500);
}
}
/**
* New entity class - not covered by reloading mechanism.
* <p/>
* Increase the reload timeout to avoid duplicate reloading in case of
* recompile with IDE and delete/create event sequence - than create is
* cached by this event and hotswap for the same class by entityReload.
*
* @param clazz
* the clazz
* @throws Exception
* the exception
*/
@OnClassFileEvent(classNameRegexp = ".*", events = { FileEvent.CREATE })
public void newEntity(CtClass clazz) throws Exception {
if (AnnotationHelper.hasAnnotation(clazz, ENTITY_ANNOTATION)) {
refresh(500);
}
}
/**
* Reload on hbm file modifications.
*/
@OnResourceFileEvent(path = "/", filter = ".*.hbm.xml")
public void refreshOnHbm() {
refresh(500);
}
/**
* Reload on hibernate.cfg.xml file modifications
*/
@OnResourceFileEvent(path = "/", filter = ".*.cfg.xml")
public void refreshOnCfg() {
refresh(500);
}
// reload the configuration - schedule a command to run in the application
/**
* Refresh.
*
* @param timeout
* the timeout
*/
// classloader and merge duplicate commands.
public void refresh(int timeout) {
if (enabled) {
scheduler.scheduleCommand(reloadSessionFactoryCommand, timeout);
}
}
}