I am using Apache Velocity in my Eclipse plugin. The corresponding entry has been added to MANIFEST.MF:
Require-Bundle: org.apache.velocity;bundle-version="1.5.0"
A Velocity-instance is initialized as follows:
VelocityEngine ve = new VelocityEngine();
ve.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, NullLogChute.class.getName());
ve.init();
I build the JAR with my plugin and test it on several machines. On 2 PCs this works fine but on the third one I get an exception:
java.lang.Exception: The specified class for ResourceManager (org.apache.velocity.runtime.resource.ResourceManagerImpl) does not implement org.apache.velocity.runtime.resource.ResourceManager; Velocity is not initialized correctly.
at org.apache.velocity.runtime.RuntimeInstance.initializeResourceManager(RuntimeInstance.java:589)
at org.apache.velocity.runtime.RuntimeInstance.init(RuntimeInstance.java:241)
at org.apache.velocity.runtime.RuntimeSingleton.init(RuntimeSingleton.java:113)
at org.apache.velocity.app.Velocity.init(Velocity.java:83)
It seems I get this exception because Velocity isn't OGSi-friendly. Can anybody give me a workaround?
I was able to solve similar issue using this : https://wiki.eclipse.org/FAQ_How_do_I_use_the_context_class_loader_in_Eclipse%3F
Basically you set the current Thread class loader to the one of your Eclipse/OSGi plug-in (or a class of your plug-in).
Resulting sample code below works fine with both plain java execution (Run as Java Application) and called through plugin API after exporting the Eclipse product.
public class Printer {
#Override
public void myPluginApiOverride() {
Printer.main(new String[0]);
}
public static void main(final String[] args) {
// without the following class loader initialization, I get the
// following exception when running as Eclipse plugin:
// org.apache.velocity.exception.VelocityException: The specified
// class for ResourceManager
// (org.apache.velocity.runtime.resource.ResourceManagerImpl) does not
// implement org.apache.velocity.runtime.resource.ResourceManager;
// Velocity is not initialized correctly.
final ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(Printer.class.getClassLoader());
// sample velocity call
final Writer writer = new PrintWriter(new OutputStreamWriter(System.out));
final VelocityContext context = new VelocityContext();
context.put("name", "World");
try {
Velocity.evaluate(context, writer, "org.apache.velocity", "Hello $name !");
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
// set back default class loader
Thread.currentThread().setContextClassLoader(oldContextClassLoader);
}
}
Related
I am trying to invoke a dynamically created Junit test class using the code below
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
URL classUrl = javaClass.getParent().toFile().toURI().toURL();
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { classUrl });
Class<?> clazz = Class.forName(fileName, true, classLoader);
Object obj = clazz.newInstance();
context.getLogger().log("Test Class Loader==>"+obj.getClass().getClassLoader()+"\n");
JUnitCore junit = new JUnitCore();
context.getLogger().log("JUnitCore Class Loader==>"+junit.getClass().getClassLoader()+"\n");
junit.addListener(new TextListener(new PrintStream(outputStream)));
Result result = junit.run(clazz);
return outputStream.toString();
Dynamically created test file
public class SampleJavaFileTest {
String EXPECTED_OUTPUT_STRING="r3plac3";
#Test
public void testReplaceString() {
SampleJavaFile sample = new SampleJavaFile();
String outputString = sample.replaceString("replace","e","3");
Assert.assertEquals(EXPECTED_OUTPUT_STRING, outputString);
}
}
But I get the error as
There was 1 failure:
1) initializationError(JUnitTest)
org.junit.runners.model.InvalidTestClassError: Invalid test class 'JUnitTest':
1. No runnable methods
at org.junit.runners.ParentRunner.validate(ParentRunner.java:511)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:101)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:84)
at org.junit.runners.JUnit4.<init>(JUnit4.java:23)
at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder
.runnerForClass(AllDefaultPossibilitiesBuilder.java:37)
at org.junit.runner.Computer.getRunner(Computer.java:50)
at org.junit.runner.Computer$1.runnerForClass(Computer.java:31)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:125)
at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:111)
at org.junit.runners.Suite.<init>(Suite.java:81)
at org.junit.runner.Computer$2.<init>(Computer.java:33)
I tried printing the class loaders of the dynamically created class and the JUnitCore class the results are
Test Class Loader==>java.net.FactoryURLClassLoader#86be70a
JUnitCore Class Loader==>java.net.URLClassLoader#49c2faae
Upon going through various posts the answers provided are to use custom class loaders to resolve this issue. Can you assist on how to create a custom class loader to resolve this issue?
If not custom class loaders , how else can this be resolved?
Thanks!
This might be class loader related issue, try to create URLClassLoader by using constructor and pass class loader of other test class (or just junit class) as is parent class loader, to ensure that JUnit classes are always loaded by the same class loader. And double check that this is right annotation, with right package.
public URLClassLoader(URL[] urls, ClassLoader parent)
so
new URLClassLoader(urlOfToClass, SomeTestOrJUnitClass.class.getClassLoader())
https://docs.oracle.com/javase/7/docs/api/java/net/URLClassLoader.html#URLClassLoader(java.net.URL[],%20java.lang.ClassLoader)
this exception is generated in this junit block of code
List<Method> methods = testClass.getAnnotatedMethods(Test.class);
if (methods.size() == 0) {
errors.add(new Exception("No runnable methods"));
}
So, I'd recommend to double check, that you definitely have annotation #Test for method, and it is really org.junit.Test and this annotation available in runtime.
You can check this by taking klass.getDeclaredMethod("testReplaceString") and printing all annotations from it.
If it doesn't help, then, you can debug Junit library, put breakpoint to exception (please note, this exceptions generated not in the same place, where throwed) and check conditions
BTW, what version of junit do you use?
EDITED:
I've checked your code, I've created a new project in IDEA, added junit 4.13-rc-1 to dependencies and created two files.
public class SampleJavaFileTest {
String EXPECTED_OUTPUT_STRING="r3plac3";
#Test
public void testReplaceString() {
Assert.assertEquals(EXPECTED_OUTPUT_STRING, "r3plac3");
}
}
and another class
public class ClassLoadDynamically {
public static void main(String[] args) throws Exception {
final File fileForClass = new File(SampleJavaFileTest.class.getProtectionDomain().getCodeSource().getLocation().getPath());
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { fileForClass.toURI().toURL() });
Class<?> clazz = Class.forName("SampleJavaFileTest", true, classLoader);
Method testReplaceString = clazz.getDeclaredMethod("testReplaceString");
System.out.println("Get declared methods==>"+ testReplaceString);
System.out.println("Get annotation => "+ testReplaceString.getAnnotation(org.junit.Test.class));
JUnitCore junit = new JUnitCore();
Result result = junit.run(clazz);
System.out.println(result.wasSuccessful());
}
}
I've checked your code, it works in this way. Please check, how do you generate your code dynamically, looks like the the issue in wrong bytecode generation, double check, how do you set annotations to the method.
However, I'm not sure, about your environment configuration on lambda. Anyway, I'd recommend to make your code run locally
I currently try to run java code in Maxmsp using a mxj object, and I want to load some classes inside of the code.
But I always get the errors, although the code runs properly in eclipse.
What is the problem?
This is my code.
If I bang in Maxmsp, call() will be called.
package Load;
import com.cycling74.max.*;
public class Loaded extends MaxObject{
public static void main(String[] args) {
//This works properly in eclipse
call();
}
public void bang() {
//This should work in Maxmsp, but get errors
call();
}
public static void call() {
try {
//this is just a example
//I want to load some classes which locate the same directory as this class
Thread.currentThread().getContextClassLoader().loadClass("Load.Loaded");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
And this is the error message:
java.lang.ClassNotFoundException: Load.Loaded
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at Load.Loaded.call(Loaded.java:21)
at Load.Loaded.bang(Loaded.java:16)
MXJ System class path is:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/commons-codec-1.11.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/core.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/gluegen-rt-natives-macosx-universal.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/gluegen-rt.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/jitter.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/jode-1.1.2-pre-embedded.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/jogl-all-natives-macosx-universal.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/jogl-all.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/max.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/sadamLib.jar
MXJ Classloader CLASSPATH is:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/classes/
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/
/Users/MyName/Documents/ecllipse-workspace/009_Processing/bin
Loaded.class is in /Users/MyName/Documents/ecllipse-workspace/009_Processing/bin
You need to include any of your dependencies on the classpath:
java -cp "path/to/maxmsp.jar;path/to/dependency2.jar;path/to/your.jar" classpath.of.your.Main
If you are just running directly from a classfile and haven't JARred your project then you can omit the path/to/your.jar and just run from the same directory with the classpath of your Main.
The above is for running java from command line.
Since Max is what is running and what's taking control of the classloading im guessing that sun.misc.Launcher$AppClassLoader is not working. Try debugging and see what it's doing. Also maybe try to find a way to use the Max classloader instead of the Java AppClassLoader.
The problem was what Max cannot load class properly.
So I created class loader method.
public static ClassLoader createClassLoader(String dirname) throws java.io.IOException {
java.net.URL[] url = new java.net.URL[1];
java.io.File file;
if (dirname.endsWith("/")) {
file = new java.io.File(dirname);
}
else {
file = new java.io.File(dirname + "/");
}
url[0]= file.toURI().toURL();
ClassLoader parent = ClassLoader.getSystemClassLoader();
java.net.URLClassLoader loader = new java.net.URLClassLoader(url, parent);
return loader
}
And call
ClassLoader loader = createClassLoader("ClassPath");
Class<?> c = Class.forName("Classname", true, loader);
I'm working with a Maven project that has three modules:
Database
Module that contains a JBehave Story (Story .java, .story, and steps .java file)
Another module that contains a JBehave Story (Story .java, .story, and steps .java file)
Both of the modules that contain a JBehave Story have the same type of .java file that runs the .story file and steps. Below is the .java file both modules have (but have different names for test purposes):
public class FirstStories extends ConfigurableEmbedder {
private SqlDataSourceProvider dataSourceProvider = new SqlDataSourceProvider();
private final CrossReference xref = new CrossReference();
private Context context = new Context();
private Format contextFormat = new ContextOutput(context);
private ContextView contextView = new JFrameContextView().sized(640, 120);
private ContextStepMonitor contextStepMonitor = new ContextStepMonitor(context, contextView, xref.getStepMonitor());
public FirstStories() {
System.setProperty("jbehave.test", "true");
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(false)
.doIgnoreFailureInView(true).doVerboseFailures(true).useThreads(1).useStoryTimeouts("5m");
configuredEmbedder().useEmbedderControls(new PropertyBasedEmbedderControls());
}
#Test
#Override
public void run() throws Throwable {
Embedder embedder = configuredEmbedder();
try {
embedder.runStoriesAsPaths(storyPaths());
} finally {
embedder.generateCrossReference();
}
}
#Override
public Configuration configuration() {
Properties viewResources = new Properties();
viewResources.put("decorateNonHtml", "true");
viewResources.put("reports", "ftl/jbehave-reports-with-totals.ftl");
return new MostUsefulConfiguration()
.useStoryReporterBuilder(
new StoryReporterBuilder()
.withDefaultFormats()//.withViewResources(viewResources)
.withFormats(contextFormat, CONSOLE, TXT, HTML_TEMPLATE, XML_TEMPLATE).withFailureTrace(true)
.withFailureTraceCompression(true).withCrossReference(xref))
.useStepMonitor(contextStepMonitor);
}
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new Steps(dataSourceProvider));
}
private List<String> storyPaths() {
String filter = System.getProperty("story.filter", "**/*.story");
return new StoryFinder().findPaths(codeLocationFromClass(this.getClass()), filter, "**/failing_before*.story");
}
}
The .story file is very straightfoward and only has one scenario:
Meta:
Narrative:
As a user
I want to perform an action
So that I can achieve a business goal
Scenario: Test scenario
Given nothing
When I do nothing
Then nothing happens
The steps file only contains one no-op method just to get everything working properly.
When running both JBehave tests via maven, the first story will run just fine. However, when starting up the second story, the following message appears, and the test shortly fails (I can run the second story on its own without issues, only when it runs after the first story):
WARNING: Failed to load the sqljdbc_auth.dll cause : Native Library C:\Windows\System32\sqljdbc_auth.dll already loaded in another classloader
java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
Is there something I am forgetting to do during my story's run() method to make sure everything is properly destroyed after the story is finished running, so the next story can run correctly without problems?
I'm working on RCP aplicattion, that works on Eclipse 4 platform(Luna). I neeed to find out how to get instance that implement tracing inside my Application. I found out the following ways
-
Using ILog interface, that can be get via Platform.getLog call. ILog has good point. It prints to .log file that located in .metadata, but
it get IStatus object as parameter. So for logging each line to log I have to created new instance of Status object. And it cannot put automatically information about caller like class name etc.(like Log4j, LogBack)
I found interface DebugTrace that provide good functionality for traicing. It can be obtained via DebugOptions inerface(DebugOptions.newDebugTrace()). To my regret I could not find appropriated way for getting instance of DebugOptions
To use DebugTrace, add this to the plugin Activator:
private DebugTrace tracer = null;
public static DebugTrace getTrace()
{
return plugin.tracer;
}
public void start(final BundleContext context) throws Exception
{
...
final Hashtable<String, String> properties = new Hashtable<String, String>(4);
properties.put(DebugOptions.LISTENER_SYMBOLICNAME, "org.eclipse.ui.trace"); //$NON-NLS-1$
context.registerService(
DebugOptionsListener.class.getName(),
new DebugOptionsListener()
{
#Override
public void optionsChanged(DebugOptions options)
{
tracer = options.newDebugTrace(context.getBundle().getSymbolicName());
}
}, properties);
You will need to add a .options file to the plugin project which will contain your logging options:
# Editor-related tracing
com.acme.atf.app/trace/editor=false
#Start-up tracing
com.acme.atf.app/trace/startup=true
org.eclipse.core.jobs/jobs=true
org.eclipse.core.jobs/jobs/beginend=true
org.eclipse.core.jobs/jobs/errorondeadlock=true
Hope this helps...
I have just gotten started with an Eclipse RCP application, it is basically just one of the provided "hello world" samples.
When the application boots up, I would like to look at my command-line parameters and start some services according to them. I can get the command-line parameters in IApplication.start:
public Object start(IApplicationContext context) {
String[] argv = (String[])
context.getArguments().get(IApplicationContext.APPLICATION_ARGS)));
}
But how do I get the BundleContext, so that I can register services? It does not seem to be in the IApplicationContext.
Just came across this doing a web search, and thought I'd promote the new standard OSGi R4.2 way (as provided by Equinox shipped with Eclipse 3.5). If you don't have an activator, and don't want to create one just to cache the bundle context, you can use FrameworkUtil.getBundle. Modifying the previous example:
import org.osgi.framework.FrameworkUtil;
public class ExportClassDigestApplication implements IApplication {
public Object start(IApplicationContext context) throws Exception {
context.applicationRunning();
BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
.getBundleContext();
}
}
Tricky internal way:
InternalPlatform.getDefault().getBundleContext()
could do it.
You will find an example in this class
public class ExportClassDigestApplication implements IApplication {
public Object start(IApplicationContext context) throws Exception {
context.applicationRunning();
List<ExtensionBean> extensionBeans = ImpCoreUtil.loadExtensionBeans("com.xab.core.containerlaunchers");
for (ExtensionBean bean : extensionBeans) {
ILauncher launcher = (ILauncher) bean.getInstance();
launcher.start();
}
ClassFilter classFilter = new ClassFilter() {
public boolean isClassAccepted(Class clz) {
return true;
}
};
PrintWriter writer = new PrintWriter( new File( "C:/classes.csv"));
Bundle[] bundles = InternalPlatform.getDefault().getBundleContext().getBundles();
Proper way:
Every plug-in has access to its own bundle context.
Just make sure your plug-in class overrides the start(BundleContext) method. You can then save it to a place classes in your plug-in can easily access
Note the bundle context provided to a plug-in is specific to it and should never be shared with other plug-ins.