diff --git a/bundles/org.openhab.ui.dashboard/META-INF/MANIFEST.MF b/bundles/org.openhab.ui.dashboard/META-INF/MANIFEST.MF
index 48205f731..a0e023f54 100644
--- a/bundles/org.openhab.ui.dashboard/META-INF/MANIFEST.MF
+++ b/bundles/org.openhab.ui.dashboard/META-INF/MANIFEST.MF
@@ -1,6 +1,5 @@
Manifest-Version: 1.0
Automatic-Module-Name: org.openhab.ui.dashboard
-Bundle-ActivationPolicy: lazy
Bundle-ManifestVersion: 2
Bundle-Name: openHAB Dashboard UI
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -19,7 +18,6 @@ Import-Package:
org.osgi.framework,
org.osgi.service.cm,
org.osgi.service.component,
- org.osgi.service.component.annotations;resolution:=optional,
org.osgi.service.http,
org.slf4j
Service-Component: OSGI-INF/*.xml
diff --git a/bundles/org.openhab.ui.dashboard/src/main/java/org/openhab/ui/dashboard/DashboardReady.java b/bundles/org.openhab.ui.dashboard/src/main/java/org/openhab/ui/dashboard/DashboardReady.java
new file mode 100644
index 000000000..e4e0a4905
--- /dev/null
+++ b/bundles/org.openhab.ui.dashboard/src/main/java/org/openhab/ui/dashboard/DashboardReady.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2015-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.ui.dashboard;
+
+/**
+ * This is a marker interface to declare that the dashboard is up and ready to be used.
+ *
+ * @author Kai Kreuzer - Initial contribution
+ *
+ */
+public interface DashboardReady {
+
+}
diff --git a/bundles/org.openhab.ui.dashboard/src/main/java/org/openhab/ui/dashboard/internal/DashboardService.java b/bundles/org.openhab.ui.dashboard/src/main/java/org/openhab/ui/dashboard/internal/DashboardService.java
index 8f37c44c6..9b3ad0e64 100644
--- a/bundles/org.openhab.ui.dashboard/src/main/java/org/openhab/ui/dashboard/internal/DashboardService.java
+++ b/bundles/org.openhab.ui.dashboard/src/main/java/org/openhab/ui/dashboard/internal/DashboardService.java
@@ -24,10 +24,12 @@ import org.eclipse.smarthome.core.i18n.LocaleProvider;
import org.eclipse.smarthome.core.i18n.TranslationProvider;
import org.eclipse.smarthome.core.net.HttpServiceUtil;
import org.eclipse.smarthome.core.net.NetworkAddressService;
+import org.openhab.ui.dashboard.DashboardReady;
import org.openhab.ui.dashboard.DashboardTile;
import org.osgi.framework.BundleContext;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentException;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
@@ -46,8 +48,8 @@ import org.slf4j.LoggerFactory;
* @author Laurent Garnier - internationalization
* @author Hilbrand Bouwkamp - internationalization
*/
-@Component(service = DashboardService.class, immediate = true, name = "org.openhab.dashboard")
-public class DashboardService {
+@Component(service = { DashboardService.class, DashboardReady.class }, immediate = true, name = "org.openhab.dashboard")
+public class DashboardService implements DashboardReady {
public static final String DASHBOARD_ALIAS = "/start";
@@ -166,10 +168,10 @@ public class DashboardService {
try {
indexTemplate = IOUtils.toString(index.openStream());
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new ComponentException(e);
}
} else {
- throw new RuntimeException("Cannot find index.html - failed to initialize Dashboard servlet");
+ throw new ComponentException("Cannot find index.html - failed to initialize Dashboard servlet");
}
URL entry = bundleContext.getBundle().getEntry("templates/entry.html");
@@ -177,10 +179,10 @@ public class DashboardService {
try {
entryTemplate = IOUtils.toString(entry.openStream());
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new ComponentException(e);
}
} else {
- throw new RuntimeException("Cannot find entry.html - failed to initialize Dashboard servlet");
+ throw new ComponentException("Cannot find entry.html - failed to initialize Dashboard servlet");
}
URL warn = bundleContext.getBundle().getEntry("templates/warn.html");
@@ -188,7 +190,7 @@ public class DashboardService {
try {
warnTemplate = IOUtils.toString(warn.openStream());
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new ComponentException(e);
}
} else {
throw new RuntimeException("Cannot find warn.html - failed to initialize Dashboard servlet");
@@ -199,10 +201,10 @@ public class DashboardService {
try {
setupTemplate = IOUtils.toString(setup.openStream());
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new ComponentException(e);
}
} else {
- throw new RuntimeException("Cannot find setup.html - failed to initialize Dashboard servlet");
+ throw new ComponentException("Cannot find setup.html - failed to initialize Dashboard servlet");
}
return new DashboardServlet(configurationAdmin, indexTemplate, entryTemplate, warnTemplate, setupTemplate,
diff --git a/bundles/org.openhab.ui.start/.classpath b/bundles/org.openhab.ui.start/.classpath
new file mode 100644
index 000000000..7f457fa41
--- /dev/null
+++ b/bundles/org.openhab.ui.start/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/bundles/org.openhab.ui.start/.project b/bundles/org.openhab.ui.start/.project
new file mode 100644
index 000000000..9ad58377d
--- /dev/null
+++ b/bundles/org.openhab.ui.start/.project
@@ -0,0 +1,33 @@
+
+
+ org.openhab.ui.start
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.pde.ds.core.builder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/bundles/org.openhab.ui.start/META-INF/MANIFEST.MF b/bundles/org.openhab.ui.start/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..e442b0139
--- /dev/null
+++ b/bundles/org.openhab.ui.start/META-INF/MANIFEST.MF
@@ -0,0 +1,21 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.openhab.ui.start
+Bundle-ManifestVersion: 2
+Bundle-Name: openHAB Start UI
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-SymbolicName: org.openhab.ui.start
+Bundle-Vendor: openHAB
+Bundle-Version: 2.4.0.qualifier
+Import-Package:
+ javax.servlet,
+ javax.servlet.http,
+ org.apache.commons.io,
+ org.eclipse.jdt.annotation;resolution:=optional,
+ org.openhab.ui.dashboard,
+ org.osgi.framework,
+ org.osgi.service.cm,
+ org.osgi.service.component,
+ org.osgi.service.http,
+ org.slf4j
+Service-Component: OSGI-INF/*.xml
+Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.openhab.ui.start/OSGI-INF/.gitignore b/bundles/org.openhab.ui.start/OSGI-INF/.gitignore
new file mode 100644
index 000000000..b878e882a
--- /dev/null
+++ b/bundles/org.openhab.ui.start/OSGI-INF/.gitignore
@@ -0,0 +1 @@
+/*.xml
diff --git a/bundles/org.openhab.ui.start/about.html b/bundles/org.openhab.ui.start/about.html
new file mode 100644
index 000000000..2a7c838be
--- /dev/null
+++ b/bundles/org.openhab.ui.start/about.html
@@ -0,0 +1,37 @@
+
+
+
+
+About
+
+
+About This Content
+
+March 22, 2017
+License
+
+The openHAB community makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at http://www.eclipse.org/legal/epl-v10.html.
+For purposes of the EPL, "Program" will mean the Content.
+
+If you did not receive this Content directly from the openHAB community, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at openhab.org.
+
+ Third Party Content
+ The Content includes items that have been sourced from third parties as set out below. If you
+ did not receive this Content directly from the openHAB project, the following is provided
+ for informational purposes only, and you should look to the Redistributor's license for
+ terms and conditions of use.
+
+ Simple HttpErrorPages
+ HttpErrorPages obtained from Github repository under MIT License.
+
+
+
\ No newline at end of file
diff --git a/bundles/org.openhab.ui.start/build.properties b/bundles/org.openhab.ui.start/build.properties
new file mode 100644
index 000000000..39c5e6747
--- /dev/null
+++ b/bundles/org.openhab.ui.start/build.properties
@@ -0,0 +1,7 @@
+output.. = target/classes/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/,\
+ about.html,\
+ pages/
+source.. = src/main/java/
diff --git a/bundles/org.openhab.ui.start/pages/404.html b/bundles/org.openhab.ui.start/pages/404.html
new file mode 100644
index 000000000..c1694b07a
--- /dev/null
+++ b/bundles/org.openhab.ui.start/pages/404.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ We've got some trouble | 404 - Resource not found
+
+
+
+ Resource not found | Error 404
The requested resource could not be found.
+
+
diff --git a/bundles/org.openhab.ui.start/pages/status.html b/bundles/org.openhab.ui.start/pages/status.html
new file mode 100644
index 000000000..522a16a4f
--- /dev/null
+++ b/bundles/org.openhab.ui.start/pages/status.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ ${message}
+
+
+
+
+
+
diff --git a/bundles/org.openhab.ui.start/pom.xml b/bundles/org.openhab.ui.start/pom.xml
new file mode 100644
index 000000000..e6ba16c3c
--- /dev/null
+++ b/bundles/org.openhab.ui.start/pom.xml
@@ -0,0 +1,14 @@
+
+
+ 4.0.0
+
+ org.openhab.core
+ pom-bundles
+ 2.4.0-SNAPSHOT
+
+
+ org.openhab.ui.start
+
+ eclipse-plugin
+ openHAB Start UI
+
diff --git a/bundles/org.openhab.ui.start/src/main/java/org/openhab/ui/start/internal/RootServlet.java b/bundles/org.openhab.ui.start/src/main/java/org/openhab/ui/start/internal/RootServlet.java
new file mode 100644
index 000000000..61980bdc7
--- /dev/null
+++ b/bundles/org.openhab.ui.start/src/main/java/org/openhab/ui/start/internal/RootServlet.java
@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2015-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.ui.start.internal;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.openhab.ui.dashboard.DashboardReady;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentException;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This servlet registers status (starting/stopping/updating) pages and serves the 404 page if system is started and an
+ * unknown url is called.
+ *
+ * @author Kai Kreuzer - Initial contribution
+ *
+ */
+@Component(immediate = true)
+public class RootServlet extends HttpServlet {
+
+ private static final long serialVersionUID = -2091860295954594917L;
+
+ private final Logger logger = LoggerFactory.getLogger(RootServlet.class);
+
+ protected HttpService httpService;
+
+ // an enumeration for the state the whole system is in
+ private enum LifeCycleState {
+ STARTING,
+ STARTED,
+ STOPPING,
+ UPDATING;
+ }
+
+ private String page404;
+ private String pageStatus;
+
+ private DashboardReady dashboardStarted;
+ private LifeCycleState lifecycleState = LifeCycleState.STARTING;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ if (dashboardStarted != null) {
+ // all is up and running
+ if (req.getRequestURI().equals("/")) {
+ resp.sendRedirect("/start/index");
+ } else {
+ resp.sendError(HttpServletResponse.SC_NOT_FOUND);
+ resp.setContentType("text/html;charset=UTF-8");
+ resp.getWriter().append(page404);
+ resp.getWriter().close();
+ }
+ } else {
+ // report current system state
+ String message = null;
+ String subMessage = null;
+ switch (lifecycleState) {
+ case STARTING:
+ message = "openHAB is starting...";
+ subMessage = "Please wait a moment!";
+ break;
+ case UPDATING:
+ message = "openHAB is updating...";
+ subMessage = "Please wait a moment!";
+ break;
+ case STOPPING:
+ message = "openHAB is shutting down...";
+ subMessage = "Please stand by.";
+ break;
+ default:
+ throw new IllegalStateException("Invalid system state " + lifecycleState);
+ }
+ resp.setContentType("text/html;charset=UTF-8");
+ resp.getWriter().append(pageStatus.replace("${message}", message).replace("${submessage}", subMessage));
+ resp.getWriter().close();
+ }
+ }
+
+ @Activate
+ protected void activate(ComponentContext context) {
+ try {
+ httpService.registerServlet("/", this, new Properties(), httpService.createDefaultHttpContext());
+ } catch (ServletException | NamespaceException e) {
+ logger.error("Failed registering root servlet!", e);
+ }
+ URL notfound = context.getBundleContext().getBundle().getEntry("pages/404.html");
+ if (notfound != null) {
+ try {
+ page404 = IOUtils.toString(notfound.openStream());
+ } catch (IOException e) {
+ throw new ComponentException(e);
+ }
+ } else {
+ throw new ComponentException("Cannot find 404.html - failed to initialize root servlet");
+ }
+ URL status = context.getBundleContext().getBundle().getEntry("pages/status.html");
+ if (status != null) {
+ try {
+ pageStatus = IOUtils.toString(status.openStream());
+ } catch (IOException e) {
+ throw new ComponentException(e);
+ }
+ } else {
+ throw new ComponentException("Cannot find status.html - failed to initialize root servlet");
+ }
+
+ // we can determine whether the whole framework is shutdown by listening to a STOPPING event for bundle 0.
+ Bundle systemBundle = context.getBundleContext().getBundle(0);
+ systemBundle.getBundleContext().addBundleListener(new SynchronousBundleListener() {
+ @Override
+ public void bundleChanged(final BundleEvent event) {
+ if (event.getBundle().getBundleId() == 0 && event.getType() == BundleEvent.STOPPING) {
+ lifecycleState = LifeCycleState.STOPPING;
+ }
+ }
+ });
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ // reset, if this component is ever reused (should normally not be the case), it should be "starting" again.
+ lifecycleState = LifeCycleState.STARTING;
+ }
+
+ @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
+ protected void setDashboardStarted(DashboardReady dashboardStarted) {
+ this.dashboardStarted = dashboardStarted;
+ this.lifecycleState = LifeCycleState.STARTED;
+ }
+
+ protected void unsetDashboardStarted(DashboardReady dashboardStarted) {
+ if (lifecycleState != LifeCycleState.STOPPING) {
+ lifecycleState = LifeCycleState.UPDATING;
+ }
+ this.dashboardStarted = null;
+ }
+
+ @Reference
+ protected void setHttpService(HttpService httpService) {
+ this.httpService = httpService;
+ }
+
+ protected void unsetHttpService(HttpService httpService) {
+ this.httpService = null;
+ }
+}
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 81f01e935..0cf6d160d 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -30,6 +30,7 @@
org.openhab.ui.classicui
org.openhab.ui.homebuilder
org.openhab.ui.paperui
+ org.openhab.ui.start
diff --git a/features/openhab-core/src/main/feature/feature.xml b/features/openhab-core/src/main/feature/feature.xml
index b2d223516..414cff959 100644
--- a/features/openhab-core/src/main/feature/feature.xml
+++ b/features/openhab-core/src/main/feature/feature.xml
@@ -32,6 +32,8 @@
openhab-transport-http
shell
wrapper
+
+ mvn:org.openhab.core/org.openhab.ui.start/${project.version}
mvn:org.openhab.core/org.openhab.core/${project.version}
mvn:org.openhab.core/org.openhab.core.karaf/${project.version}
mvn:org.openhab.core/org.openhab.io.sound/${project.version}
diff --git a/features/p2/feature.xml b/features/p2/feature.xml
index 075d7889e..5679122e3 100644
--- a/features/p2/feature.xml
+++ b/features/p2/feature.xml
@@ -86,4 +86,10 @@
version="0.0.0"
unpack="false"/>
+