Testing ServiceLoader in Eclipse Plugins - java

I have four Eclipse plugin projects (create a new Java Project, right-click, configure, Convert to Plugin Project) in my workspace. The first (my.runtime) contains an interface (MyFactoryInterface) and a class (MyClient) that defines a method (List<String> getAllFactoryNames()) that loads all implementations of that interface via java.util.ServiceLoader and calls a method (String getName()) on them, collecting the results and returning them in a list.
To test that class, I have a JUnit test in the second project (my.runtime.test, set up with my.runtime as Fragment-Host), checking if the name returned by a dummy implementation(MyDummy, returning "Dummy") I have in the my.runtime.test project is in the list returned by MyClient.getAllFactoryNames(). So far, it works fine.
In the third project (my.extension, with my.runtime as dependency) I have a class (MyHello) that uses the names returned by MyClient.getAllFactoryNames() to return a list of greetings ("Hello "+name).
Again, to test this, I have a project (my.extension.test, with my.extension as Fragment-Host) containing another Implementation (MyWorld, returning "World" as name) and a JUnit test case checking if "Hello World" is in the greetings returned by MyHello.getGreetings(). This test fails, as MyClient still only finds the MyDummy implementation, and not the MyWorld implementation. Both implementations are accompanied by matching entries in META-INF/services/my.runtime.MyFactoryInterface files.
I currently use the following code to load the implementations:
ServiceLoader<MyFactoryInterface> myFactoryLoader = ServiceLoader.load(MyFactoryInterface.class);
for (MyFactoryInterface myFactory : myFactoryLoader) {
I know that I can supply a ClassLoader as a second argument to ServiceLoader.load, but I have no idea how to get one that knows all plugin projects... any suggestions? Or is ServiceLoader not the right tool for this problem?

If anyone stumbles over the same problem: the combination of ServiceLoader.load(MyFactoryInterface.class, Thread.currentThread().getContextClassLoader()) in MyClient and Thread.currentThread().setContextClassLoader(MyWorld.class.getClassLoader()); in the second test did the job.

Related

NetBeans : JUnit no tests executed

So I'm getting this persistent error using netbeans. I've got a LinkedList class which I am testing via a JUnit test, which I created by clicking on LinkedList.java: Tools -> Create/Update Tests and this LinkedListTest.java class is now located in test packages.
My LinkedList.java file works correctly when tested in a file with a main method.
public class LinkedListTest {
#Test
public void testAddFirst() {
LinkedList linkedList = new LinkedList();
Country c1 = new Country("Australia");
linkedList.addFirst(c1);
assertEquals("Australias", linkedList.getValue(0)); // Should fail a test
} // default test methods beneath
All my imports check out. JUnit 5.3.1 and I had to download apiguardian1.1.0.jar from MVN repository to clear an error for:
reason: class file for org.apiguardian.api.API$Status not found
I right-click in this file and select Test File, or use Ctrl+F6, I've selected Test File from the original LinkedList file, I've even used Alt+F6 which tests the whole project. Yet I'm met with 'No tests executed.', an empty Test Results window, and no Notifications. What am I doing wrong?
Thanks for any help
Edit: I just switched from netbeans to eclipse.
You forget to extend Runner with class --
use like below with class -
public class LinkedListTest extends Runner {
}
Hope this help you.

Using external classes with dataflow

I am trying to make a custom transform class that takes in a side input and I am using PipelineTester and PAssert to try and test it, but I keep getting a no such method exception on methods I am trying to bring into the transform from other classes.
Caused by: java.lang.NoSuchMethodError:
com.org.utils.MyUtils.createMap(Ljava/lang/Iterable;)Ljava/util/Map;
at com.org.beam.MyTransform.ProcessElement(MyTransform.java:51)
I have tried using the #Autowired annotation to bring in the class like
#Autowired
private MyUtils myutils;
as well as just creating a static instance in the code like
private static MyUtils myUtils = new MyUtils();
and then calling
this.myUtils.createMap(mapThisToThat(inputCollection, this.myMap));
I have also tried making the methods static and calling them like
MyUtils.createMap(mapThisToThat(inputCollection, this.myMap));
the signature to mapThisToThat is
private Iterable<MyObject> mapThisToThat(Iterable<MyObject> objectIterator, Map<String, Integer> myMap) {
which is being passed into the createMap method which has this signature -
public Map<String, MyObject> createMap(Iterable<MyObject> inputCollection){
so it is passing in an Iterable of MyObjects correctly, but it says the method doesn't exist for some reason. does this mean beam transforms can't have external methods or am I doing something wrong?
For me in python, there are a variety of things I need to do for that to work:
https://cloud.google.com/dataflow/faq#how-do-i-handle-nameerrors
https://beam.apache.org/documentation/sdks/python-pipeline-dependencies/
For you in java, they don't have reciprocal documentation for some reason, but over here https://beam.apache.org/documentation/runners/dataflow/ they say things like this:
In some cases, such as starting a pipeline using a scheduler such as Apache AirFlow, you must have a self-contained application. You can pack a self-executing JAR by explicitly adding the following dependency on the Project section of your pom.xml, in addition to the adding existing dependency shown in the previous section.
In their examples readme https://github.com/mbrukman/apache-beam/tree/master/examples/java they say this
Alternatively, you may choose to bundle all dependencies into a single JAR and execute it outside of the Maven environment. For example, you can execute the following commands to create the bundled JAR of the examples and execute it both locally and in Cloud Platform
If you continue to browse that examples repo, there is a common folder with utils. Hopefully you can copy how they did it.

What is a good practice or design to swap algorithms at runtime?

I have several data processing algorithms that can be assembled into a pipeline to transform data. The code is split into two components: A pre-processing component that does data loading-related tasks, and a processing pipeline component.
I currently have the two parts compiled and packaged into two separate jars. The idea is that the same pre-processing jar can be shipped to all customers, but the pipeline jar can be exchanged depending on customer requirements. I would like to keep the code simple and minimize configuration, so that rules out the use of OSGi or CDI frameworks.
I've gotten some hints by looking at SLF4J's implementation. That project is split into two parts: A core API, and a bunch of implementations that wrap different logging APIs. The core API makes calls to dummy classes (which exist in the core project simply to allow compilation) that are meant to be overridden by the same classes found in the logging projects. At build time, the compiled dummy classes are deleted from the core API before packaging into jar. At run time, the core jar and a logging jar are required to be included in the class path, and the missing class files in the core jar will be filled in by the files from the logging jar. This works fine, but it feels a little hacky to me. I'm wondering if there is a better design, or if this is the best that be done without using CDI frameworks.
Sounds like the strategy software design pattern.
https://en.wikipedia.org/wiki/Strategy_pattern
Take a look at the ServiceLoader.
Example Suppose we have a service type com.example.CodecSet which is
intended to represent sets of encoder/decoder pairs for some protocol.
In this case it is an abstract class with two abstract methods:
public abstract Encoder getEncoder(String encodingName);
public abstract Decoder getDecoder(String encodingName);
Each method returns an appropriate object or null if the provider does
not support the given encoding. Typical providers support more than one
encoding. If com.example.impl.StandardCodecs is an implementation of
the CodecSet service then its jar file also contains a file named
META-INF/services/com.example.CodecSet
This file contains the single line:
com.example.impl.StandardCodecs # Standard codecs
The CodecSet class creates and saves a single service instance at
initialization:
private static ServiceLoader<CodecSet> codecSetLoader
= ServiceLoader.load(CodecSet.class);
To locate an encoder for a given encoding name it defines a static factory method which iterates
through the known and available providers, returning only when it has
located a suitable encoder or has run out of providers.
public static Encoder getEncoder(String encodingName) {
for (CodecSet cp : codecSetLoader) {
Encoder enc = cp.getEncoder(encodingName);
if (enc != null)
return enc;
}
return null;
}
A getDecoder method is defined similarly.
You already understand the gist of how to use it:
Split your project into parts (core, implementation 1, implementation 2, ...)
Ship the core API with the pre-processor
Have each implementation add the correct META-INF file to its .jar file.
The only configuration files that are necessary are the ones you package into your .jar files.
You can even have them automatically generated for you with an annotation:
package foo.bar;
import javax.annotation.processing.Processor;
#AutoService(Processor.class)
final class MyProcessor extends Processor {
// …
}
AutoService will generate the file
META-INF/services/javax.annotation.processing.Processor
in the output classes folder. The file will contain:
foo.bar.MyProcessor

Having problems while trying to execute an Acceleo module in standalone mode

I have successfully created an Acceleo module for M2T purposes and am trying to execute it from a Java program.
This is what I tried :
String[] str = {"/home/hamza/workspace/HLRedundancy/model/System1.xmi", "/home/hamza/workspace/HLRedundancy/"};
Generate.main(str);
Generate being the name of the Acceleo module I created and thus, the name of the Java class containing the Acceleo generation methods.
Here is the error I'm always getting :
Exception in thread "main" org.eclipse.acceleo.engine.AcceleoEvaluationException: The type of the first parameter of the main template named 'generateElement' is a proxy.
at org.eclipse.acceleo.engine.service.AcceleoService.doGenerate(AcceleoService.java:566)
at org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator.generate(AbstractAcceleoGenerator.java:193)
at org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator.doGenerate(AbstractAcceleoGenerator.java:158)
at HighLevelGenerator.main.Generate.doGenerate(Generate.java:250)
at HighLevelGenerator.main.Generate.main(Generate.java:160)
at Execute.main(Execute.java:11)
I've been searching for a while about this error but I have no idea about its cause.
Any idea about a solution to my problem ?
Thanks
The most common cause of this issue is failure in properly registering the metamodel and factory corresponding to your inpu model (System1.xmi).
If you look at the comments in the generated class "Generate.java", you will notice a number of places where we indicate steps to follow if running in standalone. The most important begin registerPackages where you are required to register your metamodel.
If you debug the launch down to the point where the model is loaded (place a breakpoint right after the line model = ModelUtils.load(newModelURI, modelResourceSet);), you can look at the model.eResource().getErrors() list to see whether there were errors loading your model.
You might also be interested in looking at this video describing the process (registration required) .
Check out the first line of your acceleo module,
what is the URI of the metamodel? Does it start with 'http://' ?
Maybe this can help:
Acceleo stand alone - first parameter is proxy
This issue happen when your meta model contains sub-packages and the top package not contain any class.
to solve the problem, add a Dummy class the the top package and regenerate the meta-model code. It worked fine for me.

How can I get all #Entity classes from a Persistence Unit?

Problem
I'm writing a standalone utility program which, given a jar containing a JPA-2 annotated persistence unit, needs to programmatically get a list of all my #Entity classes in a particular persistence unit.
I'd like to decide which of 2 approaches would be the way to go to get this information, and why; or if there is another better way I haven't thought of.
Solution 1
Java program puts jar on the classpath, creates persistence unit from the classes in the jar using JavaSE methodologies. Then it uses the javax.persistence classes to get the JPA Metamodel, pull back list of class tokens from that.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MY_ PERSISTENCE_UNIT");
Metamodel mm = emf.getMetamodel();
// loop these, using getJavaType() from Type sub-interface to get
// Class tokens for managed classes.
mm.getManagedTypes();
Solution 2
Program scan the directories and files inside the specified jar for persistence.xml files, then finds one with the specified persistence unit name. Then XPath the file to get the list of <class> XML elements and read the fully qualified class names from there. From names, build class tokens.
Constraints/Concerns
I'd like to go with approach 1 if possible.
This utility will NOT run inside a container, but the jar is an EJB project designed to run inside one. How will this be a problem?
The utility will have Open-EJB available on the classpath to get implementations of all the Java EE 6 classes.
Even though the EJB project is built to run on Hibernate, the utility should not be Hibernate-specific.
Are there any stumbling blocks?
In case anyone's interested, Solution 1 worked. Here's essentially what I had to do:
public MySQLSchemaGenerator() throws ClassNotFoundException {
Properties mySQLDialectProps = new Properties();
mySQLDialectProps.setProperty("javax.persistence.transactionType", "RESOURCE_LOCAL");
mySQLDialectProps.setProperty("javax.persistence.jtaDataSource", "");
final EntityManagerFactory emf = Persistence.createEntityManagerFactory("<persistence_unit_name>", mySQLDialectProps);
final Metamodel mm = emf.getMetamodel();
for (final ManagedType<?> managedType : mm.getManagedTypes()) {
managedType.getJavaType(); // this returns the java class of the #Entity object
}
}
The key was to override my transaction type and blank out the jtaDataSource which had been defined in my persistence.xml. Turns out everything else was unnecessary.
If Your jar is well-formed (persistence.xml at the right place - in the META-INF folder), then all looks fine.
It is not necessary to run your utility inside a container, JPA is not a part of JavaEE specs.

Categories

Resources