From c62d655585280e42ad9b18ccfe01dd1d40f01d85 Mon Sep 17 00:00:00 2001 From: Raluca Munteanu Date: Fri, 11 Dec 2015 09:41:45 +0000 Subject: [PATCH] Merged HEAD (5.1) to 5.1.N (5.1.1) 119697 bhorje: ACE-4744 javadoc and cleanup git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.1.N/root@120076 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../AJDanglingExtensionError.java | 43 --- .../alfresco/traitextender/AJExtender.java | 272 ++++++++++++++++-- .../AJExtensibleCompilingError.java | 24 -- .../AJExtensibleCompilingException.java | 65 ----- .../org/alfresco/traitextender/Extend.java | 14 + .../alfresco/traitextender/ExtendedTrait.java | 27 +- .../org/alfresco/traitextender/Extender.java | 101 ++++++- .../alfresco/traitextender/ExtenderImpl.java | 9 +- .../alfresco/traitextender/Extensible.java | 18 +- .../traitextender/ExtensionBundle.java | 23 +- .../traitextender/ExtensionFactory.java | 18 +- .../traitextender/ExtensionPoint.java | 17 +- .../ExtensionPointActivator.java | 21 -- .../ExtensionTargetException.java | 14 +- .../traitextender/InstanceExtension.java | 6 + .../InstanceExtensionFactory.java | 9 +- .../traitextender/InvalidExtension.java | 14 +- .../traitextender/RouteExtensions.java | 23 +- .../traitextender/SingletonExtension.java | 15 +- .../SingletonExtensionFactory.java | 7 + .../traitextender/SpringBeanExtension.java | 17 +- .../traitextender/SpringExtensionBundle.java | 71 ++++- .../traitextender/SpringExtensionPoint.java | 9 + .../SpringTraitExtenderConfigurator.java | 15 - .../org/alfresco/traitextender/Trait.java | 12 +- .../AJExtensionsCompileTest.java | 4 +- 26 files changed, 622 insertions(+), 246 deletions(-) delete mode 100644 source/java/org/alfresco/traitextender/AJDanglingExtensionError.java delete mode 100644 source/java/org/alfresco/traitextender/AJExtensibleCompilingError.java delete mode 100644 source/java/org/alfresco/traitextender/AJExtensibleCompilingException.java delete mode 100644 source/java/org/alfresco/traitextender/ExtensionPointActivator.java delete mode 100644 source/java/org/alfresco/traitextender/SpringTraitExtenderConfigurator.java diff --git a/source/java/org/alfresco/traitextender/AJDanglingExtensionError.java b/source/java/org/alfresco/traitextender/AJDanglingExtensionError.java deleted file mode 100644 index 05540b65f0..0000000000 --- a/source/java/org/alfresco/traitextender/AJDanglingExtensionError.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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; - } - -} diff --git a/source/java/org/alfresco/traitextender/AJExtender.java b/source/java/org/alfresco/traitextender/AJExtender.java index 87ce87a2ea..195253ef49 100644 --- a/source/java/org/alfresco/traitextender/AJExtender.java +++ b/source/java/org/alfresco/traitextender/AJExtender.java @@ -42,6 +42,32 @@ import org.aspectj.lang.reflect.MethodSignature; import com.hazelcast.util.ConcurrentHashSet; +/** + * Static utility used for aspectJ extension consistency , routing and for + * maintaining thread-local extension-bypass context stack.
+ * AspectJ extension routing distinguishes between the following contexts in + * which an extended method (i.e. a method with an {@link Extend} annotation) + * can be called: + *
    + *
  1. Extend context
    + * when an extended method is called and the extension overrides the method call + *
  2. + *
  3. Local proceed context
    + * when an extension method needs to execute the original method that it has + * overridden.
  4. + *
  5. Extension bypass context
    + * when a call to an extended method needs to be completed with the extensions + * disabled for that call
  6. + *
+ *
+ * The {@link AJExtender} can check {@link ExtensionPoint} definitions for + * consistency by compiling extensible classes. The compilation process fails if + * there are inconsistencies between {@link ExtensionPoint}s and {@link Extend} + * annotated methods (egg. an annotated method can not be mapped to a method in + * the indicated extension by signature matching). + * + * @author Bogdan Horje + */ public class AJExtender { private static final Object[] SAFE_NULL_ARGS = new Object[0]; @@ -50,6 +76,9 @@ public class AJExtender private static ConcurrentHashSet oneTimeLogSet = null; + /** + * + */ private static final ThreadLocal> ajPointsLocalEnabled = new ThreadLocal>() { protected Stack initialValue() @@ -60,6 +89,9 @@ public class AJExtender }; }; + /** + * @author Bogdan Horje + */ static class ProceedingContext { final Extend extend; @@ -83,12 +115,119 @@ public class AJExtender }; }; + /** + * Implementors are aspectJ extension ignoring closures. When executing + * {@link ExtensionBypass}es using {@link AJExtender#run(ExtensionBypass)} or + * {@link AJExtender#run(ExtensionBypass, Class[])} the {@link #run()} + * method code will ignore extension overrides. + * + * @author Bogdan Horje + */ public static interface ExtensionBypass { R run() throws Throwable; } - public static class CompiledExtensible + /** + * Thrown-exception or stored error resulted compiling inconsistencies found + * during aspectJ extensible classes compilation. + * + * @see {@link AJExtender#compile(Class)} + * @author Bogdan Horje + */ + interface AJExtensibleCompilingError + { + String getShortMessage(); + } + + /** + * Thrown or stored on compiling inconsistencies found during aspectJ + * extensible classes compilation. + * + * @see {@link AJExtender#compile(Class)} + * @author Bogdan Horje + */ + static class AJExtensibleCompilingException extends Exception implements AJExtensibleCompilingError + { + + /** + * + */ + private static final long serialVersionUID = 1L; + + AJExtensibleCompilingException() + { + super(); + } + + AJExtensibleCompilingException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) + { + super(message, + cause, + enableSuppression, + writableStackTrace); + } + + AJExtensibleCompilingException(String message, Throwable cause) + { + super(message, + cause); + } + + AJExtensibleCompilingException(String message) + { + super(message); + } + + AJExtensibleCompilingException(Throwable cause) + { + super(cause); + } + + @Override + public String getShortMessage() + { + return getMessage(); + } + + } + + /** + * Signals the existence of extension methods that are not matched with + * same-signature methods through {@link Extend} annotations within + * {@link Extensible}. + * + * @author Bogdan Horje + */ + static class AJDanglingExtensionError implements AJExtensibleCompilingError + { + private Method danglingMethod; + + private Extend extendDeclaration; + + AJDanglingExtensionError(Method danglingMethod, Extend extendDeclaration) + { + super(); + this.danglingMethod = danglingMethod; + this.extendDeclaration = extendDeclaration; + } + + @Override + public String getShortMessage() + { + return "Dangling extension method " + danglingMethod + " " + extendDeclaration; + } + } + + /** + * An {@link Extensible} sub class compilation result containing all + * {@link Extend} mapped routes, not routed or dangling methods within the + * give extensible class and/or possible compilation errors. + * + * @author Bogdan Horje + */ + static class CompiledExtensible { private Class extensible; @@ -98,28 +237,28 @@ public class AJExtender private List errors = new LinkedList<>(); - public CompiledExtensible(Class extensible) + CompiledExtensible(Class extensible) { super(); this.extensible = extensible; } - public Class getExtensible() + Class getExtensible() { return this.extensible; } - public void add(AJExtensibleCompilingError error) + void add(AJExtensibleCompilingError error) { this.errors.add(error); } - public boolean hasErrors() + boolean hasErrors() { return !errors.isEmpty(); } - public String getErrorsString() + String getErrorsString() { StringBuilder builder = new StringBuilder(); @@ -132,12 +271,12 @@ public class AJExtender return builder.toString(); } - public List getErrors() + List getErrors() { return this.errors; } - public void add(ExtensionRoute route) + void add(ExtensionRoute route) { if (route.extensionMethod == null) { @@ -152,24 +291,29 @@ public class AJExtender } } - public Collection getAllNotRouted() + Collection getAllNotRouted() { return notRoutedMethods.values(); } - public int getExtendedMethodCount() + int getExtendedMethodCount() { return routedMethods.size() + notRoutedMethods.size(); } - public String getInfo() + String getInfo() { return extensible.getName() + "{ " + routedMethods.size() + " routed methods; " + notRoutedMethods.size() + " not routed methods;" + errors.size() + " errors}"; } } - public static class ExtensionRoute + /** + * Encapsulates extended-method to extension-method mapping information. + * + * @author Bogdan Horje + */ + static class ExtensionRoute { final Extend extendAnnotation; @@ -237,27 +381,48 @@ public class AJExtender } } - public static boolean areAJPointsEnabled() + /** + * @return true if aspectJ routed extensions are enabled on the + * call stack of the current thread + */ + static boolean areAJPointsEnabled() { return ajPointsLocalEnabled.get().peek(); } + /** + * Pushes a new enabled state of the aspectJ routed extensions on the + * current thread execution stack. + */ static void enableAJPoints() { ajPointsLocalEnabled.get().push(true); } + /** + * Pops the current aspectJ routed extensions enablement state from the + * current thread execution stack. + */ static void revertAJPoints() { ajPointsLocalEnabled.get().pop(); } - public static R throwableRun(AJExtender.ExtensionBypass section) throws Throwable + /** + * Exception throwing extension-bypass closure runner method.
+ * Sets up adequate call contexts to avoid exception calling and than + * delegates to the given closure. + * + * @param closure + * @return + * @throws Throwable + */ + static R throwableRun(AJExtender.ExtensionBypass closure) throws Throwable { try { AJExtender.ajPointsLocalEnabled.get().push(false); - return section.run(); + return closure.run(); } finally @@ -266,11 +431,24 @@ public class AJExtender } } - public static R run(AJExtender.ExtensionBypass section, Class[] exTypes) throws Throwable + /** + * Extension-bypass closure runner method.
+ * Sets up adequate call contexts to avoid exception calling and than + * delegates to the given closure.
+ * Only the given exTypes exceptions will be passed on to the calling + * context, all others will be wrapped as + * {@link UndeclaredThrowableException}s. + * + * @param closure + * @param exTypes + * @return + * @throws Throwable + */ + public static R run(AJExtender.ExtensionBypass closure, Class[] exTypes) throws Throwable { try { - return throwableRun(section); + return throwableRun(closure); } catch (Error | RuntimeException error) { @@ -283,7 +461,7 @@ public class AJExtender } } - public static Throwable asCheckThrowable(Throwable error, Class... checkedThrowableTypes) + static Throwable asCheckThrowable(Throwable error, Class... checkedThrowableTypes) { Class errorClass = error.getClass(); for (int i = 0; i < checkedThrowableTypes.length; i++) @@ -296,11 +474,19 @@ public class AJExtender return new UndeclaredThrowableException(error); } - public static R run(AJExtender.ExtensionBypass section) + /** + * Extension-bypass closure runner method.
+ * Sets up adequate call contexts to avoid exception calling and than + * delegates to the given closure. + * + * @param closure + * @return + */ + public static R run(AJExtender.ExtensionBypass closure) { try { - return throwableRun(section); + return throwableRun(closure); } catch (Error | RuntimeException error) { @@ -312,7 +498,13 @@ public class AJExtender } } - public static void oneTimeLiveLog(Log logger, ExtensionRoute route) + /** + * Logs each method routing path once per session. + * + * @param logger + * @param route + */ + static void oneTimeLiveLog(Log logger, ExtensionRoute route) { synchronized (AJExtender.class) { @@ -336,8 +528,13 @@ public class AJExtender } } - public static CompiledExtensible compile(Class extensible) - throws AJExtensibleCompilingException + /** + * @param extensible + * @return a compilation result containing all {@link Extend} mapped routes, + * not routed or dangling methods within the give extensible class. + * @throws AJExtensibleCompilingException + */ + static CompiledExtensible compile(Class extensible) throws AJExtensibleCompilingException { logger.info("Compiling extensible " + extensible); @@ -416,7 +613,18 @@ public class AJExtender return compiledExtensible; } - public static Object extendAroundAdvice(JoinPoint thisJoinPoint, Extensible extensible, Extend extendAnnotation, + /** + * Around advice helper that matches the advised method with its + * corresponding extension method, sets up aspectJ call contexts (egg. the + * local-proceed context) and delegates to the extension method. + * + * @param thisJoinPoint + * @param extensible + * @param extendAnnotation + * @param extension + * @return the result of the extended method + */ + static Object extendAroundAdvice(JoinPoint thisJoinPoint, Extensible extensible, Extend extendAnnotation, Object extension) { @@ -479,7 +687,12 @@ public class AJExtender } - public static boolean isLocalProceeder(Method method) + /** + * @param method + * @return true if the given method has the same signature as + * the currently aspectJ extension-overridden method + */ + static boolean isLocalProceeder(Method method) { if (!ajLocalProceedingJoinPoints.get().isEmpty()) { @@ -495,7 +708,14 @@ public class AJExtender } } - public static Object localProceed(Object[] args) throws Throwable + /** + * Calls the currently overridden method in local-proceed context - proceeds + * with the aspectJ join point saved on the current call stack.
+ * + * @param args + * @throws Throwable + */ + static Object localProceed(Object[] args) throws Throwable { ProceedingContext proceedingCotext = ajLocalProceedingJoinPoints.get().peek(); Object[] safeArgs = args == null ? SAFE_NULL_ARGS : args; diff --git a/source/java/org/alfresco/traitextender/AJExtensibleCompilingError.java b/source/java/org/alfresco/traitextender/AJExtensibleCompilingError.java deleted file mode 100644 index 65b7ea29dc..0000000000 --- a/source/java/org/alfresco/traitextender/AJExtensibleCompilingError.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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(); -} diff --git a/source/java/org/alfresco/traitextender/AJExtensibleCompilingException.java b/source/java/org/alfresco/traitextender/AJExtensibleCompilingException.java deleted file mode 100644 index b450758bd8..0000000000 --- a/source/java/org/alfresco/traitextender/AJExtensibleCompilingException.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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(); - } - -} diff --git a/source/java/org/alfresco/traitextender/Extend.java b/source/java/org/alfresco/traitextender/Extend.java index 64f425536c..808b063a27 100644 --- a/source/java/org/alfresco/traitextender/Extend.java +++ b/source/java/org/alfresco/traitextender/Extend.java @@ -16,14 +16,28 @@ * 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; +/** + * A runtime retained annotation that marks AJ-trait-extended methods of + * {@link Extensible} objects.
+ * It defines the actual circumstances in which the {@link ExtensionPoint} + * defined using {@link #extensionAPI()} and {@link #traitAPI()} has its + * extension invoked.
+ * Methods marked by this aspect are advised by an extension-routing around + * advice in {@link RouteExtensions}. Consequently the call will be routed to a + * method of an extension object having the same signature as the marked method.
+ * + * @author Bogdan Horje + */ @Retention(RetentionPolicy.RUNTIME) public @interface Extend { Class extensionAPI(); + Class traitAPI(); } diff --git a/source/java/org/alfresco/traitextender/ExtendedTrait.java b/source/java/org/alfresco/traitextender/ExtendedTrait.java index c701cffeac..7cdd685653 100644 --- a/source/java/org/alfresco/traitextender/ExtendedTrait.java +++ b/source/java/org/alfresco/traitextender/ExtendedTrait.java @@ -16,10 +16,18 @@ * 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; +/** + * Trait based extension reference holder.
+ * Keeps track of extension references for one extensible and allows the + * collection of those extensions when the extensible is collected. + * + * @author Bogdan Horje + */ public class ExtendedTrait { private ConcurrentHashMap, Object> extensions = new ConcurrentHashMap, Object>(); @@ -40,23 +48,24 @@ public class ExtendedTrait public E getExtension(Class extensionAPI) { @SuppressWarnings("unchecked") - E extension=(E) extensions.get(extensionAPI); - + E extension = (E) extensions.get(extensionAPI); + return extension; } - + public synchronized E extend(Class extensionAPI, ExtensionFactory factory) { @SuppressWarnings("unchecked") - E extension=(E) extensions.get(extensionAPI); - - if (extension==null) + E extension = (E) extensions.get(extensionAPI); + + if (extension == null) { extension = factory.createExtension(trait); - extensions.put(extensionAPI, extension); - + extensions.put(extensionAPI, + extension); + } - + return extension; } } diff --git a/source/java/org/alfresco/traitextender/Extender.java b/source/java/org/alfresco/traitextender/Extender.java index c9998533df..5afb067298 100644 --- a/source/java/org/alfresco/traitextender/Extender.java +++ b/source/java/org/alfresco/traitextender/Extender.java @@ -16,22 +16,37 @@ * 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; - - +/** + * Trait-extender central extension registry and life cycle handler.
+ * Implementors must handle: + *
    + *
  1. + * {@link ExtensionBundle} life cycle operations that start and stop bundles + * of extension points implementations at runtime.
    + * See also: {@link Extender#start(ExtensionBundle)} , + * {@link Extender#stop(ExtensionBundle)} and {@link Extender#stopAll()} ).
  2. + *
  3. The management of the extension point factory registry. At runtime + * extension point factories can be registered or unregistered. The registered + * factories will later be used for creating extensions of extensible-traits + * (see {@link Extender#getExtension(Extensible, ExtensionPoint))}.
    + * See also:{@link #register(ExtensionPoint, ExtensionFactory)} and + * {@link Extender#unregister(ExtensionPoint)}
  4. + *
  5. The creation of extension for a given extensible trait.
    + * See: {@link Extender#getExtension(Extensible, ExtensionPoint)}
  6. + *
+ * + * @author Bogdan Horje + */ public abstract class Extender { private static Extender instance; - - public static class Configuration { - private boolean enabled; - private List disbaledBundles; - - - } + /** + * @return singleton {@link ExtenderImpl} instance + */ public static synchronized Extender getInstance() { if (instance == null) @@ -41,16 +56,72 @@ public abstract class Extender return instance; } + /** + * Start life-cycle phase trigger method.
+ * Upon successful execution the bundle will have all its extension points + * registered using {@link #register(ExtensionPoint, ExtensionFactory)} and + * ready to be. + * + * @param bundle to be started + */ public abstract void start(ExtensionBundle bundle); - + + /** + * Start life-cycle phase trigger method.
+ * Upon successful execution the bundle will have all its extension points + * unregistered using {@link #unregister(ExtensionPoint)}. + * + * @param bundle to be stopped + */ public abstract void stop(ExtensionBundle bundle); - + + /** + * Stops all previously registered {@link ExtensionBundle}s. + */ public abstract void stopAll(); + /** + * Creates and returns a unique per {@link ExtensibleTrait} object or + * null if no extension-point factory is registered for the + * given {@link ExtensionPoint}.
+ * Given that {@link Extensible#getTrait(Class)} is used to obtain the + * {@link ExtendedTrait} that the returned extension is uniquely associated + * with, the uniqueness and garbage collection of the returned extension is + * dependent on how the given {@link Extensible} handles its + * {@link ExtendedTrait}s. + * + * @param anExtensible + * @param point + * @return a unique per {@link ExtensibleTrait} extension object or + * null if no extension-point factory is registered for + * the given {@link ExtensionPoint} + */ public abstract E getExtension(Extensible anExtensible, ExtensionPoint point); - + + /** + * Registers an extension-point to factory association to be used in + * extension creation. The presence of an association for a given extension + * point guarantees that, when requested, a unique extension object per + * {@link ExtensibleTrait} extension is returned by + * {@link #getExtension(Extensible, ExtensionPoint)}. + * + * @param point the extension point to be associated with the given + * extension factory during extension retrieval using + * {@link Extender#getExtension(Extensible, ExtensionPoint)} + * @param factory + */ public abstract void register(ExtensionPoint point, ExtensionFactory factory); - + + /** + * Unregisters an extension-point to factory association of the given + * extension point. The absence of an association for a given extension + * point guarantees that, when requested, a null is returned by + * {@link #getExtension(Extensible, ExtensionPoint)}.
+ * Unregistering extension points does not force the garbage collection of + * the already created extensions. + * + * @param point + */ public abstract void unregister(ExtensionPoint point); - + } diff --git a/source/java/org/alfresco/traitextender/ExtenderImpl.java b/source/java/org/alfresco/traitextender/ExtenderImpl.java index c0bed57a40..62db5496b6 100644 --- a/source/java/org/alfresco/traitextender/ExtenderImpl.java +++ b/source/java/org/alfresco/traitextender/ExtenderImpl.java @@ -27,12 +27,15 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +/** + * Standard-singleton {@link Extender} implementation. + * + * @author Bogdan Horje + */ public class ExtenderImpl extends Extender { private static Log logger = LogFactory.getLog(Extender.class); - - private List bundles = new LinkedList(); private Map, ExtensionFactory> pointFactories = new ConcurrentHashMap, ExtensionFactory>(); @@ -62,7 +65,7 @@ public class ExtenderImpl extends Extender { E extension = null; - //consistency is checked at registration time + // consistency is checked at registration time @SuppressWarnings("unchecked") ExtensionFactory factory = (ExtensionFactory) pointFactories.get(point); diff --git a/source/java/org/alfresco/traitextender/Extensible.java b/source/java/org/alfresco/traitextender/Extensible.java index d634cd6b7c..54e0673123 100644 --- a/source/java/org/alfresco/traitextender/Extensible.java +++ b/source/java/org/alfresco/traitextender/Extensible.java @@ -16,9 +16,25 @@ * 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; - +/** + * An {@link Extensible} object exposes a set of {@link Trait}s as + * {@link ExtendedTrait}s objects.
+ * An {@link ExtendedTrait} is an association between a {@link Trait} exposing + * object and several extension objects.
+ * The actual {@link Trait}s and associated extensions provided by an + * {@link Extensible} object are given by its {@link ExtensionPoint} handling + * strategy and by the current set of registered extensions (see + * {@link Extender}).
+ * The exposed {@link Trait}s can be thought of as parts of an object's + * interface that will be exposed to an extension. Upon the extension invocation + * the given trait instances will be made available to their corresponding + * extensions. + * + * @author Bogdan Horje + */ public interface Extensible { ExtendedTrait getTrait(Class traitAPI); diff --git a/source/java/org/alfresco/traitextender/ExtensionBundle.java b/source/java/org/alfresco/traitextender/ExtensionBundle.java index c1e9622bb3..6592e13725 100644 --- a/source/java/org/alfresco/traitextender/ExtensionBundle.java +++ b/source/java/org/alfresco/traitextender/ExtensionBundle.java @@ -16,14 +16,31 @@ * 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; - +/** + * Implementors are sets of extension implementations that are registered on + * specific {@link ExtensionPoint} for given {@link Extender}s. + * + * @author Bogdan Horje + */ public interface ExtensionBundle { + /** + * Sets up an registers extension factories with the give {@link Extender} + * for all extensions defined by this bundle. + * + * @param extender + */ void start(Extender extender); - + + /** + * Unregisters all defined extensions from the given {@link Extender} . + * + * @param extender + */ void stop(Extender extender); - + String getId(); } diff --git a/source/java/org/alfresco/traitextender/ExtensionFactory.java b/source/java/org/alfresco/traitextender/ExtensionFactory.java index 9726b562e4..60e0142c88 100644 --- a/source/java/org/alfresco/traitextender/ExtensionFactory.java +++ b/source/java/org/alfresco/traitextender/ExtensionFactory.java @@ -16,11 +16,27 @@ * 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; +/** + * Creates extension instances for given {@link Trait}s and + * {@link ExtensionPoint}s. + * + * @author Bogdan Horje + */ public interface ExtensionFactory { E createExtension(T trait); - + + /** + * @param point + * @return true if the given extensio-point API elements are + * compatible with the returned extension (i.e. the given extension + * API is assignable form the type of the extension created by this + * factory and the {@link Trait} accepted as aparameter in + * {@link #createExtension(Trait)} is assignable from the type of + * the given trait API). + */ boolean canCreateExtensionFor(ExtensionPoint point); } diff --git a/source/java/org/alfresco/traitextender/ExtensionPoint.java b/source/java/org/alfresco/traitextender/ExtensionPoint.java index 18ab2ccd67..226f0c9b44 100644 --- a/source/java/org/alfresco/traitextender/ExtensionPoint.java +++ b/source/java/org/alfresco/traitextender/ExtensionPoint.java @@ -16,8 +16,20 @@ * 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; +/** + * Defines a two-way interfacing mechanism between a {@link Trait} exposing + * object and an extension of that object.
+ * The extended object can call methods of the {@link #extensionAPI} which will + * be able to interact with the extended object through the {@link #traitAPI} + * interface it was paired with in the extension point. The actual circumstances + * in which the extension methods are invoked are not defined by the extension + * point. + * + * @author Bogdan Horje + */ public class ExtensionPoint { private Class extensionAPI; @@ -52,9 +64,8 @@ public class ExtensionPoint { if (obj instanceof ExtensionPoint) { - ExtensionPoint pointObj = (ExtensionPoint) obj; - return extensionAPI.equals(pointObj.extensionAPI) - && traitAPI.equals(pointObj.traitAPI); + ExtensionPoint pointObj = (ExtensionPoint) obj; + return extensionAPI.equals(pointObj.extensionAPI) && traitAPI.equals(pointObj.traitAPI); } else { diff --git a/source/java/org/alfresco/traitextender/ExtensionPointActivator.java b/source/java/org/alfresco/traitextender/ExtensionPointActivator.java deleted file mode 100644 index f4d445fc67..0000000000 --- a/source/java/org/alfresco/traitextender/ExtensionPointActivator.java +++ /dev/null @@ -1,21 +0,0 @@ - -package org.alfresco.traitextender; - -public class ExtensionPointActivator -{ - private ExtensionBundle bundle; - - private ExtensionPoint extensionPoint; - - private ExtensionFactory extensionFactory; - - public ExtensionPointActivator(ExtensionBundle bundle, ExtensionPoint extensionPoint, - ExtensionFactory extensionFactory) - { - super(); - this.bundle = bundle; - this.extensionPoint = extensionPoint; - this.extensionFactory = extensionFactory; - } - -} diff --git a/source/java/org/alfresco/traitextender/ExtensionTargetException.java b/source/java/org/alfresco/traitextender/ExtensionTargetException.java index b6ead38069..bea81d61ea 100644 --- a/source/java/org/alfresco/traitextender/ExtensionTargetException.java +++ b/source/java/org/alfresco/traitextender/ExtensionTargetException.java @@ -16,8 +16,14 @@ * 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; +/** + * Trait-extension runtime target-exception wrapper. + * + * @author Bogdan Horje + */ public class ExtensionTargetException extends RuntimeException { private static final long serialVersionUID = -502697833178766952L; @@ -30,12 +36,16 @@ public class ExtensionTargetException extends RuntimeException public ExtensionTargetException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); + super(message, + cause, + enableSuppression, + writableStackTrace); } public ExtensionTargetException(String message, Throwable cause) { - super(message, cause); + super(message, + cause); } public ExtensionTargetException(String message) diff --git a/source/java/org/alfresco/traitextender/InstanceExtension.java b/source/java/org/alfresco/traitextender/InstanceExtension.java index 2569a6eef6..fe50e1403d 100644 --- a/source/java/org/alfresco/traitextender/InstanceExtension.java +++ b/source/java/org/alfresco/traitextender/InstanceExtension.java @@ -19,6 +19,12 @@ package org.alfresco.traitextender; +/** + * Sub classes are extension API implementors that get instantiated once per + * extensible-extension point definition. + * + * @author Bogdan Horje + */ public abstract class InstanceExtension { protected T trait; diff --git a/source/java/org/alfresco/traitextender/InstanceExtensionFactory.java b/source/java/org/alfresco/traitextender/InstanceExtensionFactory.java index b155976603..28ebdfc6a1 100644 --- a/source/java/org/alfresco/traitextender/InstanceExtensionFactory.java +++ b/source/java/org/alfresco/traitextender/InstanceExtensionFactory.java @@ -21,6 +21,12 @@ package org.alfresco.traitextender; import java.lang.reflect.Constructor; +/** + * Creates extension sub classes that are extension API implementors once per + * extensible-extension point definition. + * + * @author Bogdan Horje + */ public class InstanceExtensionFactory, T extends Trait, E> implements ExtensionFactory { @@ -48,7 +54,8 @@ public class InstanceExtensionFactory, T exten { try { - // Trait RTTI will be performed anyway at Constructor#newInstance invocation time + // Trait RTTI will be performed anyway at Constructor#newInstance + // invocation time T tTrait = (T) traitObject; Constructor c = extensionClass.getConstructor(traitAPI); diff --git a/source/java/org/alfresco/traitextender/InvalidExtension.java b/source/java/org/alfresco/traitextender/InvalidExtension.java index 7d3f885d48..b35f4a8fa1 100644 --- a/source/java/org/alfresco/traitextender/InvalidExtension.java +++ b/source/java/org/alfresco/traitextender/InvalidExtension.java @@ -16,8 +16,14 @@ * 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; +/** + * Signals an invalid extension state or extension definition. + * + * @author Bogdan Horje + */ public class InvalidExtension extends RuntimeException { private static final long serialVersionUID = -7146808120353555462L; @@ -29,12 +35,16 @@ public class InvalidExtension extends RuntimeException public InvalidExtension(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); + super(message, + cause, + enableSuppression, + writableStackTrace); } public InvalidExtension(String message, Throwable cause) { - super(message, cause); + super(message, + cause); } public InvalidExtension(String message) diff --git a/source/java/org/alfresco/traitextender/RouteExtensions.java b/source/java/org/alfresco/traitextender/RouteExtensions.java index 5570f24c94..145313c6b0 100644 --- a/source/java/org/alfresco/traitextender/RouteExtensions.java +++ b/source/java/org/alfresco/traitextender/RouteExtensions.java @@ -16,6 +16,7 @@ * 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; @@ -28,13 +29,29 @@ import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; +/** + * An method override extension routing aspect.
+ * Overrides calls to methods marked by an {@link Extend} annotation with calls + * to methods having the same signature in extensions registered for the + * {@link ExtensionPoint} referred by the {@link Extend} method annotation.
+ * Overriding methods can call the overridden method using its correspondent + * {@link Trait} representation (i.e. a method having the same signature).
+ * If no extension is defined the call proceeds with the original method.
+ * The aspect uses the {@link AJExtender} static utility to for extension + * invocation and for maintaining thread-local extension-bypass contexts as not all + * calls must be overridden and calls from within the extension must be aware of + * this context (see {@link AJProxyTrait}). + * + * @author Bogdan Horje + */ @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 { + public Object intercept(ProceedingJoinPoint pjp, Extend extendAnnotation) throws Throwable + { boolean ajPointsEnabled = AJExtender.areAJPointsEnabled(); try { @@ -57,7 +74,7 @@ public class RouteExtensions point); if (extension != null) { - + return AJExtender.extendAroundAdvice(pjp, extensible, extendAnnotation, diff --git a/source/java/org/alfresco/traitextender/SingletonExtension.java b/source/java/org/alfresco/traitextender/SingletonExtension.java index b15f618893..890e0e7e64 100644 --- a/source/java/org/alfresco/traitextender/SingletonExtension.java +++ b/source/java/org/alfresco/traitextender/SingletonExtension.java @@ -19,6 +19,15 @@ package org.alfresco.traitextender; +/** + * A singleton extension API implementor. The singleton extension continues to + * exist after the extensible has been collected. The instance of this extension + * is shared among {@link Extensible}s defining extension-points that this + * extension is bound to.The {@link Trait} it requires is set at call-time on + * the local thread. + * + * @author Bogdan Horje + */ public abstract class SingletonExtension { private ThreadLocal localTrait = new ThreadLocal<>(); @@ -35,7 +44,7 @@ public abstract class SingletonExtension { return trait != null && acceptsTraitClass(trait.getClass()); } - + public boolean acceptsTraitClass(Class aTraitClass) { return traitClass.isAssignableFrom(aTraitClass); @@ -46,6 +55,10 @@ public abstract class SingletonExtension localTrait.set(trait); } + /** + * @return the {@link Trait} instance of the current execution extension + * call. + */ protected T getTrait() { return localTrait.get(); diff --git a/source/java/org/alfresco/traitextender/SingletonExtensionFactory.java b/source/java/org/alfresco/traitextender/SingletonExtensionFactory.java index 903d75f99d..06b3858317 100644 --- a/source/java/org/alfresco/traitextender/SingletonExtensionFactory.java +++ b/source/java/org/alfresco/traitextender/SingletonExtensionFactory.java @@ -27,6 +27,13 @@ import java.lang.reflect.Proxy; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +/** + * Creates singleton extension sub classes that are extension API implementors. + * The singleton extensions continue to exist after the extensible has been + * collected. + * + * @author Bogdan Horje + */ public class SingletonExtensionFactory, T extends Trait> implements ExtensionFactory { diff --git a/source/java/org/alfresco/traitextender/SpringBeanExtension.java b/source/java/org/alfresco/traitextender/SpringBeanExtension.java index 32c5695708..89eb18284f 100644 --- a/source/java/org/alfresco/traitextender/SpringBeanExtension.java +++ b/source/java/org/alfresco/traitextender/SpringBeanExtension.java @@ -16,9 +16,17 @@ * 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 extends SingletonExtension +/** + * A {@link SingletonExtension} extension-API implementor defined as a + * spring-bean.
+ * Handles also spring-bundle extension registrations. + * + * @author Bogdan Horje + */ +public abstract class SpringBeanExtension extends SingletonExtension { private SpringExtensionPoint extensionPoint; @@ -31,9 +39,10 @@ public abstract class SpringBeanExtension extends SingletonEx { this.extensionPoint = extensionPoint; } - - public void register(RegistryExtensionBundle bundle) throws InvalidExtension + + public void register(RegistryExtensionBundle bundle) throws InvalidExtension { - extensionPoint.register(bundle,this); + extensionPoint.register(bundle, + this); } } diff --git a/source/java/org/alfresco/traitextender/SpringExtensionBundle.java b/source/java/org/alfresco/traitextender/SpringExtensionBundle.java index e16049c66e..11221d0829 100644 --- a/source/java/org/alfresco/traitextender/SpringExtensionBundle.java +++ b/source/java/org/alfresco/traitextender/SpringExtensionBundle.java @@ -26,6 +26,51 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +/** + * A {@link SpringBeanExtension}s collection that get registered on the + * {@link Extender}'s registry on {@link #afterPropertiesSet()}.
+ * Works in conjunction with {@link SpringBeanExtension}s and + * {@link SpringExtensionPoint}s to define and start spring based + * {@link ExtensionBundle}s of {@link SingletonExtension}s.
+ * The spring-context XML sample bellow shows the definition of spring-bundled + * trait-extensions: + * + *
+ * {@code
+ * 
+ *  
+ *     
+ *     
+ *  
+ *  
+ *  
+ *     
+ *     
+ *  
+ * 
+ *   
+ *    
+ *  
+ * 
+ *  
+ *     
+ *  
+ * 
+ *  
+ *    
+ *    
+ *    
+ *       
+ *          
+ *          
+ *       
+ *    
+ *  
+ * }
+ * 
+ * + * @author Bogdan Horje + */ public class SpringExtensionBundle implements InitializingBean { private static Log logger = LogFactory.getLog(SpringExtensionBundle.class); @@ -38,6 +83,12 @@ public class SpringExtensionBundle implements InitializingBean private RegistryExtensionBundle extensionBundle; + /** + * @param enabled true if the current bundle should be + * registered.
+ * false if the current bundle should skip extension + * registration + */ public void setEnabled(boolean enabled) { this.enabled = enabled; @@ -53,6 +104,17 @@ public class SpringExtensionBundle implements InitializingBean this.id = id; } + /** + * Creates a {@link RegistryExtensionBundle} and registers all contained + * {@link SpringBeanExtension}s with it.
+ * When all extension have successfully registered it starts the + * {@link RegistryExtensionBundle}.
+ * The previously created {@link RegistryExtensionBundle} is stored for + * later start or {@link #stop()} operations. + * + * @see Extender#start(ExtensionBundle) + * @see Extender#stop(ExtensionBundle) + */ public synchronized void start() { @@ -81,6 +143,13 @@ public class SpringExtensionBundle implements InitializingBean Extender.getInstance().start(extensionBundle); } + /** + * Stops a previously {@link #start()} created + * {@link RegistryExtensionBundle}. + * + * @see Extender#start(ExtensionBundle) + * @see Extender#stop(ExtensionBundle) + */ public synchronized void stop() { if (extensionBundle == null) @@ -96,7 +165,7 @@ public class SpringExtensionBundle implements InitializingBean { if (this.enabled) { - logger.info("The extension bundle " + id+" is spring-enabled. Starting ... "); + logger.info("The extension bundle " + id + " is spring-enabled. Starting ... "); start(); } else diff --git a/source/java/org/alfresco/traitextender/SpringExtensionPoint.java b/source/java/org/alfresco/traitextender/SpringExtensionPoint.java index c1573b3ce8..ab07a03993 100644 --- a/source/java/org/alfresco/traitextender/SpringExtensionPoint.java +++ b/source/java/org/alfresco/traitextender/SpringExtensionPoint.java @@ -19,6 +19,15 @@ package org.alfresco.traitextender; +/** + * An {@link ExtensionPoint} spring bean wrapper with spring registering + * life-cycle management.
+ * Works in conjunction with {@link SpringBeanExtension}s and + * {@link SpringExtensionBundle}s to define spring based {@link ExtensionBundle} + * s of singleton extensions. + * + * @author Bogdan Horje + */ public class SpringExtensionPoint { private String trait; diff --git a/source/java/org/alfresco/traitextender/SpringTraitExtenderConfigurator.java b/source/java/org/alfresco/traitextender/SpringTraitExtenderConfigurator.java deleted file mode 100644 index 8a1523d909..0000000000 --- a/source/java/org/alfresco/traitextender/SpringTraitExtenderConfigurator.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.alfresco.traitextender; - -import org.springframework.beans.factory.InitializingBean; - -public class SpringTraitExtenderConfigurator implements InitializingBean -{ - - private boolean enableTraitExtender; - - @Override - public void afterPropertiesSet() throws Exception - { - } - -} diff --git a/source/java/org/alfresco/traitextender/Trait.java b/source/java/org/alfresco/traitextender/Trait.java index cca5f18151..58c1fb689a 100644 --- a/source/java/org/alfresco/traitextender/Trait.java +++ b/source/java/org/alfresco/traitextender/Trait.java @@ -16,9 +16,19 @@ * 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; +/** + * Markup interface.
+ * Subinterfaces represent distiguishing features of {@link Extensible} objects + * that are meant to be extended and exposed to the extending code.
+ * Ideally they would be the only means of interaction between extensions and + * the extended modules. + * + * @author Bogdan Horje + */ public interface Trait { - + } diff --git a/source/test-java/org/alfresco/traitextender/AJExtensionsCompileTest.java b/source/test-java/org/alfresco/traitextender/AJExtensionsCompileTest.java index 1979b2e58d..c2e5ba1b03 100644 --- a/source/test-java/org/alfresco/traitextender/AJExtensionsCompileTest.java +++ b/source/test-java/org/alfresco/traitextender/AJExtensionsCompileTest.java @@ -32,14 +32,14 @@ import org.springframework.core.type.filter.AssignableTypeFilter; public class AJExtensionsCompileTest extends TestCase { - protected void compile(Class extensible) throws AJExtensibleCompilingException + protected void compile(Class extensible) throws Exception { Set> extensiblesSet = new HashSet<>(); extensiblesSet.add(extensible); compile(extensiblesSet); } - protected void compile(Set> extensibles) throws AJExtensibleCompilingException + protected void compile(Set> extensibles) throws Exception { StringBuilder errorString = new StringBuilder(); boolean errorsFound = false;