7

Quick background: I am working on developing an interface that will be implemented by myself and other developers. This interface will allow users to "plugin" new functional code into a system for new use. This new code will be called from an already running server/application. (TLDR: I need to develop the ability for plugins to be installed into my application on the fly)

All the work I have done with interfaces so far have been for internal coding purposes, not to be exposed outward. The only way I can think of to allow users to plugin new code implementing interfaces, would be for the user to somehow hook a JAR file in containing the implementing class and somehow defining its class signature for call. This seems like something that has been done before, I just have never been exposed into the coding side of it.

Is there a framework I could use to allow this plugin of new Java code during server/application runtime? I have used APIs before, but in more of the web service exposing sense where you are consuming a service and not "implementing" some core interface.

For reference I am using a Java backend, with Spring for the main application.

Walls
  • 233
  • 3
  • 10
  • 2
    Looks like a duplicate of http://stackoverflow.com/questions/25449/how-to-create-a-pluginable-java-program – Esben Skov Pedersen Mar 28 '16 at 13:50
  • 1
    @EsbenSkovPedersen that led me into a rabbit hole which eventually gave me everything I needed and then some. Thank you very much. (-admins: Duplicate, close is fine by me) – Walls Mar 28 '16 at 22:07
  • @Walls duplicates must be on the same site. Just because SO has a similar question does not mean this one is a duplicate of it. You could summarize what you found in an answer to this question and link to the SO question, since answers are a bit more permanent than comments. –  Mar 30 '16 at 05:13

2 Answers2

6

After looking into a related post on Stack Overflow, I found there to be a variety of different tools at my disposal to do "plugin" style development.

First, I was close with "API" but the correct solution is an "SPI" or Service Provider Interface. I found a very good post describing the difference on Stack Overflow. To summarize: API is a set of classes/interfaces/methods that you CALL and USE to achieve a goal. Compared to a SPI which is a set of classes/interfaces/methods that you EXTEND and IMPLEMENT to achieve a goal.

There are many ways I am still looking through to find the right solution for me, but it seems that using Java's ClassLoader or URLClassLoader will be the way to go. Oracle provides a great tutorial on how to implement this here.

There are many tools out there that can provide support for this such as Apache Aries and OSGi.

Walls
  • 233
  • 3
  • 10
-1

Have a look at FlexiCore, an open-source framework that brings modularity to spring boot utilizing plugins(jars) loaded at runtime See wizzdi and FlexiCore. for example FlexiCore allows you to create a project ( compiled into a seperate jar from your main application) that contains a spring bean as follows:

@Component
@Extension
public class HelloWorldService implements ServicePlugin{

 public String hello() {
  return "Hello World!";
 }

}

it will be automatically be loaded once placed inside the designated plugins folder, it basically allows a full support for most(all) of spring boot features , so for example you can add a RestController bean to your jar as well , FlexiCore will automatically load that bean allowing you to call the controller as if it was in your main application jar:

@RestController
@Extension
public class TestEntityController implements Plugin {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @Autowired
    private TestEntityService testEntityService;

    @PostMapping("/createTestEntity")
    public TestEntity createTestEntity(@RequestParam(name="name", required=false, defaultValue="Stranger") String name) {
        return testEntityService.createTestEntity(name);
    }

    @GetMapping("{id}")
    public TestEntity getTestEntity(@PathVariable("id")String id) {
        return testEntityService.getTestEntity(id);
    }

}

Disclaimer: I am the CTO of wizzdi, the company powering FlexiCore.