@Override public Class<?> run() throws ClassNotFoundException { return bundle.loadClass(className); } });
@Override public Class<?> run() throws ClassNotFoundException { return bundle.loadClass(className); } });
/** {@inheritDoc} */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { return bundle.loadClass(name); }
Class<?> loadClass(Bundle bundle, String classFilePath) { String className = classFilePath.replaceFirst("^/", "").replace('/', '.').replaceFirst(".class$", ""); try { return bundle.loadClass(className); } catch (Throwable e) { errors.add(String.format("Class [%s] could not be loaded. Message: [%s].", className, e.getMessage())); } return null; }
@Override public Class<?> loadClass(String className) { try { return context.getBundle().loadClass(className); } catch (ClassNotFoundException e) { throw new MappingException(e); } }
@Test public void shouldRegisterServiceWithBothPluginIDAndExtensionTypeAsProperties() throws Exception { setupClassesInBundle("PublicGoExtensionClassWhichWillLoadSuccessfullyAndProvideAValidIdentifier.class"); when(bundle.loadClass("PublicGoExtensionClassWhichWillLoadSuccessfullyAndProvideAValidIdentifier")).thenReturn((Class) PublicGoExtensionClassWhichWillLoadSuccessfullyAndProvideAValidIdentifier.class); Hashtable<String, String> expectedPropertiesUponRegistration = new Hashtable<>(); expectedPropertiesUponRegistration.put(Constants.BUNDLE_SYMBOLICNAME, PLUGIN_ID); expectedPropertiesUponRegistration.put(Constants.BUNDLE_CATEGORY, "test-extension"); activator.start(context); assertThat(activator.hasErrors(), is(false)); verify(context).registerService(eq(GoPlugin.class), any(GoPlugin.class), eq(expectedPropertiesUponRegistration)); }
@Test public void shouldFailToRegisterServiceWhenExtensionTypeCannotBeSuccessfullyRetrieved() throws Exception { setupClassesInBundle("PublicGoExtensionClassWhichWillLoadSuccessfullyButThrowWhenAskedForPluginIdentifier.class"); when(bundle.loadClass("PublicGoExtensionClassWhichWillLoadSuccessfullyButThrowWhenAskedForPluginIdentifier")).thenReturn((Class) PublicGoExtensionClassWhichWillLoadSuccessfullyButThrowWhenAskedForPluginIdentifier.class); activator.start(context); assertThat(activator.hasErrors(), is(true)); verifyErrorReportedContains("Unable to find extension type from plugin identifier in class com.thoughtworks.go.plugin.activation.PublicGoExtensionClassWhichWillLoadSuccessfullyButThrowWhenAskedForPluginIdentifier"); verify(context, times(0)).registerService(eq(GoPlugin.class), any(GoPlugin.class), any()); }
private void assertLoadUnloadInvocationCount(Class<?> testExtensionClass, int invocationCount) throws Exception { String simpleNameOfTestExtensionClass = testExtensionClass.getSimpleName(); setupClassesInBundle(simpleNameOfTestExtensionClass + ".class"); when(bundle.loadClass(contains(simpleNameOfTestExtensionClass))).thenReturn((Class) testExtensionClass); activator.start(context); assertThat(testExtensionClass.getField("loadInvoked").getInt(null), is(invocationCount)); activator.stop(context); assertThat(testExtensionClass.getField("unLoadInvoked").getInt(null), is(invocationCount)); }
@Test public void shouldReportMultipleClassLoadErrorsToThePluginHealthService() throws Exception { setupClassesInBundle("SomeClass.class", "SomeOtherClass.class"); when(bundle.loadClass(anyString())).thenThrow(new ClassNotFoundException("Ouch! Failed")); activator.start(context); verifyErrorsReported("Class [SomeClass] could not be loaded. Message: [Ouch! Failed].", "Class [SomeOtherClass] could not be loaded. Message: [Ouch! Failed]." , NO_EXT_ERR_MSG); }
@Test public void shouldReportAClassLoadErrorToThePluginHealthService() throws Exception { setupClassesInBundle("SomeClass.class"); when(bundle.loadClass(anyString())).thenThrow(new ClassNotFoundException("Ouch! Failed")); activator.start(context); verifyErrorsReported("Class [SomeClass] could not be loaded. Message: [Ouch! Failed].", NO_EXT_ERR_MSG); }
@Test public void loggerShouldBeAvailableToBeUsedInStaticBlocksAndConstructorAndLoadUnloadMethodsOfPluginExtensionClasses() throws Exception { setupClassesInBundle("PublicGoExtensionClassWhichLogsInAStaticBlock.class"); when(bundle.loadClass(contains("PublicGoExtensionClassWhichLogsInAStaticBlock"))).thenReturn((Class) PublicGoExtensionClassWhichLogsInAStaticBlock.class); activator.start(context); activator.stop(context); verify(loggingService).info(PLUGIN_ID, PublicGoExtensionClassWhichLogsInAStaticBlock.class.getName(), "HELLO from static block in PublicGoExtensionClassWhichLogsInAStaticBlock"); verify(loggingService).info(PLUGIN_ID, PublicGoExtensionClassWhichLogsInAStaticBlock.class.getName(), "HELLO from constructor in PublicGoExtensionClassWhichLogsInAStaticBlock"); verify(loggingService).info(PLUGIN_ID, PublicGoExtensionClassWhichLogsInAStaticBlock.class.getName(), "HELLO from load in PublicGoExtensionClassWhichLogsInAStaticBlock"); verify(loggingService).info(PLUGIN_ID, PublicGoExtensionClassWhichLogsInAStaticBlock.class.getName(), "HELLO from unload in PublicGoExtensionClassWhichLogsInAStaticBlock"); }
@Test public void shouldReportAClassWhichIsAnnotatedAsAnExtensionIfItFailsDuringConstruction() throws Exception { setupClassesInBundle("PublicGoExtensionClassWhichThrowsAnExceptionInItsConstructor.class"); when(bundle.loadClass(contains("PublicGoExtensionClassWhichThrowsAnExceptionInItsConstructor"))).thenReturn((Class) PublicGoExtensionClassWhichThrowsAnExceptionInItsConstructor.class); activator.start(context); verifyErrorsReported( format("Class [PublicGoExtensionClassWhichThrowsAnExceptionInItsConstructor] is annotated with @Extension but cannot be constructed. Reason: java.lang.RuntimeException: %s.", CONSTRUCTOR_FAIL_MSG), NO_EXT_ERR_MSG); }
@Test public void shouldNotReportAClassWhichIsNotAnnotatedAsAnExtensionEvenIfItIsNotPublic() throws Exception { setupClassesInBundle("NonPublicClassWhichIsNotAGoExtension.class"); when(bundle.loadClass(contains("NonPublicClassWhichIsNotAGoExtension"))).thenReturn((Class) NonPublicClassWhichIsNotAGoExtension.class); activator.start(context); verifyErrorsReported(NO_EXT_ERR_MSG); }
@Test public void shouldReportAClassWhichIsAnnotatedAsAnExtensionIfItIsAbstract() throws Exception { setupClassesInBundle("PublicAbstractGoExtensionClass.class"); when(bundle.loadClass(contains("PublicAbstractGoExtensionClass"))).thenReturn((Class) PublicAbstractGoExtensionClass.class); activator.start(context); verifyErrorsReported("Class [PublicAbstractGoExtensionClass] is annotated with @Extension but is abstract.", NO_EXT_ERR_MSG); }
@Test public void shouldReportAClassWhichIsAnnotatedAsAnExtensionIfItIsNotInstantiable() throws Exception { setupClassesInBundle("PublicGoExtensionClassWhichDoesNotHaveADefaultConstructor.class"); when(bundle.loadClass(contains("PublicGoExtensionClassWhichDoesNotHaveADefaultConstructor"))).thenReturn((Class) PublicGoExtensionClassWhichDoesNotHaveADefaultConstructor.class); activator.start(context); verifyErrorsReported("Class [PublicGoExtensionClassWhichDoesNotHaveADefaultConstructor] is annotated with @Extension but cannot be constructed. " + "Make sure it and all of its parent classes have a default constructor.", NO_EXT_ERR_MSG); }
@Test public void shouldReportAClassWhichIsAnnotatedAsAnExtensionIfItIsNotPublic() throws Exception { setupClassesInBundle("NonPublicGoExtensionClass.class"); when(bundle.loadClass(contains("NonPublicGoExtensionClass"))).thenReturn((Class) NonPublicGoExtensionClass.class); activator.start(context); verifyErrorsReported("Class [NonPublicGoExtensionClass] is annotated with @Extension but is not public.", NO_EXT_ERR_MSG); }
@Test public void shouldInvokeMethodWithLoadUnloadAnnotationAtPluginStart() throws Exception { setupClassesInBundle("GoExtensionWithLoadUnloadAnnotation.class"); when(bundle.loadClass(contains("GoExtensionWithLoadUnloadAnnotation"))).thenReturn((Class) GoExtensionWithLoadUnloadAnnotation.class); activator.start(context); assertThat(GoExtensionWithLoadUnloadAnnotation.loadInvoked, is(1)); activator.stop(context); assertThat(GoExtensionWithLoadUnloadAnnotation.unLoadInvoked, is(1)); }
@Test public void shouldHandleExceptionGeneratedByLoadMethodAtPluginStart() throws Exception { setupClassesInBundle("GoExtensionWithLoadAnnotationMethodThrowingException.class"); when(bundle.loadClass(contains("GoExtensionWithLoadAnnotationMethodThrowingException"))).thenReturn((Class) GoExtensionWithLoadAnnotationMethodThrowingException.class); activator.start(context); assertThat(activator.hasErrors(), is(true)); verifyErrorsReported("Class [GoExtensionWithLoadAnnotationMethodThrowingException] is annotated with @Extension but cannot be registered. " + "Reason: java.io.IOException: Load Dummy Checked Exception."); }
@Test public void shouldHandleExceptionGeneratedByUnLoadMethodAtPluginStop() throws Exception { setupClassesInBundle("GoExtensionWithUnloadAnnotationMethodThrowingException.class"); when(bundle.loadClass(contains("GoExtensionWithUnloadAnnotationMethodThrowingException"))).thenReturn((Class) GoExtensionWithUnloadAnnotationMethodThrowingException.class); activator.start(context); assertThat(activator.hasErrors(), is(false)); activator.stop(context); assertThat(activator.hasErrors(), is(true)); verifyErrorsReported("Invocation of unload method [public int com.thoughtworks.go.plugin.activation.GoExtensionWithUnloadAnnotationMethodThrowingException" + ".throwExceptionAgain(com.thoughtworks.go.plugin.api.info.PluginContext) " + "throws java.io.IOException]. " + "Reason: java.io.IOException: Unload Dummy Checked Exception."); }
@Test public void shouldGenerateExceptionWhenThereAreMoreThanOneLoadAnnotationsAtPluginStart() throws Exception { String expectedErrorMessageWithMethodsWithIncreasingOrder = "Class [GoExtensionWithMultipleLoadUnloadAnnotation] is annotated with @Extension will not be registered. " + "Reason: java.lang.RuntimeException: More than one method with @Load annotation not allowed. " + "Methods Found: [public void com.thoughtworks.go.plugin.activation.GoExtensionWithMultipleLoadUnloadAnnotation.setupData1(com.thoughtworks.go.plugin.api.info.PluginContext), " + "public void com.thoughtworks.go.plugin.activation.GoExtensionWithMultipleLoadUnloadAnnotation.setupData2(com.thoughtworks.go.plugin.api.info.PluginContext)]."; String expectedErrorMessageWithMethodsWithDecreasingOrder = "Class [GoExtensionWithMultipleLoadUnloadAnnotation] is annotated with @Extension will not be registered. " + "Reason: java.lang.RuntimeException: More than one method with @Load annotation not allowed. " + "Methods Found: [public void com.thoughtworks.go.plugin.activation.GoExtensionWithMultipleLoadUnloadAnnotation.setupData2(com.thoughtworks.go.plugin.api.info.PluginContext), " + "public void com.thoughtworks.go.plugin.activation.GoExtensionWithMultipleLoadUnloadAnnotation.setupData1(com.thoughtworks.go.plugin.api.info.PluginContext)]."; setupClassesInBundle("GoExtensionWithMultipleLoadUnloadAnnotation.class"); when(bundle.loadClass(contains("GoExtensionWithMultipleLoadUnloadAnnotation"))).thenReturn((Class) GoExtensionWithMultipleLoadUnloadAnnotation.class); activator.start(context); assertThat(activator.hasErrors(), is(true)); verifyThatOneOfTheErrorMessagesIsPresent(expectedErrorMessageWithMethodsWithIncreasingOrder, expectedErrorMessageWithMethodsWithDecreasingOrder); activator.stop(context); verifyThatOneOfTheErrorMessagesIsPresent(expectedErrorMessageWithMethodsWithIncreasingOrder, expectedErrorMessageWithMethodsWithDecreasingOrder); }