<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gab</title>
    <description>The latest articles on DEV Community by Gab (@r4venw).</description>
    <link>https://dev.to/r4venw</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F62988%2F8a6de827-b41f-41cc-ad37-65628fea336a.png</url>
      <title>DEV Community: Gab</title>
      <link>https://dev.to/r4venw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/r4venw"/>
    <language>en</language>
    <item>
      <title>Building an OSGi-like Plugin System in Java</title>
      <dc:creator>Gab</dc:creator>
      <pubDate>Sun, 05 Jan 2020 15:09:14 +0000</pubDate>
      <link>https://dev.to/r4venw/building-an-osgi-like-plugin-system-in-java-2gie</link>
      <guid>https://dev.to/r4venw/building-an-osgi-like-plugin-system-in-java-2gie</guid>
      <description>&lt;p&gt;If you are not familiar with what OSGi is, you can find additional details &lt;a href="https://en.wikipedia.org/wiki/OSGi" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://www.osgi.org/developer/what-is-osgi/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The complete project can be found on github here: &lt;a href="https://github.com/Larisho/osgi" rel="noopener noreferrer"&gt;https://github.com/Larisho/osgi&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Spec
&lt;/h1&gt;

&lt;p&gt;By the end of this tutorial, we will have an MVP that should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;accept a path to a plugin (&lt;code&gt;jar file&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;creates an instance of the plugin&lt;/li&gt;
&lt;li&gt;runs the plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Requirements
&lt;/h1&gt;

&lt;p&gt;To follow along, you will only need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java 8+&lt;/li&gt;
&lt;li&gt;Maven 3+&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Phase 1: Boilerplate!
&lt;/h1&gt;

&lt;p&gt;Let's get right into it. Open up a terminal and follow along.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/osgi
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/osgi

mvn archetype:generate &lt;span class="nt"&gt;-DgroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.gabdavid.osgi                       &lt;span class="se"&gt;\&lt;/span&gt;
                       &lt;span class="nt"&gt;-DartifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;engine                               &lt;span class="se"&gt;\&lt;/span&gt;
                       &lt;span class="nt"&gt;-DarchetypeArtifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;maven-archetype-quickstart  &lt;span class="se"&gt;\&lt;/span&gt;
                       &lt;span class="nt"&gt;-DinteractiveMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false
&lt;/span&gt;mvn archetype:generate &lt;span class="nt"&gt;-DgroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.gabdavid.osgi                       &lt;span class="se"&gt;\&lt;/span&gt;
                       &lt;span class="nt"&gt;-DartifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sample-plugin                        &lt;span class="se"&gt;\&lt;/span&gt;
                       &lt;span class="nt"&gt;-DarchetypeArtifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;maven-archetype-quickstart  &lt;span class="se"&gt;\&lt;/span&gt;
                       &lt;span class="nt"&gt;-DinteractiveMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure that your &lt;code&gt;pom.xml&lt;/code&gt; files look like the following:&lt;br&gt;
&lt;code&gt;~/osgi/engine/pom.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0"&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
  &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.gabdavid.osgi&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;engine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;jar&lt;span class="nt"&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;engine&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;http://maven.apache.org&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;project.build.sourceEncoding&amp;gt;&lt;/span&gt;UTF-8&lt;span class="nt"&gt;&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;maven.compiler.source&amp;gt;&lt;/span&gt;1.8&lt;span class="nt"&gt;&amp;lt;/maven.compiler.source&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;maven.compiler.target&amp;gt;&lt;/span&gt;1.8&lt;span class="nt"&gt;&amp;lt;/maven.compiler.target&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;junit&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.12&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-jar-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.2.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;archive&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;manifest&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;mainClass&amp;gt;&lt;/span&gt;com.gabdavid.osgi.engine.Engine&lt;span class="nt"&gt;&amp;lt;/mainClass&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/archive&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;~/osgi/sample-plugin/pom.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0"&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
  &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.gabdavid.osgi&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sample-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;jar&lt;span class="nt"&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;sample-plugin&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;http://maven.apache.org&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;project.build.sourceEncoding&amp;gt;&lt;/span&gt;UTF-8&lt;span class="nt"&gt;&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;maven.compiler.source&amp;gt;&lt;/span&gt;1.8&lt;span class="nt"&gt;&amp;lt;/maven.compiler.source&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;maven.compiler.target&amp;gt;&lt;/span&gt;1.8&lt;span class="nt"&gt;&amp;lt;/maven.compiler.target&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;junit&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.12&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-jar-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.2.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;archive&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;manifest&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;mainClass&amp;gt;&lt;/span&gt;com.gabdavid.osgi.sampleplugin.App&lt;span class="nt"&gt;&amp;lt;/mainClass&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/archive&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;NOTE&lt;/em&gt;: I've moved and renamed where the main source file is in each project. Feel free to not do that, just make sure that the &lt;code&gt;mainClass&lt;/code&gt; tags reflect where the actual main classes are.&lt;/p&gt;

&lt;p&gt;Now we're ready to roll! Next up, a little theory.&lt;/p&gt;

&lt;h1&gt;
  
  
  Phase 2: The Theory
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Interfacing with the Plugin
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is figure out a way for the engine to interface with the plugin.&lt;/p&gt;

&lt;p&gt;One option would be to rely on a class in the Java standard library. A benefit of this option is that we do not need a third project that contains classes that both the engine and the plugins can depend on. A downside is that we have no way of specifying "plugin system specific" methods in a type-safe way. For the sake of simplicity of our MVP, this is the option that we're going to go with.&lt;/p&gt;

&lt;p&gt;The class from the standard library we will be using is the &lt;code&gt;Runnable&lt;/code&gt; class. We will be able to make use of its &lt;code&gt;run()&lt;/code&gt; method to run the plugin itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading a &lt;code&gt;jar&lt;/code&gt; file
&lt;/h2&gt;

&lt;p&gt;The second issue we need to address is how to read the &lt;code&gt;jar&lt;/code&gt; file. For those not "in the know", I'll let you in to a little secret: &lt;code&gt;jar&lt;/code&gt; files are just &lt;code&gt;zip&lt;/code&gt; files organized in a certain way! Which means that you could unzip a &lt;code&gt;jar&lt;/code&gt; and read the &lt;code&gt;class&lt;/code&gt; files somehow (we'll get to that in a second) and create instances of the classes defined. Luckily, we don't need to go through all of that work because Java's standard library comes with a &lt;code&gt;JarInputStream&lt;/code&gt; that will iterate through all of the "entries" (files) in the &lt;code&gt;jar&lt;/code&gt; (&lt;code&gt;zip&lt;/code&gt;) file and allow you to access them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the right &lt;code&gt;class&lt;/code&gt; file to load
&lt;/h2&gt;

&lt;p&gt;The next issue is finding the right file to read. For the sake of simplicity, we will require that the plugin include the entry class's canonical name (&lt;code&gt;&amp;lt;package&amp;gt;.&amp;lt;classname&amp;gt;&lt;/code&gt;) in the &lt;code&gt;MANIFEST.MF&lt;/code&gt;. This simplifies things because the &lt;code&gt;JarInputStream&lt;/code&gt; has a &lt;code&gt;getManifest&lt;/code&gt; method which will give us a &lt;code&gt;Manifest&lt;/code&gt; object containing all of the properties defined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loading the &lt;code&gt;class&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The final issue is actually reading the &lt;code&gt;class&lt;/code&gt; file and running it! We will be using a &lt;code&gt;UrlClassLoader&lt;/code&gt; to dynamically load the classes. We will be using its &lt;code&gt;loadClass&lt;/code&gt; method to load our class from byte code. The &lt;code&gt;loadClass&lt;/code&gt; method will return a &lt;code&gt;Class&lt;/code&gt; object which we will use to create instances of the class using the reflection API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class Loading 101
&lt;/h3&gt;

&lt;p&gt;If you already know how class loading works in Java, you can skip this section. &lt;strong&gt;Huge caveat: this is a quick explanation for the sake of context and is not a 100% complete explanation!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Java source code is compiled into byte code (the content of a &lt;code&gt;class&lt;/code&gt; file) which is then run by the JVM. All references to objects outside of the &lt;code&gt;class&lt;/code&gt; file are resolved at runtime, as opposed to a language like C which resolves all &lt;code&gt;include&lt;/code&gt; macros at compilation time. The way that these classes are resolved at runtime is with a &lt;code&gt;ClassLoader&lt;/code&gt;. If a &lt;code&gt;ClassLoader&lt;/code&gt; cannot find a particular &lt;code&gt;class&lt;/code&gt; it will throw a &lt;code&gt;ClassNotFoundException&lt;/code&gt;. The class loader is able to take byte code and turn it into an actual &lt;code&gt;Class&lt;/code&gt; object.&lt;/p&gt;

&lt;h1&gt;
  
  
  Phase 3: Writing the Engine
&lt;/h1&gt;

&lt;p&gt;Here is our MVP for the engine:&lt;br&gt;
&lt;code&gt;~/osgi/engine/src/main/java/com/gabdavid/osgi/engine/Engine.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.gabdavid.osgi.engine&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.File&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.FileInputStream&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.net.URL&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.net.URLClassLoader&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.jar.Attributes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.jar.JarInputStream&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.jar.Manifest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Have to check that a path has been passed in&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Path must be passed in"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;jarFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;className&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JarInputStream&lt;/span&gt; &lt;span class="n"&gt;jarStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JarInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jarFile&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;Manifest&lt;/span&gt; &lt;span class="n"&gt;manifest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jarStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getManifest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

      &lt;span class="c1"&gt;// Get Main-Class attribute from MANIFEST.MF&lt;/span&gt;
      &lt;span class="n"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMainAttributes&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MAIN_CLASS&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Class name found in manifest is: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;className&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Here, we initialize the class loader with the path to the jar file.&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// We use the jar protocol here. The !/ is used to separate between the URL to the actual&lt;/span&gt;
    &lt;span class="c1"&gt;// jar resource and the path within the jar. For example, I could download a whole jar by&lt;/span&gt;
    &lt;span class="c1"&gt;// calling jar:http://something.com/myjar!/ or I could download only 1 class file by calling&lt;/span&gt;
    &lt;span class="c1"&gt;// jar:http://something.com/myjar!/com/gabdavid/myjar/File.class&lt;/span&gt;
    &lt;span class="c1"&gt;// See https://docs.oracle.com/javase/7/docs/api/java/net/JarURLConnection.html for more details&lt;/span&gt;
    &lt;span class="nc"&gt;URLClassLoader&lt;/span&gt; &lt;span class="n"&gt;classLoader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLClassLoader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jar:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;jarFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toURI&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toURL&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"!/"&lt;/span&gt;&lt;span class="o"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pluginClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;className&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Load the class&lt;/span&gt;

    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Package of plugin class: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pluginClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPackage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Interface of plugin class is: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pluginClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInterfaces&lt;/span&gt;&lt;span class="o"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Creating a new instance now....!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create an instance of the loaded class and cast it from an Object&lt;/span&gt;
    &lt;span class="c1"&gt;// to a Runnable. We assume that this will succeed because that is the&lt;/span&gt;
    &lt;span class="c1"&gt;// contract we've agreed to (see theory section).&lt;/span&gt;
    &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pluginClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running instance now....!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Exiting successfully!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Phase 4: Writing the Plugin
&lt;/h1&gt;

&lt;p&gt;Here is our super simple plugin:&lt;br&gt;
&lt;code&gt;~/osgi/sample-plugin/com/gabdavid/osgi/sampleplugin/App.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.gabdavid.osgi.sampleplugin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// This is here for the sake of completeness, really. Wouldn't want to tell&lt;/span&gt;
  &lt;span class="c1"&gt;// Maven that this class has a main method when it doesn't actually have one!&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from the Sample Plugin!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Phase 5: Let's Run the Thing Already!
&lt;/h1&gt;

&lt;p&gt;Let's run it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/osgi/engine
mvn package

&lt;span class="nb"&gt;cd&lt;/span&gt; ~/osgi/sample-plugin
mvn package

java &lt;span class="nt"&gt;-jar&lt;/span&gt; ~/osgi/engine/target/engine-1.0-SNAPSHOT.jar ~/osgi/sample-plugin/target/sample-plugin-1.0-SNAPSHOT.jar

&lt;span class="c"&gt;# Output:&lt;/span&gt;
&lt;span class="c"&gt;# Class name found in manifest is: com.gabdavid.osgi.sampleplugin.App&lt;/span&gt;
&lt;span class="c"&gt;# Package of plugin class: package com.gabdavid.osgi.sampleplugin&lt;/span&gt;
&lt;span class="c"&gt;# Interface of plugin class is: java.lang.Runnable&lt;/span&gt;
&lt;span class="c"&gt;# Creating a new instance now....!&lt;/span&gt;
&lt;span class="c"&gt;# Hello from the Sample Plugin!&lt;/span&gt;
&lt;span class="c"&gt;# Exiting successfully!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you have it! You've now dynamically loaded a different &lt;code&gt;jar&lt;/code&gt; file and run their code! From here, the possibilities are endless.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Drawbacks of our current solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;Runnable&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;As we discussed in the theory section, using the &lt;code&gt;Runnable&lt;/code&gt; interface as our "adapter", if you will, limits us in the number of operations that we can call in a type-safe way. We may want to have lifecycle hooks or something as well as the main &lt;code&gt;run&lt;/code&gt; method. I keep saying "type-safe" because we could always just cast the plugin to an &lt;code&gt;Object&lt;/code&gt; and use reflection to call whatever methods that we want but that leaves a lot of room for error and could lead to (fictional) plugin-writers becoming frustrated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Doesn't Really Do Anything
&lt;/h3&gt;

&lt;p&gt;This really doesn't do anything! A future post will be to expand on this project so that it could actually &lt;em&gt;do&lt;/em&gt; something. &lt;/p&gt;

&lt;h2&gt;
  
  
  Future Plans?
&lt;/h2&gt;

&lt;p&gt;I plan on writing a part 2 to this post where I expand on the engine. If you have any suggestions of features to be added, please comment!&lt;/p&gt;

&lt;p&gt;Here's a short list of things that I'm thinking of improving on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turn the engine into a &lt;code&gt;repl&lt;/code&gt; of sorts where we can load and run different plugins&lt;/li&gt;
&lt;li&gt;Have the ability to reload a plugin&lt;/li&gt;
&lt;li&gt;Create a library where we can define an actual contract specific to our engine. That way, we can specify lifecycle hooks and get a little more creative with our plugins.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>tutorial</category>
      <category>osgi</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
