Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* The Abiquo Platform
* Cloud management application for hybrid clouds
* Copyright (C) 2008 - Abiquo Holdings S.L.
*
* This application is free software; you can redistribute it and/or
* modify it under the terms of the GNU LESSER GENERAL PUBLIC
* LICENSE as published by the Free Software Foundation under
* version 3 of the License
*
* This software 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 v.3 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package com.abiquo.commons.plugin.internal;
import static com.abiquo.commons.plugin.internal.function.Functions.TO_CLASS;
import static com.google.common.base.Throwables.propagateIfInstanceOf;
import static com.google.common.collect.Lists.transform;
import static java.util.Arrays.asList;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Vector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.abiquo.commons.plugin.UnsupportedOperation;
import com.abiquo.commons.plugin.exception.ComputeException;
import com.google.common.reflect.AbstractInvocationHandler;
/**
* Handles automatically plugin composition.
*
* @author Serafin Sedano
*/
public class PluginInvocationHandler extends AbstractInvocationHandler
{
private static final Logger LOGGER = LoggerFactory.getLogger(PluginInvocationHandler.class);
private final Object target;
/**
* @param target instanceof Pluggable or Firewall
*/
public PluginInvocationHandler(final Object target)
{
this.target = target;
}
@Override
public Object handleInvocation(final Object proxy, final Method method, final Object[] args)
throws UnsupportedOperationException, ComputeException
{
try
{
checkOperationSupported(target, method, args);
return method.invoke(target, args);
}
catch (IllegalAccessException | IllegalArgumentException | SecurityException
| InvocationTargetException e)
{
LOGGER.trace("invoke: Plugin {}. Trying to invoke {}. Error {}:{}", new Object[] {
target.getClass().getName(), method.getName(), e.getClass().getName(), e.getMessage()});
propagateIfInstanceOf(e.getCause(), ComputeException.class);
throw new RuntimeException(e);
}
}
/** If method is not implemented or annotated with UnsupportedOperation is not supported. */
private void checkOperationSupported(final Object plugin, final Method method,
final Object[] args) throws UnsupportedOperationException
{
long t = System.currentTimeMillis();
try
{
Method operation = findMethod(plugin, method.getName(), getParameters(args));
if (operation.isAnnotationPresent(UnsupportedOperation.class))
{
LOGGER.warn("checkOperationSupported: method {} unsupported for this plugin {}",
new Object[] {method.getName(), target.getClass().getName()});
throw new UnsupportedOperationException(method.getName()
+ " is not implemented in plugin");
}
}
catch (NoSuchMethodException e)
{
LOGGER.warn("checkOperationSupported: method not implemented {} for this plugin {}",
new Object[] {method.getName(), target.getClass().getName()});
throw new UnsupportedOperationException(method.getName()
+ " is not implemented in plugin");
}
LOGGER.trace("checkOperationSupported: duration {}", t - System.currentTimeMillis());
}
private static Method findMethod(final Object plugin, final String name,
final Class[] parameterTypes) throws NoSuchMethodException
{
int l = parameterTypes.length;
Method[] methods = plugin.getClass().getMethods();
// First find the applicable methods
Vector applicableMethods = new Vector<>();
for (int i = 0; i < methods.length; i++)
{
// Check the name matches
if (!methods[i].getName().equals(name))
{
continue;
}
// Check the parameters match
Class[] params = methods[i].getParameterTypes();
if (params.length != l)
{
continue;
}
int j;
for (j = 0; j < l; j++)
{
if (!Object.class.equals(parameterTypes[j])
&& !params[j].isAssignableFrom(parameterTypes[j]))
{
break;
}
}
// If so, add it to the list
if (j == l)
{
applicableMethods.add(methods[i]);
}
}
int size = applicableMethods.size();
if (size == 0)
{
throw new NoSuchMethodException("No such method: " + name);
}
// By the definition of our interfaces we exit
// If this change we should look for the maximally specific
if (applicableMethods.size() == 1)
{
return applicableMethods.elementAt(0);
}
/* For a definition of maximally specific, see JLS section 15.11.2.2. */
int maximallySpecific = -1; // Index of maximally specific method
for (int i = 0; i < size; i++)
{
int j;
// In terms of the JLS, current is T
Method current = applicableMethods.elementAt(i);
Class[] currentParams = current.getParameterTypes();
Class currentDeclarer = current.getDeclaringClass();
for (j = 0; j < size; j++)
{
if (i == j)
{
continue;
}
// In terms of the JLS, test is U
Method method = applicableMethods.elementAt(j);
Class[] params = method.getParameterTypes();
Class declared = method.getDeclaringClass();
// Check if T is a subclass of U, breaking if not
if (!declared.isAssignableFrom(currentDeclarer))
{
break;
}
// Check if each parameter in T is a subclass of the
// equivalent parameter in U
int k;
for (k = 0; k < l; k++)
{
if (!params[k].isAssignableFrom(currentParams[k]))
{
break;
}
}
if (k != l)
{
break;
}
}
// Maximally specific!
if (j == size)
{
if (maximallySpecific != -1)
{
throw new NoSuchMethodException("Ambiguous method search - more than one maximally specific method");
}
maximallySpecific = i;
}
}
if (maximallySpecific == -1)
{
throw new NoSuchMethodException("No maximally specific method.");
}
return applicableMethods.elementAt(maximallySpecific);
}
private Class[] getParameters(final Object[] args)
{
return transform(asList(args), TO_CLASS).toArray(new Class[0]);
}
}