mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged HEAD (5.1) to 5.1.N (5.1.1)
117473 bhorje: CM-690 trait extension git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.1.N/root@117558 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class AJDanglingExtensionError implements AJExtensibleCompilingError
|
||||
{
|
||||
private Method danglingMethod;
|
||||
private Extend extendDeclaration;
|
||||
|
||||
public AJDanglingExtensionError(Method danglingMethod,Extend extendDeclaration)
|
||||
{
|
||||
super();
|
||||
this.danglingMethod = danglingMethod;
|
||||
this.extendDeclaration=extendDeclaration;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getShortMessage()
|
||||
{
|
||||
return "Dangling extension method "+danglingMethod+" "+extendDeclaration;
|
||||
}
|
||||
|
||||
}
|
504
source/java/org/alfresco/traitextender/AJExtender.java
Normal file
504
source/java/org/alfresco/traitextender/AJExtender.java
Normal file
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
import com.hazelcast.util.ConcurrentHashSet;
|
||||
|
||||
public class AJExtender
|
||||
{
|
||||
private static final Object[] SAFE_NULL_ARGS = new Object[0];
|
||||
|
||||
private static Log logger = LogFactory.getLog(AJExtender.class);
|
||||
|
||||
private static ConcurrentHashSet<ExtensionRoute> oneTimeLogSet = null;
|
||||
|
||||
private static final ThreadLocal<Stack<Boolean>> ajPointsLocalEnabled = new ThreadLocal<Stack<Boolean>>()
|
||||
{
|
||||
protected Stack<Boolean> initialValue()
|
||||
{
|
||||
Stack<Boolean> enablementStack = new Stack<Boolean>();
|
||||
enablementStack.push(true);
|
||||
return enablementStack;
|
||||
};
|
||||
};
|
||||
|
||||
static class ProceedingContext
|
||||
{
|
||||
final Extend extend;
|
||||
|
||||
final ProceedingJoinPoint proceedingJoinPoint;
|
||||
|
||||
ProceedingContext(Extend extend, ProceedingJoinPoint proceedingJoinPoint)
|
||||
{
|
||||
super();
|
||||
this.extend = extend;
|
||||
this.proceedingJoinPoint = proceedingJoinPoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final ThreadLocal<Stack<ProceedingContext>> ajLocalProceedingJoinPoints = new ThreadLocal<Stack<ProceedingContext>>()
|
||||
{
|
||||
protected java.util.Stack<ProceedingContext> initialValue()
|
||||
{
|
||||
return new Stack<>();
|
||||
};
|
||||
};
|
||||
|
||||
public static interface ExtensionBypass<R>
|
||||
{
|
||||
R run() throws Throwable;
|
||||
}
|
||||
|
||||
public static class CompiledExtensible
|
||||
{
|
||||
private Class<? extends Extensible> extensible;
|
||||
|
||||
private Map<Method, ExtensionRoute> routedMethods = new HashMap<>();
|
||||
|
||||
private Map<Method, ExtensionRoute> notRoutedMethods = new HashMap<>();
|
||||
|
||||
private List<AJExtensibleCompilingError> errors = new LinkedList<>();
|
||||
|
||||
public CompiledExtensible(Class<? extends Extensible> extensible)
|
||||
{
|
||||
super();
|
||||
this.extensible = extensible;
|
||||
}
|
||||
|
||||
public Class<? extends Extensible> getExtensible()
|
||||
{
|
||||
return this.extensible;
|
||||
}
|
||||
|
||||
public void add(AJExtensibleCompilingError error)
|
||||
{
|
||||
this.errors.add(error);
|
||||
}
|
||||
|
||||
public boolean hasErrors()
|
||||
{
|
||||
return !errors.isEmpty();
|
||||
}
|
||||
|
||||
public String getErrorsString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (AJExtensibleCompilingError error : errors)
|
||||
{
|
||||
builder.append(error.getShortMessage());
|
||||
builder.append("\n");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public List<AJExtensibleCompilingError> getErrors()
|
||||
{
|
||||
return this.errors;
|
||||
}
|
||||
|
||||
public void add(ExtensionRoute route)
|
||||
{
|
||||
if (route.extensionMethod == null)
|
||||
{
|
||||
notRoutedMethods.remove(route.extendedMethod);
|
||||
routedMethods.put(route.extendedMethod,
|
||||
route);
|
||||
}
|
||||
else if (!routedMethods.containsKey(route.extendedMethod))
|
||||
{
|
||||
routedMethods.put(route.extendedMethod,
|
||||
route);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<ExtensionRoute> getAllNotRouted()
|
||||
{
|
||||
return notRoutedMethods.values();
|
||||
}
|
||||
|
||||
public int getExtendedMethodCount()
|
||||
{
|
||||
return routedMethods.size() + notRoutedMethods.size();
|
||||
}
|
||||
|
||||
public String getInfo()
|
||||
{
|
||||
return extensible.getName() + "{ " + routedMethods.size() + " routed methods; " + notRoutedMethods.size()
|
||||
+ " not routed methods;" + errors.size() + " errors}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExtensionRoute
|
||||
{
|
||||
final Extend extendAnnotation;
|
||||
|
||||
final Method extendedMethod;
|
||||
|
||||
final Method extensionMethod;
|
||||
|
||||
ExtensionRoute(Extend extendAnnotation, Method traitMethod)
|
||||
{
|
||||
this(extendAnnotation,
|
||||
traitMethod,
|
||||
null);
|
||||
}
|
||||
|
||||
ExtensionRoute(Extend extendAnnotation, Method extendedMethod, Method extensionMethod)
|
||||
{
|
||||
super();
|
||||
ParameterCheck.mandatory("extendAnnotation",
|
||||
extendAnnotation);
|
||||
ParameterCheck.mandatory("traitMethod",
|
||||
extendedMethod);
|
||||
|
||||
this.extendAnnotation = extendAnnotation;
|
||||
this.extendedMethod = extendedMethod;
|
||||
this.extensionMethod = extensionMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj instanceof ExtensionRoute)
|
||||
{
|
||||
ExtensionRoute route = (ExtensionRoute) obj;
|
||||
return extendAnnotation.traitAPI().equals(route.extendAnnotation.traitAPI())
|
||||
&& extendAnnotation.extensionAPI().equals(route.extendAnnotation.extensionAPI())
|
||||
&& extendedMethod.equals(route.extendedMethod)
|
||||
&& ((extensionMethod == null && route.extensionMethod == null) || (extensionMethod != null && extensionMethod
|
||||
.equals(route.extensionMethod)));
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String extensionString = "NOT ROUTED";
|
||||
|
||||
if (extensionMethod != null)
|
||||
{
|
||||
Class<?> exDeclClass = extendedMethod.getDeclaringClass();
|
||||
extensionString = extensionMethod.toGenericString() + "#" + exDeclClass;
|
||||
}
|
||||
|
||||
return extendAnnotation.toString() + "\t\n[" + extendedMethod.toGenericString() + " -> " + extensionString
|
||||
+ "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return extendAnnotation.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean areAJPointsEnabled()
|
||||
{
|
||||
return ajPointsLocalEnabled.get().peek();
|
||||
}
|
||||
|
||||
static void enableAJPoints()
|
||||
{
|
||||
ajPointsLocalEnabled.get().push(true);
|
||||
}
|
||||
|
||||
static void revertAJPoints()
|
||||
{
|
||||
ajPointsLocalEnabled.get().pop();
|
||||
}
|
||||
|
||||
public static <R> R throwableRun(AJExtender.ExtensionBypass<R> section) throws Throwable
|
||||
{
|
||||
try
|
||||
{
|
||||
AJExtender.ajPointsLocalEnabled.get().push(false);
|
||||
return section.run();
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
AJExtender.ajPointsLocalEnabled.get().pop();
|
||||
}
|
||||
}
|
||||
|
||||
public static <R> R run(AJExtender.ExtensionBypass<R> section, Class<?>[] exTypes) throws Throwable
|
||||
{
|
||||
try
|
||||
{
|
||||
return throwableRun(section);
|
||||
}
|
||||
catch (Error | RuntimeException error)
|
||||
{
|
||||
throw error;
|
||||
}
|
||||
catch (Throwable error)
|
||||
{
|
||||
throw asCheckThrowable(error,
|
||||
exTypes);
|
||||
}
|
||||
}
|
||||
|
||||
public static Throwable asCheckThrowable(Throwable error, Class<?>... checkedThrowableTypes)
|
||||
{
|
||||
Class<? extends Throwable> errorClass = error.getClass();
|
||||
for (int i = 0; i < checkedThrowableTypes.length; i++)
|
||||
{
|
||||
if (errorClass.equals(checkedThrowableTypes[i]))
|
||||
{
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return new UndeclaredThrowableException(error);
|
||||
}
|
||||
|
||||
public static <R> R run(AJExtender.ExtensionBypass<R> section)
|
||||
{
|
||||
try
|
||||
{
|
||||
return throwableRun(section);
|
||||
}
|
||||
catch (Error | RuntimeException error)
|
||||
{
|
||||
throw error;
|
||||
}
|
||||
catch (Throwable error)
|
||||
{
|
||||
throw new UndeclaredThrowableException(error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void oneTimeLiveLog(Log logger, ExtensionRoute route)
|
||||
{
|
||||
synchronized (AJExtender.class)
|
||||
{
|
||||
if (oneTimeLogSet == null)
|
||||
{
|
||||
oneTimeLogSet = new ConcurrentHashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (oneTimeLogSet)
|
||||
{
|
||||
if (oneTimeLogSet.contains(route))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug(route.toString());
|
||||
oneTimeLogSet.add(route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static CompiledExtensible compile(Class<? extends Extensible> extensible)
|
||||
throws AJExtensibleCompilingException
|
||||
{
|
||||
logger.info("Compiling extensible " + extensible);
|
||||
|
||||
CompiledExtensible compiledExtensible = new CompiledExtensible(extensible);
|
||||
|
||||
List<Method> methods = new ArrayList<>();
|
||||
Class<?> extendDeclaring = extensible;
|
||||
while (extendDeclaring != null)
|
||||
{
|
||||
Method[] declaredMethods = extendDeclaring.getDeclaredMethods();
|
||||
methods.addAll(Arrays.asList(declaredMethods));
|
||||
extendDeclaring = extendDeclaring.getSuperclass();
|
||||
}
|
||||
Set<Extend> extendDeclarations = new HashSet<>();
|
||||
Set<Method> routedExtensionMethods = new HashSet<>();
|
||||
for (Method method : methods)
|
||||
{
|
||||
|
||||
Extend extend = method.getAnnotation(Extend.class);
|
||||
if (extend != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
extendDeclarations.add(extend);
|
||||
Class<?> extensionAPI = extend.extensionAPI();
|
||||
Method extensionMethod = extensionAPI.getMethod(method.getName(),
|
||||
method.getParameterTypes());
|
||||
compiledExtensible.add(new ExtensionRoute(extend,
|
||||
method,
|
||||
extensionMethod));
|
||||
routedExtensionMethods.add(extensionMethod);
|
||||
}
|
||||
catch (NoSuchMethodException error)
|
||||
{
|
||||
AJExtensibleCompilingException ajCompilingError = new AJExtensibleCompilingException("No route for "
|
||||
+ method.toGenericString()
|
||||
+ " @"
|
||||
+ extend,
|
||||
error);
|
||||
compiledExtensible.add(ajCompilingError);
|
||||
}
|
||||
catch (SecurityException error)
|
||||
{
|
||||
AJExtensibleCompilingException ajCompilingError = new AJExtensibleCompilingException("Access denined to route for "
|
||||
+ method.toGenericString()
|
||||
+ " @"
|
||||
+ extend,
|
||||
error);
|
||||
compiledExtensible.add(ajCompilingError);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final Set<Method> allObjectMethods = new HashSet<>(Arrays.asList(Object.class.getMethods()));
|
||||
|
||||
for (Extend extend : extendDeclarations)
|
||||
{
|
||||
Class<?> extension = extend.extensionAPI();
|
||||
|
||||
Set<Method> allExtensionMethods = new HashSet<>(Arrays.asList(extension.getMethods()));
|
||||
allExtensionMethods.removeAll(allObjectMethods);
|
||||
allExtensionMethods.removeAll(routedExtensionMethods);
|
||||
if (!allExtensionMethods.isEmpty())
|
||||
{
|
||||
for (Method method : allExtensionMethods)
|
||||
{
|
||||
compiledExtensible.add(new AJDanglingExtensionError(method,
|
||||
extend));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(compiledExtensible.getInfo());
|
||||
|
||||
return compiledExtensible;
|
||||
}
|
||||
|
||||
public static Object extendAroundAdvice(JoinPoint thisJoinPoint, Extensible extensible, Extend extendAnnotation,
|
||||
Object extension)
|
||||
{
|
||||
|
||||
MethodSignature ms = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = ms.getMethod();
|
||||
try
|
||||
{
|
||||
ajLocalProceedingJoinPoints.get().push(new ProceedingContext(extendAnnotation,
|
||||
(ProceedingJoinPoint) thisJoinPoint));
|
||||
|
||||
Method extensionMethod = extension.getClass().getMethod(method.getName(),
|
||||
method.getParameterTypes());
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
oneTimeLiveLog(AJExtender.logger,
|
||||
new ExtensionRoute(extendAnnotation,
|
||||
method,
|
||||
extensionMethod));
|
||||
}
|
||||
|
||||
return extensionMethod.invoke(extension,
|
||||
thisJoinPoint.getArgs());
|
||||
}
|
||||
catch (IllegalAccessException error)
|
||||
{
|
||||
throw new InvalidExtension("Ivalid extension : " + error.getMessage(),
|
||||
error);
|
||||
}
|
||||
catch (IllegalArgumentException error)
|
||||
{
|
||||
throw new InvalidExtension("Ivalid extension : " + error.getMessage(),
|
||||
error);
|
||||
}
|
||||
catch (InvocationTargetException error)
|
||||
{
|
||||
Throwable targetException = error.getTargetException();
|
||||
if (targetException instanceof RuntimeException)
|
||||
{
|
||||
throw (RuntimeException) targetException;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ExtensionTargetException(targetException);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException error)
|
||||
{
|
||||
throw new InvalidExtension("Ivalid extension : " + error.getMessage(),
|
||||
error);
|
||||
}
|
||||
catch (SecurityException error)
|
||||
{
|
||||
throw new InvalidExtension("Ivalid extension : " + error.getMessage(),
|
||||
error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ajLocalProceedingJoinPoints.get().pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean isLocalProceeder(Method method)
|
||||
{
|
||||
if (!ajLocalProceedingJoinPoints.get().isEmpty())
|
||||
{
|
||||
ProceedingContext proceedingCotext = ajLocalProceedingJoinPoints.get().peek();
|
||||
MethodSignature ms = (MethodSignature) proceedingCotext.proceedingJoinPoint.getSignature();
|
||||
Method jpMethod = ms.getMethod();
|
||||
return jpMethod.getName().endsWith(method.getName()) && Arrays.equals(jpMethod.getParameterTypes(),
|
||||
method.getParameterTypes());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Object localProceed(Object[] args) throws Throwable
|
||||
{
|
||||
ProceedingContext proceedingCotext = ajLocalProceedingJoinPoints.get().peek();
|
||||
Object[] safeArgs = args == null ? SAFE_NULL_ARGS : args;
|
||||
return proceedingCotext.proceedingJoinPoint.proceed(safeArgs);
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public interface AJExtensibleCompilingError
|
||||
{
|
||||
String getShortMessage();
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public class AJExtensibleCompilingException extends Exception implements AJExtensibleCompilingError
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public AJExtensibleCompilingException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AJExtensibleCompilingException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace)
|
||||
{
|
||||
super(message,
|
||||
cause,
|
||||
enableSuppression,
|
||||
writableStackTrace);
|
||||
}
|
||||
|
||||
public AJExtensibleCompilingException(String message, Throwable cause)
|
||||
{
|
||||
super(message,
|
||||
cause);
|
||||
}
|
||||
|
||||
public AJExtensibleCompilingException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AJExtensibleCompilingException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortMessage()
|
||||
{
|
||||
return getMessage();
|
||||
}
|
||||
|
||||
}
|
122
source/java/org/alfresco/traitextender/AJProxyTrait.java
Normal file
122
source/java/org/alfresco/traitextender/AJProxyTrait.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.alfresco.traitextender.AJExtender.ExtensionBypass;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* Java {@link Proxy} {@link InvocationHandler} to be used in conjuction with
|
||||
* asprctJ extended traits.<br>
|
||||
* Method calls will be delegated to a given {@link Extensible} object method
|
||||
* having the same signature within an {@link ExtensionBypass} context.
|
||||
*
|
||||
* @author Bogdan Horje
|
||||
*/
|
||||
public class AJProxyTrait implements InvocationHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* {@link Trait} {@link Proxy} factory method.
|
||||
*
|
||||
* @param extensible the {@link Extensible} object that defines the given
|
||||
* {@link Trait}
|
||||
* @param traitAPI the trait interface part that the given
|
||||
* {@link Extensible} object defines
|
||||
* @return a {@link Proxy} object for the given trait API interface with an
|
||||
* {@link AJProxyTrait} attached. All method calls performed on the
|
||||
* returned proxy will be delegated to a given {@link Extensible}
|
||||
* object method having the same signature within an
|
||||
* {@link ExtensionBypass} context.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <M extends Trait> M create(Object extensibleInterface, Class<M> traitAPI)
|
||||
{
|
||||
return (M) Proxy.newProxyInstance(AJProxyTrait.class.getClassLoader(),
|
||||
new Class[] { traitAPI },
|
||||
new AJProxyTrait(extensibleInterface));
|
||||
}
|
||||
|
||||
private Object extensibleInterface;
|
||||
|
||||
private AJProxyTrait(Object extensibleInterface)
|
||||
{
|
||||
ParameterCheck.mandatory("extensible",
|
||||
extensibleInterface);
|
||||
this.extensibleInterface = extensibleInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, final Object[] args) throws Throwable
|
||||
{
|
||||
final Method traitMethod = extensibleInterface.getClass().getMethod(method.getName(),
|
||||
method.getParameterTypes());
|
||||
|
||||
if (AJExtender.isLocalProceeder(method))
|
||||
{
|
||||
return AJExtender.localProceed(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Class<?>[] exTypes = traitMethod.getExceptionTypes();
|
||||
|
||||
return AJExtender.run(new AJExtender.ExtensionBypass<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object run() throws Throwable
|
||||
{
|
||||
try
|
||||
{
|
||||
return traitMethod.invoke(extensibleInterface,
|
||||
args);
|
||||
}
|
||||
catch (IllegalAccessException error)
|
||||
{
|
||||
throw new InvalidExtension(error);
|
||||
}
|
||||
catch (IllegalArgumentException error)
|
||||
{
|
||||
throw new InvalidExtension(error);
|
||||
}
|
||||
catch (InvocationTargetException error)
|
||||
{
|
||||
Throwable targetException = error.getTargetException();
|
||||
throw targetException;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
exTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "AJAutoTrait@" + System.identityHashCode(this) + " of " + extensibleInterface.getClass().getSimpleName() + "@"
|
||||
+ System.identityHashCode(extensibleInterface);
|
||||
}
|
||||
|
||||
}
|
29
source/java/org/alfresco/traitextender/Extend.java
Normal file
29
source/java/org/alfresco/traitextender/Extend.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Extend
|
||||
{
|
||||
Class<?> extensionAPI();
|
||||
Class<? extends Trait> traitAPI();
|
||||
}
|
62
source/java/org/alfresco/traitextender/ExtendedTrait.java
Normal file
62
source/java/org/alfresco/traitextender/ExtendedTrait.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ExtendedTrait<T extends Trait>
|
||||
{
|
||||
private ConcurrentHashMap<Class<?>, Object> extensions = new ConcurrentHashMap<Class<?>, Object>();
|
||||
|
||||
private T trait;
|
||||
|
||||
public ExtendedTrait(T trait)
|
||||
{
|
||||
super();
|
||||
this.trait = trait;
|
||||
}
|
||||
|
||||
public T getTrait()
|
||||
{
|
||||
return trait;
|
||||
}
|
||||
|
||||
public <E> E getExtension(Class<E> extensionAPI)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
E extension=(E) extensions.get(extensionAPI);
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
public synchronized <E> E extend(Class<E> extensionAPI, ExtensionFactory<E> factory)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
E extension=(E) extensions.get(extensionAPI);
|
||||
|
||||
if (extension==null)
|
||||
{
|
||||
extension = factory.createExtension(trait);
|
||||
extensions.put(extensionAPI, extension);
|
||||
|
||||
}
|
||||
|
||||
return extension;
|
||||
}
|
||||
}
|
56
source/java/org/alfresco/traitextender/Extender.java
Normal file
56
source/java/org/alfresco/traitextender/Extender.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class Extender
|
||||
{
|
||||
private static Extender instance;
|
||||
|
||||
public static class Configuration {
|
||||
private boolean enabled;
|
||||
private List<String> disbaledBundles;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static synchronized Extender getInstance()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new ExtenderImpl();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public abstract void start(ExtensionBundle bundle);
|
||||
|
||||
public abstract void stop(ExtensionBundle bundle);
|
||||
|
||||
public abstract void stopAll();
|
||||
|
||||
public abstract <E, M extends Trait> E getExtension(Extensible anExtensible, ExtensionPoint<E, M> point);
|
||||
|
||||
public abstract void register(ExtensionPoint<?, ?> point, ExtensionFactory<?> factory);
|
||||
|
||||
public abstract void unregister(ExtensionPoint<?, ?> point);
|
||||
|
||||
}
|
105
source/java/org/alfresco/traitextender/ExtenderImpl.java
Normal file
105
source/java/org/alfresco/traitextender/ExtenderImpl.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
public class ExtenderImpl extends Extender
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(Extender.class);
|
||||
|
||||
|
||||
|
||||
private List<ExtensionBundle> bundles = new LinkedList<ExtensionBundle>();
|
||||
|
||||
private Map<ExtensionPoint<?, ?>, ExtensionFactory<?>> pointFactories = new ConcurrentHashMap<ExtensionPoint<?, ?>, ExtensionFactory<?>>();
|
||||
|
||||
public synchronized void start(ExtensionBundle bundle)
|
||||
{
|
||||
bundles.add(bundle);
|
||||
bundle.start(this);
|
||||
}
|
||||
|
||||
public void stop(ExtensionBundle bundle)
|
||||
{
|
||||
bundle.stop(this);
|
||||
bundles.remove(bundle);
|
||||
}
|
||||
|
||||
public synchronized void stopAll()
|
||||
{
|
||||
List<ExtensionBundle> bundlesCopy = new LinkedList<>(bundles);
|
||||
for (ExtensionBundle bundle : bundlesCopy)
|
||||
{
|
||||
stop(bundle);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized <E, M extends Trait> E getExtension(Extensible anExtensible, ExtensionPoint<E, M> point)
|
||||
{
|
||||
E extension = null;
|
||||
|
||||
//consistency is checked at registration time
|
||||
@SuppressWarnings("unchecked")
|
||||
ExtensionFactory<E> factory = (ExtensionFactory<E>) pointFactories.get(point);
|
||||
|
||||
if (factory != null)
|
||||
{
|
||||
ExtendedTrait<M> exTrait = anExtensible.getTrait(point.getTraitAPI());
|
||||
|
||||
extension = exTrait.getExtension(point.getExtensionAPI());
|
||||
|
||||
if (extension == null)
|
||||
{
|
||||
extension = exTrait.extend(point.getExtensionAPI(),
|
||||
factory);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("trait extension leak trace : " + System.identityHashCode(extension) + " : "
|
||||
+ System.identityHashCode(exTrait) + " : " + System.identityHashCode(extension));
|
||||
}
|
||||
}
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
|
||||
public synchronized void register(ExtensionPoint<?, ?> point, ExtensionFactory<?> factory)
|
||||
{
|
||||
// point->factory type consistency checks
|
||||
if (!factory.canCreateExtensionFor(point))
|
||||
{
|
||||
throw new InvalidExtension("Invalid extension factory registry entry : " + point + "->" + factory);
|
||||
}
|
||||
pointFactories.put(point,
|
||||
factory);
|
||||
}
|
||||
|
||||
public synchronized void unregister(ExtensionPoint<?, ?> point)
|
||||
{
|
||||
pointFactories.remove(point);
|
||||
}
|
||||
|
||||
}
|
25
source/java/org/alfresco/traitextender/Extensible.java
Normal file
25
source/java/org/alfresco/traitextender/Extensible.java
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
|
||||
public interface Extensible
|
||||
{
|
||||
<T extends Trait> ExtendedTrait<T> getTrait(Class<? extends T> traitAPI);
|
||||
}
|
29
source/java/org/alfresco/traitextender/ExtensionBundle.java
Normal file
29
source/java/org/alfresco/traitextender/ExtensionBundle.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
|
||||
public interface ExtensionBundle
|
||||
{
|
||||
void start(Extender extender);
|
||||
|
||||
void stop(Extender extender);
|
||||
|
||||
String getId();
|
||||
}
|
26
source/java/org/alfresco/traitextender/ExtensionFactory.java
Normal file
26
source/java/org/alfresco/traitextender/ExtensionFactory.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public interface ExtensionFactory<E>
|
||||
{
|
||||
<T extends Trait> E createExtension(T trait);
|
||||
|
||||
boolean canCreateExtensionFor(ExtensionPoint<?, ?> point);
|
||||
}
|
70
source/java/org/alfresco/traitextender/ExtensionPoint.java
Normal file
70
source/java/org/alfresco/traitextender/ExtensionPoint.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public class ExtensionPoint<E, M extends Trait>
|
||||
{
|
||||
private Class<E> extensionAPI;
|
||||
|
||||
private Class<M> traitAPI;
|
||||
|
||||
public ExtensionPoint(Class<E> extensionAPI, Class<M> traitAPI)
|
||||
{
|
||||
super();
|
||||
this.extensionAPI = extensionAPI;
|
||||
this.traitAPI = traitAPI;
|
||||
}
|
||||
|
||||
public Class<E> getExtensionAPI()
|
||||
{
|
||||
return this.extensionAPI;
|
||||
}
|
||||
|
||||
public Class<M> getTraitAPI()
|
||||
{
|
||||
return this.traitAPI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return extensionAPI.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj instanceof ExtensionPoint)
|
||||
{
|
||||
ExtensionPoint<?,?> pointObj = (ExtensionPoint<?,?>) obj;
|
||||
return extensionAPI.equals(pointObj.extensionAPI)
|
||||
&& traitAPI.equals(pointObj.traitAPI);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "{" + extensionAPI.toString() + "," + traitAPI.toString() + "}";
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public class ExtensionPointActivator
|
||||
{
|
||||
private ExtensionBundle bundle;
|
||||
|
||||
private ExtensionPoint<?, ?> extensionPoint;
|
||||
|
||||
private ExtensionFactory<?> extensionFactory;
|
||||
|
||||
public <E> ExtensionPointActivator(ExtensionBundle bundle, ExtensionPoint<E, ?> extensionPoint,
|
||||
ExtensionFactory<E> extensionFactory)
|
||||
{
|
||||
super();
|
||||
this.bundle = bundle;
|
||||
this.extensionPoint = extensionPoint;
|
||||
this.extensionFactory = extensionFactory;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public class ExtensionTargetException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = -502697833178766952L;
|
||||
|
||||
public ExtensionTargetException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ExtensionTargetException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace)
|
||||
{
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
public ExtensionTargetException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ExtensionTargetException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ExtensionTargetException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public abstract class InstanceExtension<E, T extends Trait>
|
||||
{
|
||||
protected T trait;
|
||||
|
||||
public InstanceExtension(T trait)
|
||||
{
|
||||
super();
|
||||
this.trait = trait;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public class InstanceExtensionFactory<I extends InstanceExtension<E, T>, T extends Trait, E> implements
|
||||
ExtensionFactory<E>
|
||||
{
|
||||
private Class<? extends I> extensionClass;
|
||||
|
||||
private Class<T> traitAPI;
|
||||
|
||||
public <C extends I> InstanceExtensionFactory(Class<C> extensionClass, Class<T> traitAPI,
|
||||
Class<? extends E> extensionAPI)
|
||||
{
|
||||
super();
|
||||
this.extensionClass = extensionClass;
|
||||
this.traitAPI = traitAPI;
|
||||
|
||||
if (!extensionAPI.isAssignableFrom(extensionClass))
|
||||
{
|
||||
throw new InvalidExtension("Extension class " + extensionClass + " is incompatible with extensio API "
|
||||
+ extensionAPI);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <TO extends Trait> E createExtension(TO traitObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Trait RTTI will be performed anyway at Constructor#newInstance invocation time
|
||||
T tTrait = (T) traitObject;
|
||||
|
||||
Constructor<? extends I> c = extensionClass.getConstructor(traitAPI);
|
||||
return (E) c.newInstance(tTrait);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateExtensionFor(ExtensionPoint<?, ?> point)
|
||||
{
|
||||
return point.getExtensionAPI().isAssignableFrom(extensionClass)
|
||||
&& traitAPI.isAssignableFrom(point.getTraitAPI());
|
||||
}
|
||||
|
||||
}
|
50
source/java/org/alfresco/traitextender/InvalidExtension.java
Normal file
50
source/java/org/alfresco/traitextender/InvalidExtension.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public class InvalidExtension extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = -7146808120353555462L;
|
||||
|
||||
public InvalidExtension()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidExtension(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)
|
||||
{
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
public InvalidExtension(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public InvalidExtension(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidExtension(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* {@link ExtensionBundle} that supports simple {@link ExtensionPoint} to
|
||||
* {@link ExtensionFactory} association registration.
|
||||
*
|
||||
* @author Bogdan Horje
|
||||
*/
|
||||
public class RegistryExtensionBundle implements ExtensionBundle
|
||||
{
|
||||
|
||||
private Map<ExtensionPoint<?, ?>, ExtensionFactory<?>> factories = new HashMap<>();
|
||||
|
||||
private String id;
|
||||
|
||||
public RegistryExtensionBundle(String id)
|
||||
{
|
||||
ParameterCheck.mandatory("id",
|
||||
id);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an association between the given {@link ExtensionPoint} and
|
||||
* {@link ExtensionFactory}.<br>
|
||||
* At {@link #start(Extender)} time all registered {@link ExtensionPoint}s
|
||||
* will be registered with the given {@link Extender}.<br>
|
||||
* At {@link #stop(Extender)} time all registered {@link ExtensionPoint}s
|
||||
* will be unregistered with the given {@link Extender}.<br>
|
||||
*
|
||||
* @param point
|
||||
* @param factory
|
||||
*/
|
||||
public <E, C extends E, M extends Trait> void register(ExtensionPoint<E, M> point, ExtensionFactory<C> factory)
|
||||
{
|
||||
factories.put(point,
|
||||
factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Extender extender)
|
||||
{
|
||||
Set<Entry<ExtensionPoint<?, ?>, ExtensionFactory<?>>> factoryEntries = factories.entrySet();
|
||||
for (Entry<ExtensionPoint<?, ?>, ExtensionFactory<?>> entry : factoryEntries)
|
||||
{
|
||||
extender.register(entry.getKey(),
|
||||
entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(Extender extender)
|
||||
{
|
||||
Set<Entry<ExtensionPoint<?, ?>, ExtensionFactory<?>>> factoryEntries = factories.entrySet();
|
||||
for (Entry<ExtensionPoint<?, ?>, ExtensionFactory<?>> entry : factoryEntries)
|
||||
{
|
||||
extender.unregister(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
84
source/java/org/alfresco/traitextender/RouteExtensions.java
Normal file
84
source/java/org/alfresco/traitextender/RouteExtensions.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.alfresco.traitextender.AJExtender.ExtensionRoute;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
@Aspect
|
||||
public class RouteExtensions
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(RouteExtensions.class);
|
||||
|
||||
@Around("execution(@org.alfresco.traitextender.Extend * *(..)) && (@annotation(extendAnnotation))")
|
||||
public Object intercept(ProceedingJoinPoint pjp, Extend extendAnnotation) throws Throwable {
|
||||
boolean ajPointsEnabled = AJExtender.areAJPointsEnabled();
|
||||
try
|
||||
{
|
||||
AJExtender.enableAJPoints();
|
||||
if (ajPointsEnabled)
|
||||
{
|
||||
Object extensibleObject = pjp.getThis();
|
||||
if (!(extensibleObject instanceof Extensible))
|
||||
{
|
||||
throw new InvalidExtension("Invalid extension point for non extensible class : "
|
||||
+ extensibleObject.getClass());
|
||||
}
|
||||
Extensible extensible = (Extensible) extensibleObject;
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
ExtensionPoint point = new ExtensionPoint(extendAnnotation.extensionAPI(),
|
||||
extendAnnotation.traitAPI());
|
||||
@SuppressWarnings("unchecked")
|
||||
Object extension = Extender.getInstance().getExtension(extensible,
|
||||
point);
|
||||
if (extension != null)
|
||||
{
|
||||
|
||||
return AJExtender.extendAroundAdvice(pjp,
|
||||
extensible,
|
||||
extendAnnotation,
|
||||
extension);
|
||||
}
|
||||
else if (logger.isDebugEnabled())
|
||||
{
|
||||
MethodSignature ms = (MethodSignature) pjp.getSignature();
|
||||
Method traitMethod = ms.getMethod();
|
||||
|
||||
AJExtender.oneTimeLiveLog(logger,
|
||||
new ExtensionRoute(extendAnnotation,
|
||||
traitMethod));
|
||||
}
|
||||
}
|
||||
return pjp.proceed();
|
||||
}
|
||||
finally
|
||||
{
|
||||
AJExtender.revertAJPoints();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public abstract class SingletonExtension<E, T extends Trait>
|
||||
{
|
||||
private ThreadLocal<T> localTrait = new ThreadLocal<>();
|
||||
|
||||
private Class<T> traitClass;
|
||||
|
||||
public SingletonExtension(Class<T> traitClass)
|
||||
{
|
||||
super();
|
||||
this.traitClass = traitClass;
|
||||
}
|
||||
|
||||
public boolean acceptsTrait(Object trait)
|
||||
{
|
||||
return trait != null && acceptsTraitClass(trait.getClass());
|
||||
}
|
||||
|
||||
public boolean acceptsTraitClass(Class<?> aTraitClass)
|
||||
{
|
||||
return traitClass.isAssignableFrom(aTraitClass);
|
||||
}
|
||||
|
||||
void setTrait(T trait)
|
||||
{
|
||||
localTrait.set(trait);
|
||||
}
|
||||
|
||||
protected T getTrait()
|
||||
{
|
||||
return localTrait.get();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
public class SingletonExtensionFactory<E, S extends SingletonExtension<E, T>, T extends Trait> implements
|
||||
ExtensionFactory<E>
|
||||
{
|
||||
private Log logger = LogFactory.getLog(SingletonExtensionFactory.class);
|
||||
|
||||
private class TraiSingletontHandler implements InvocationHandler
|
||||
{
|
||||
private S singleton;
|
||||
|
||||
private T trait;
|
||||
|
||||
public TraiSingletontHandler(S singleton, T trait)
|
||||
{
|
||||
super();
|
||||
this.singleton = singleton;
|
||||
this.trait = trait;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
|
||||
{
|
||||
// Subsequent trait calls might change the trait on this thread.
|
||||
// We save the current trait on the current call-stack in order
|
||||
// to restore it on the finally block.
|
||||
|
||||
T stackedTrait = this.singleton.getTrait();
|
||||
|
||||
this.singleton.setTrait(trait);
|
||||
try
|
||||
{
|
||||
return method.invoke(this.singleton,
|
||||
args);
|
||||
}
|
||||
catch (IllegalAccessException error)
|
||||
{
|
||||
throw new InvalidExtension(error);
|
||||
}
|
||||
catch (IllegalArgumentException error)
|
||||
{
|
||||
throw new InvalidExtension(error);
|
||||
}
|
||||
catch (InvocationTargetException error)
|
||||
{
|
||||
Throwable targetException = error.getTargetException();
|
||||
throw targetException;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.singleton.setTrait(stackedTrait);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private S singleton;
|
||||
|
||||
private Class<E> extensionAPI;
|
||||
|
||||
public SingletonExtensionFactory(S singleton, Class<E> extensionAPI) throws InvalidExtension
|
||||
{
|
||||
super();
|
||||
if (!extensionAPI.isAssignableFrom(singleton.getClass()))
|
||||
{
|
||||
throw new InvalidExtension(singleton.getClass() + " is not an " + extensionAPI + " extension.");
|
||||
}
|
||||
this.singleton = singleton;
|
||||
this.extensionAPI = extensionAPI;
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <TO extends Trait> E createExtension(TO traitObject)
|
||||
{
|
||||
T tTrait = (T) traitObject;
|
||||
// perform programmatic RTTI
|
||||
if (!singleton.acceptsTrait(traitObject))
|
||||
{
|
||||
throw new InvalidExtension("Extension factory error : " + singleton.getClass() + " does not support trait "
|
||||
+ traitObject);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
String traitTrace = traitObject != null ? traitObject.getClass().toString() : "<null> trait";
|
||||
logger.info("Creating singleton extension " + singleton.getClass() + "<-" + traitTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("Creating singleton extension " + singleton.getClass());
|
||||
}
|
||||
|
||||
return (E) Proxy.newProxyInstance(getClass().getClassLoader(),
|
||||
new Class[] { extensionAPI },
|
||||
new TraiSingletontHandler(singleton,
|
||||
tTrait));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateExtensionFor(ExtensionPoint<?, ?> point)
|
||||
{
|
||||
return point.getExtensionAPI().isAssignableFrom(singleton.getClass())
|
||||
&& singleton.acceptsTraitClass(point.getTraitAPI());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public abstract class SpringBeanExtension<E,T extends Trait> extends SingletonExtension<E, T>
|
||||
{
|
||||
private SpringExtensionPoint extensionPoint;
|
||||
|
||||
public SpringBeanExtension(Class<T> traitClass)
|
||||
{
|
||||
super(traitClass);
|
||||
}
|
||||
|
||||
public void setExtensionPoint(SpringExtensionPoint extensionPoint)
|
||||
{
|
||||
this.extensionPoint = extensionPoint;
|
||||
}
|
||||
|
||||
public void register(RegistryExtensionBundle bundle) throws InvalidExtension
|
||||
{
|
||||
extensionPoint.register(bundle,this);
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
public class SpringExtensionBundle implements InitializingBean
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(SpringExtensionBundle.class);
|
||||
|
||||
private List<SpringBeanExtension<?, ?>> extensions = Collections.emptyList();
|
||||
|
||||
private String id;
|
||||
|
||||
private boolean enabled=true;
|
||||
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void setExtensions(List<SpringBeanExtension<?, ?>> extensions)
|
||||
{
|
||||
this.extensions = extensions;
|
||||
}
|
||||
|
||||
public void setId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
if (this.enabled)
|
||||
{
|
||||
logger.info("Starting extension bundle " + id);
|
||||
|
||||
RegistryExtensionBundle extensionBundle = new RegistryExtensionBundle(id);
|
||||
|
||||
for (SpringBeanExtension<?, ?> springExtension : extensions)
|
||||
{
|
||||
try
|
||||
{
|
||||
springExtension.register(extensionBundle);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
throw new InvalidExtension("Could not register extension " + springExtension + " with "
|
||||
+ extensionBundle,
|
||||
error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Extender.getInstance().start(extensionBundle);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("Extension bundle " + id + " is disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public class SpringExtensionPoint
|
||||
{
|
||||
private String trait;
|
||||
|
||||
private String extension;
|
||||
|
||||
public void setTrait(String trait)
|
||||
{
|
||||
this.trait = trait;
|
||||
}
|
||||
|
||||
public void setExtension(String extension)
|
||||
{
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void register(RegistryExtensionBundle bundle, SpringBeanExtension<?, ?> extensionBean)
|
||||
throws InvalidExtension
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
Class<?> extensionAPI = Class.forName(extension);
|
||||
Class<? extends Trait> traitAPI = (Class<? extends Trait>) Class.forName(trait);
|
||||
|
||||
// perform RTTIs in order to avoid later cast exceptions
|
||||
|
||||
if (!Trait.class.isAssignableFrom(traitAPI))
|
||||
{
|
||||
throw new InvalidExtension("Non " + Trait.class + " spring extension point : " + traitAPI);
|
||||
}
|
||||
|
||||
if (!extensionBean.acceptsTraitClass(traitAPI))
|
||||
{
|
||||
throw new InvalidExtension("Unsupported trait class : " + traitAPI + " in extension point targeting "
|
||||
+ extensionBean);
|
||||
}
|
||||
|
||||
bundle.register(new ExtensionPoint(extensionAPI,
|
||||
traitAPI),
|
||||
new SingletonExtensionFactory(extensionBean,
|
||||
extensionAPI));
|
||||
|
||||
}
|
||||
catch (InvalidExtension error)
|
||||
{
|
||||
throw error;
|
||||
}
|
||||
catch (ClassNotFoundException error)
|
||||
{
|
||||
throw new InvalidExtension("Extension point definition class not found.",
|
||||
error);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
public class SpringTraitExtenderConfigurator implements InitializingBean
|
||||
{
|
||||
|
||||
private boolean enableTraitExtender;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
}
|
24
source/java/org/alfresco/traitextender/Trait.java
Normal file
24
source/java/org/alfresco/traitextender/Trait.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package org.alfresco.traitextender;
|
||||
|
||||
public interface Trait
|
||||
{
|
||||
|
||||
}
|
Reference in New Issue
Block a user