package org.hotswap.agent.annotation.handler;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.hotswap.agent.annotation.Plugin;
import org.hotswap.agent.logging.AgentLogger;
import org.hotswap.agent.versions.DeploymentInfo;
import org.hotswap.agent.versions.VersionMatchResult;
import org.hotswap.agent.versions.matcher.MethodMatcher;
import org.hotswap.agent.versions.matcher.PluginMatcher;
/**
* DTO for resolved plugin annotation properties.
* <p/>
* Either method OR field is filled - never both (annotation on method or field).
*
* @author Jiri Bubnik
*/
public class PluginAnnotation<T extends Annotation> {
private static AgentLogger LOGGER = AgentLogger.getLogger(PluginAnnotation.class);
// the main plugin class
Class<?> pluginClass;
// target plugin object
Object plugin;
// the annotation to process
T annotation;
// annotation is on a field (and method property is empty)
Field field;
// annotation is on a method (and field property is empty)
Method method;
// plugin matcher
final PluginMatcher pluginMatcher;
// Method matcher
final MethodMatcher methodMatcher;
// plugin group (elresolver etc..)
final String group;
// Falback plugin - plugin is used if no other plugin in the group version matches
final boolean fallback;
public PluginAnnotation(Class<?> pluginClass, Object plugin, T annotation, Method method) {
this.pluginClass = pluginClass;
this.plugin = plugin;
this.annotation = annotation;
this.method = method;
Plugin pluginAnnotation = pluginClass.getAnnotation(Plugin.class);
this.group = (pluginAnnotation.group() != null && !pluginAnnotation.group().isEmpty()) ? pluginAnnotation.group() : null;
this.fallback = pluginAnnotation.fallback();
if(method != null && (Modifier.isStatic(method.getModifiers()))) {
this.pluginMatcher = new PluginMatcher(pluginClass);
this.methodMatcher= new MethodMatcher(method);
} else {
this.pluginMatcher = null;
this.methodMatcher = null;
}
}
public PluginAnnotation(Class<?> pluginClass, Object plugin, T annotation, Field field) {
this.pluginClass = pluginClass;
this.plugin = plugin;
this.annotation = annotation;
this.field = field;
this.pluginMatcher = null;
this.methodMatcher = null;
this.fallback = false;
this.group = null;
}
/**
* Return plugin class (the plugin to which this annotation belongs - not necessarily declaring class.
*/
public Class<?> getPluginClass() {
return pluginClass;
}
public Object getPlugin() {
return plugin;
}
public T getAnnotation() {
return annotation;
}
public Method getMethod() {
return method;
}
public Field getField() {
return field;
}
public boolean shouldCheckVersion() {
return //
(this.plugin == null)//
&& //
(//
(pluginMatcher != null && pluginMatcher.isApply()) //
|| //
(methodMatcher != null && methodMatcher.isApply())//
);//
}
/**
* @return true, if plugin is fallback
*/
public boolean isFallBack() {
return fallback;
}
/**
* @return the plugin group
*/
public String getGroup() {
return group;
}
/**
* Matches.
*
* @param deploymentInfo the deployment info
* @return true, if successful
*/
public boolean matches(DeploymentInfo deploymentInfo){
if(deploymentInfo == null || (pluginMatcher == null && methodMatcher == null)) {
LOGGER.debug("No matchers, apply");
return true;
}
if(pluginMatcher != null && pluginMatcher.isApply()) {
if(VersionMatchResult.REJECTED.equals(pluginMatcher.matches(deploymentInfo))){
LOGGER.debug("Plugin matcher rejected");
return false;
}
}
if(methodMatcher != null && methodMatcher.isApply()) {
if(VersionMatchResult.REJECTED.equals(methodMatcher.matches(deploymentInfo))){
LOGGER.debug("Method matcher rejected");
return false;
}
}
return true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PluginAnnotation<?> that = (PluginAnnotation<?>) o;
if (!annotation.equals(that.annotation)) return false;
if (field != null ? !field.equals(that.field) : that.field != null) return false;
if (method != null ? !method.equals(that.method) : that.method != null) return false;
if (!plugin.equals(that.plugin)) return false;
return true;
}
@Override
public int hashCode() {
int result = plugin.hashCode();
result = 31 * result + annotation.hashCode();
result = 31 * result + (field != null ? field.hashCode() : 0);
result = 31 * result + (method != null ? method.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "PluginAnnotation{" +
"plugin=" + plugin +
", annotation=" + annotation +
", field=" + field +
", method=" + method +
'}';
}
}