diff --git a/osgi.enroute.updater.provider/.classpath b/osgi.enroute.updater.provider/.classpath
new file mode 100644
index 0000000..57c70f3
--- /dev/null
+++ b/osgi.enroute.updater.provider/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/osgi.enroute.updater.provider/.gitignore b/osgi.enroute.updater.provider/.gitignore
new file mode 100644
index 0000000..11f90b6
--- /dev/null
+++ b/osgi.enroute.updater.provider/.gitignore
@@ -0,0 +1,3 @@
+/generated/
+/bin/
+/bin_test/
diff --git a/osgi.enroute.updater.provider/.project b/osgi.enroute.updater.provider/.project
new file mode 100644
index 0000000..01ad476
--- /dev/null
+++ b/osgi.enroute.updater.provider/.project
@@ -0,0 +1,23 @@
+
+
+ osgi.enroute.updater.provider
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ bndtools.core.bndbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ bndtools.core.bndnature
+
+
diff --git a/osgi.enroute.updater.provider/.settings/org.eclipse.core.resources.prefs b/osgi.enroute.updater.provider/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..94dd240
--- /dev/null
+++ b/osgi.enroute.updater.provider/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,10 @@
+eclipse.preferences.version=1
+encoding/.classpath=UTF-8
+encoding/.gitignore=UTF-8
+encoding/.project=UTF-8
+encoding//.settings/org.eclipse.jdt.core.prefs=UTF-8
+encoding//src/osgi/enroute/updater/provider/UpdaterImpl.java=UTF-8
+encoding//test/.gitignore=UTF-8
+encoding//test/osgi/enroute/updater/provider/UpdaterImplTest.java=UTF-8
+encoding/bnd.bnd=UTF-8
+encoding/readme.md=UTF-8
diff --git a/osgi.enroute.updater.provider/.settings/org.eclipse.jdt.core.prefs b/osgi.enroute.updater.provider/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..a698e59
--- /dev/null
+++ b/osgi.enroute.updater.provider/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/osgi.enroute.updater.provider/bnd.bnd b/osgi.enroute.updater.provider/bnd.bnd
new file mode 100644
index 0000000..83c80bc
--- /dev/null
+++ b/osgi.enroute.updater.provider/bnd.bnd
@@ -0,0 +1,25 @@
+#
+# OSGI ENROUTE UPDATER PROVIDER BUNDLE
+#
+
+
+Bundle-Description: \
+ Updates bundles based on their location if they use a file: URL.
+
+Private-Package: \
+ osgi.enroute.updater.provider
+
+-buildpath: \
+ osgi.enroute.base.api;version=1.0
+
+-testpath: \
+ osgi.enroute.junit.wrapper;version=4.12
+
+-includeresource: {readme.md}
+
+
+-runrequires: \
+ osgi.identity;filter:='(osgi.identity=osgi.enroute.updater.provider)'
+
+-runbundles: \
+ ${error;Resolve first}
diff --git a/osgi.enroute.updater.provider/readme.md b/osgi.enroute.updater.provider/readme.md
new file mode 100644
index 0000000..5f08afd
--- /dev/null
+++ b/osgi.enroute.updater.provider/readme.md
@@ -0,0 +1,15 @@
+# OSGI ENROUTE UPDATER PROVIDER
+
+${Bundle-Description}
+
+## Example
+
+## Configuration
+
+ Pid: osgi.enroute.updater
+
+ Field Type Description
+
+
+## References
+
diff --git a/osgi.enroute.updater.provider/src/osgi/enroute/updater/provider/UpdaterImpl.java b/osgi.enroute.updater.provider/src/osgi/enroute/updater/provider/UpdaterImpl.java
new file mode 100644
index 0000000..6cec903
--- /dev/null
+++ b/osgi.enroute.updater.provider/src/osgi/enroute/updater/provider/UpdaterImpl.java
@@ -0,0 +1,136 @@
+package osgi.enroute.updater.provider;
+
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.wiring.FrameworkWiring;
+import org.osgi.util.tracker.BundleTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A very simple bundle that tracks bundles that have a location
+ * that maps to a file. If so, it checks the lastModified times
+ * of the bundle and if necessary refreshes the bundles.
+ */
+public class UpdaterImpl extends Thread implements BundleActivator {
+ private static final String REFERENCE = "reference:";
+ private static final int SYSTEM_BUNDLE = 0;
+ private static Logger logger = LoggerFactory
+ .getLogger(UpdaterImpl.class);
+
+ static class BInfo {
+ File file;
+ Bundle bundle;
+ long lastPolled;
+ }
+
+ private BundleTracker tracker;
+ private FrameworkWiring framework;
+ private AtomicBoolean inRefresh = new AtomicBoolean(false);
+
+ public UpdaterImpl() {
+ super("OSGi Bundle Updater");
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ framework = context.getBundle(0).adapt(FrameworkWiring.class);
+ tracker = new BundleTracker(context, -1, null) {
+ @Override
+ public BInfo addingBundle(Bundle bundle, BundleEvent event) {
+ try {
+
+ if (bundle.getBundleId() == SYSTEM_BUNDLE)
+ return null;
+
+ String location = bundle.getLocation();
+ if (location.startsWith(REFERENCE))
+ location = location.substring(REFERENCE.length());
+
+ if (!location.startsWith("file:"))
+ return null;
+
+ File f = Paths.get(new URI(location)).toFile();
+ if (!f.exists())
+ return null;
+
+ BInfo b = new BInfo();
+ b.bundle = bundle;
+ return b;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ };
+ tracker.open();
+ start();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ interrupt();
+ }
+
+ public void run() {
+ logger.info("Starting");
+ try {
+ while (!isInterrupted())
+ try {
+ logger.info("Sleep");
+ sleep(1000);
+ if (inRefresh.get())
+ continue;
+
+ Set bundles = new HashSet();
+
+ long recently = System.currentTimeMillis() - 1000;
+ for (BInfo b : tracker.getTracked().values()) {
+ long lastModified = b.file.lastModified();
+
+ if (lastModified > recently)
+ continue;
+
+ if (lastModified > b.bundle.getLastModified()) {
+ bundles.add(b.bundle);
+ b.bundle.stop();
+ }
+ }
+
+ if (bundles.isEmpty())
+ continue;
+
+ logger.info("Update " + bundles);
+ for (Bundle b : bundles) try {
+ b.update();
+ b.start();
+ } catch(Exception e) {
+ logger.error("Unexpected error updating bundle "+b, e);
+ }
+
+ logger.info("Refresh start");
+ inRefresh.set(true);
+ framework.refreshBundles(bundles, event -> {
+ inRefresh.set(false);
+ logger.info("Refresh end");
+ });
+
+ } catch (InterruptedException e) {
+ return;
+ } catch (Exception e) {
+ logger.error("Unexpected error", e);
+ }
+ } finally {
+ logger.info("Exiting");
+ }
+ }
+}
diff --git a/osgi.enroute.updater.provider/test/.gitignore b/osgi.enroute.updater.provider/test/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/osgi.enroute.updater.provider/test/osgi/enroute/updater/provider/UpdaterImplTest.java b/osgi.enroute.updater.provider/test/osgi/enroute/updater/provider/UpdaterImplTest.java
new file mode 100644
index 0000000..8bbba13
--- /dev/null
+++ b/osgi.enroute.updater.provider/test/osgi/enroute/updater/provider/UpdaterImplTest.java
@@ -0,0 +1,18 @@
+package osgi.enroute.updater.provider;
+
+import junit.framework.TestCase;
+
+/*
+ *
+ *
+ *
+ */
+
+public class UpdaterImplTest extends TestCase {
+
+ /*
+ *
+ *
+ *
+ */
+}