diff --git a/bundles/org.openhab.ui.cometvisu.php/pom.xml.versionsBackup b/bundles/org.openhab.ui.cometvisu.php/pom.xml.versionsBackup deleted file mode 100644 index 8227902e8..000000000 --- a/bundles/org.openhab.ui.cometvisu.php/pom.xml.versionsBackup +++ /dev/null @@ -1,53 +0,0 @@ - - - 4.0.0 - - - org.openhab.ui.bundles - org.openhab.ui.reactor.bundles - 2.5.0 - - - org.openhab.ui.cometvisu.php - - openHAB UI :: Bundles :: CometVisu :: PHP Support - - - - org.openhab - com.caucho.quercus - 4.0.45 - - - org.openhab.ui.bundles - org.openhab.ui.cometvisu - ${project.version} - - - org.openhab.core.bundles - org.openhab.core - ${project.version} - - - org.openhab.ui.bundles - org.openhab.ui.dashboard - ${project.version} - - - org.openhab.core.bundles - org.openhab.core.model.sitemap - ${project.version} - - - org.openhab.core.bundles - org.openhab.core.ui - ${project.version} - - - org.openhab.core.bundles - org.openhab.core.ui.icon - ${project.version} - - - - diff --git a/bundles/org.openhab.ui.cometvisu/.classpath b/bundles/org.openhab.ui.cometvisu/.classpath index a2f8d9d5f..e7791d4d9 100644 --- a/bundles/org.openhab.ui.cometvisu/.classpath +++ b/bundles/org.openhab.ui.cometvisu/.classpath @@ -28,19 +28,16 @@ - - - - - - - - - + + + + + + diff --git a/bundles/org.openhab.ui.cometvisu/bnd.bnd b/bundles/org.openhab.ui.cometvisu/bnd.bnd deleted file mode 100644 index 82333b824..000000000 --- a/bundles/org.openhab.ui.cometvisu/bnd.bnd +++ /dev/null @@ -1,2 +0,0 @@ -Bundle-SymbolicName: ${project.artifactId} -Bundle-Activator: org.openhab.ui.cometvisu.internal.CvActivator diff --git a/bundles/org.openhab.ui.cometvisu/pom.xml b/bundles/org.openhab.ui.cometvisu/pom.xml index e9a7ac4c5..33c02374c 100644 --- a/bundles/org.openhab.ui.cometvisu/pom.xml +++ b/bundles/org.openhab.ui.cometvisu/pom.xml @@ -68,11 +68,6 @@ jackson-annotations 2.9.10 - - org.glassfish.jersey.media - jersey-media-multipart - 2.22.2 - diff --git a/bundles/org.openhab.ui.cometvisu/pom.xml.versionsBackup b/bundles/org.openhab.ui.cometvisu/pom.xml.versionsBackup deleted file mode 100644 index e9bad0aed..000000000 --- a/bundles/org.openhab.ui.cometvisu/pom.xml.versionsBackup +++ /dev/null @@ -1,100 +0,0 @@ - - - 4.0.0 - - - org.openhab.ui.bundles - org.openhab.ui.reactor.bundles - 2.5.0 - - - org.openhab.ui.cometvisu - - openHAB UI :: Bundles :: CometVisu :: Backend - - - - com.sun.xml.bind - jaxb-core - 2.2.11 - provided - - - com.sun.xml.bind - jaxb-impl - 2.2.11 - provided - - - javax.activation - activation - 1.1.1 - provided - - - javax.xml.bind - jaxb-api - 2.2.12 - provided - - - org.openhab.core.bundles - org.openhab.core - ${project.version} - - - org.openhab.ui.bundles - org.openhab.ui.dashboard - ${project.version} - - - org.openhab.core.bundles - org.openhab.core.model.sitemap - ${project.version} - - - org.openhab.core.bundles - org.openhab.core.ui - ${project.version} - - - org.openhab.core.bundles - org.openhab.core.ui.icon - ${project.version} - - - org.rrd4j - rrd4j - 3.4 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - src/gen/java - - - - org.codehaus.mojo - jaxb2-maven-plugin - 2.2 - - - org.openhab.ui.cometvisu.internal.config.beans - - src/main/resources/visu_config.xsd - - src/gen/java - en - false - false - - - - - - diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/CvActivator.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/CvActivator.java deleted file mode 100644 index c8c2fd5de..000000000 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/CvActivator.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.ui.cometvisu.internal; - -import org.glassfish.jersey.media.multipart.MultiPartFeature; -import org.glassfish.jersey.media.sse.SseFeature; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Bundle activator for CometVisu backend. - * - * @author Tobias Bräutigam - Initial Contribution and API - * - */ -public class CvActivator implements BundleActivator { - - private final Logger logger = LoggerFactory.getLogger(CvActivator.class); - - private static BundleContext context; - - private ServiceRegistration sseFeatureRegistration; - - private ServiceRegistration blockingAsyncFeatureRegistration; - - private ServiceRegistration multiPartRegistration; - - /** - * Called whenever the OSGi framework starts our bundle - */ - @Override - public void start(BundleContext bc) throws Exception { - context = bc; - - String featureName = SseFeature.class.getName(); - if (bc.getServiceReference(featureName) == null) { - sseFeatureRegistration = bc.registerService(featureName, new SseFeature(), null); - - logger.debug("CometVisu - SseFeature registered."); - } - featureName = MultiPartFeature.class.getName(); - if (bc.getServiceReference(featureName) == null) { - multiPartRegistration = bc.registerService(featureName, new MultiPartFeature(), null); - - logger.debug("CometVisu - MultiPartFeature registered."); - } - - logger.debug("CometVisu has been started."); - } - - /** - * Called whenever the OSGi framework stops our bundle - */ - @Override - public void stop(BundleContext bc) throws Exception { - context = null; - - if (sseFeatureRegistration != null) { - sseFeatureRegistration.unregister(); - logger.debug("CometVisu - SseFeature unregistered."); - } - - if (blockingAsyncFeatureRegistration != null) { - blockingAsyncFeatureRegistration.unregister(); - logger.debug("CometVisu - BlockingAsyncFeature unregistered."); - } - - if (multiPartRegistration != null) { - multiPartRegistration.unregister(); - logger.debug("CometVisu - MultiPartFeature unregistered."); - } - - logger.debug("CometVisu has been stopped."); - } - - /** - * Returns the bundle context of this bundle - * - * @return the bundle context - */ - public static BundleContext getContext() { - return context; - } -} diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncBinder.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncBinder.java deleted file mode 100644 index 6c3164be1..000000000 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncBinder.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.ui.cometvisu.internal.async; - -import org.glassfish.hk2.utilities.binding.AbstractBinder; -import org.glassfish.jersey.internal.inject.CustomAnnotationLiteral; -import org.glassfish.jersey.servlet.spi.AsyncContextDelegateProvider; - -/** - * An {@link AbstractBinder} implementation that registers our custom - * {@link BlockingAsyncContextDelegateProvider} class as an implementation of - * the {@link AsyncContextDelegateProvider} SPI interface. - * - * @author Tobias Bräutigam - Initial Contribution and API - * - */ -public class BlockingAsyncBinder extends AbstractBinder { - - @Override - protected void configure() { - // the qualifiedBy is needed in order for our implementation to be used - // if there are multiple implementations of AsyncContextDelegateProvider - bind(new BlockingAsyncContextDelegateProvider()).to(AsyncContextDelegateProvider.class) - .qualifiedBy(CustomAnnotationLiteral.INSTANCE); - } -} diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncContextDelegateProvider.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncContextDelegateProvider.java deleted file mode 100644 index 3ecee6836..000000000 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncContextDelegateProvider.java +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.ui.cometvisu.internal.async; - -import java.io.IOException; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.glassfish.jersey.media.sse.SseFeature; -import org.glassfish.jersey.servlet.spi.AsyncContextDelegate; -import org.glassfish.jersey.servlet.spi.AsyncContextDelegateProvider; -import org.openhab.ui.cometvisu.internal.util.SseUtil; - -/** - * An {@link AsyncContextDelegateProvider} implementation that returns a - * blocking {@link AsyncContextDelegate}, which blocks while the connection is - * alive if the response content-type is {@link SseFeature #SERVER_SENT_EVENTS} - * or throws an UnsupportedOperationException otherwise. The blocking continues - * until the response can longer be written to. - * - * @author Tobias Bräutigam - Initial Contribution and API - * - */ -public class BlockingAsyncContextDelegateProvider implements AsyncContextDelegateProvider { - - @Override - public final AsyncContextDelegate createDelegate(final HttpServletRequest request, - final HttpServletResponse response) { - return new BlockingAsyncContextDelegate(request, response); - } - - private static final class BlockingAsyncContextDelegate implements AsyncContextDelegate { - private static final int PING_TIMEOUT = 15 * 1000; - - private final HttpServletResponse response; - - private volatile boolean isRunning; - - private BlockingAsyncContextDelegate(final HttpServletRequest request, final HttpServletResponse response) { - this.response = response; - } - - @Override - public void complete() { - isRunning = false; - } - - @Override - public void suspend() throws IllegalStateException { - if (SseUtil.shouldAsyncBlock()) { - isRunning = true; - - synchronized (this) { - while (isRunning) { - try { - this.wait(PING_TIMEOUT); - ServletOutputStream outputStream = response.getOutputStream(); - - // write a new line to the OutputStream and flush to - // check connectivity. If the other peer closes the - // connection, the first flush() should generate a - // TCP reset that is detected on the second flush() - outputStream.write('\n'); - response.flushBuffer(); - - outputStream.write('\n'); - response.flushBuffer(); - } catch (Exception exception) { - // If an exception has occurred during write and - // flush we consider the connection closed, attempt - // to close the output stream and stop blocking. - try { - response.getOutputStream().close(); - } catch (IOException e) { - } - - isRunning = false; - } - } - } - } else { - throw new UnsupportedOperationException("ASYNCHRONOUS PROCESSING IS NOT SUPPORTED!"); - } - } - } -} diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncFeature.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncFeature.java deleted file mode 100644 index ca5f47bc8..000000000 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/async/BlockingAsyncFeature.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.ui.cometvisu.internal.async; - -import javax.ws.rs.core.Feature; -import javax.ws.rs.core.FeatureContext; - -/** - * A {@link Feature} implementation that registers our custom - * {@link BlockingAsyncBinder}. - * - * @author Tobias Bräutigam - Initial Contribution and API - * - */ -public class BlockingAsyncFeature implements Feature { - - @Override - public boolean configure(FeatureContext context) { - if (context.getConfiguration().isEnabled(BlockingAsyncFeature.class)) { - return false; - } - - context.register(new BlockingAsyncBinder()); - - return true; - } -} diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ChartResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ChartResource.java index 16f47d094..c7644f539 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ChartResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ChartResource.java @@ -39,6 +39,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.core.items.GroupItem; import org.openhab.core.items.Item; @@ -55,6 +56,11 @@ import org.osgi.service.component.annotations.Component; 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.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.rrd4j.ConsolFun; import org.rrd4j.core.FetchData; import org.rrd4j.core.FetchRequest; @@ -73,9 +79,13 @@ import io.swagger.annotations.ApiResponses; * used by the diagram plugin * * @author Tobias Bräutigam - Initial contribution - * + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_CHART_ALIAS) +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_CHART_ALIAS) @Api(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_CHART_ALIAS) public class ChartResource implements RESTResource { diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/CheckResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/CheckResource.java index 4e4b6d904..d12b758ca 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/CheckResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/CheckResource.java @@ -21,12 +21,18 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.ui.cometvisu.internal.Config; import org.openhab.ui.cometvisu.internal.ManagerSettings; import org.openhab.ui.cometvisu.internal.backend.model.rest.CheckResponse; import org.openhab.ui.cometvisu.internal.backend.model.rest.EnvironmentState; import org.osgi.service.component.annotations.Component; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -37,9 +43,13 @@ import io.swagger.annotations.ApiResponses; * Check filesystem backend for the cometvisu manager. * * @author Tobias Bräutigam - Initial contribution - * + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/fs/check") +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/fs/check") @Api(Config.COMETVISU_BACKEND_ALIAS + "/fs/check") public class CheckResource implements RESTResource { diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ConfigResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ConfigResource.java index b00de86b3..59d707891 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ConfigResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ConfigResource.java @@ -19,13 +19,20 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.ui.cometvisu.internal.Config; import org.openhab.ui.cometvisu.internal.util.ClientInstaller; import org.osgi.service.component.annotations.Component; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; @@ -35,9 +42,15 @@ import io.swagger.annotations.ApiResponses; * Allows certain actions to configure the CometVisu backend through the REST api. * * @author Tobias Bräutigam - Initial contribution + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_CONFIG_ALIAS) +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_CONFIG_ALIAS) +@Api(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_CONFIG_ALIAS) public class ConfigResource implements RESTResource { private final Logger logger = LoggerFactory.getLogger(ConfigResource.class); diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/DataProviderResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/DataProviderResource.java index 4aee5fad4..b6cf8b704 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/DataProviderResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/DataProviderResource.java @@ -26,6 +26,7 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.core.items.GroupItem; import org.openhab.core.items.Item; @@ -43,6 +44,11 @@ import org.osgi.service.component.annotations.Component; 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.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,9 +61,13 @@ import io.swagger.annotations.ApiResponses; * DataProvider backend for the cometvisu manager. * * @author Tobias Bräutigam - Initial contribution - * + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/data") +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/data") @Api(Config.COMETVISU_BACKEND_ALIAS + "/data") public class DataProviderResource implements RESTResource { diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/EventBroadcaster.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/EventBroadcaster.java index 36deafa4d..69e25631f 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/EventBroadcaster.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/EventBroadcaster.java @@ -14,6 +14,8 @@ package org.openhab.ui.cometvisu.internal.backend.rest; import java.util.Map; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.items.Item; import org.openhab.core.types.State; @@ -22,6 +24,7 @@ import org.openhab.core.types.State; * * @author Tobias Bräutigam - Initial contribution */ +@NonNullByDefault public interface EventBroadcaster { /** * Broadcasts an event described by the given parameters to all currently @@ -65,5 +68,5 @@ public interface EventBroadcaster { * - the item that is listened to * @return */ - public Map> getClientItems(Item item); + public Map> getClientItems(Item item); } diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/FsResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/FsResource.java index 4db28d344..2b30bfe66 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/FsResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/FsResource.java @@ -13,27 +13,29 @@ package org.openhab.ui.cometvisu.internal.backend.rest; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; +import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; -import org.glassfish.jersey.media.multipart.FormDataContentDisposition; -import org.glassfish.jersey.media.multipart.FormDataParam; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.ui.cometvisu.internal.Config; import org.openhab.ui.cometvisu.internal.ManagerSettings; @@ -42,6 +44,11 @@ import org.openhab.ui.cometvisu.internal.util.FileOperationException; import org.openhab.ui.cometvisu.internal.util.FsUtil; import org.openhab.ui.cometvisu.internal.util.MountedFile; import org.osgi.service.component.annotations.Component; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,9 +62,13 @@ import io.swagger.annotations.ApiResponses; * Filesystem backend for the cometvisu manager. * * @author Tobias Bräutigam - Initial contribution - * + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/fs") +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/fs") @Api(Config.COMETVISU_BACKEND_ALIAS + "/fs") public class FsResource implements RESTResource { @@ -103,21 +114,22 @@ public class FsResource implements RESTResource { @ApiOperation(value = "Create a binary file") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "not allowed"), @ApiResponse(code = 406, message = "File already exists") }) - public Response createBinary( + public Response createBinary(@Context HttpServletRequest request, @ApiParam(value = "Relative path inside the config folder", required = true) @QueryParam("path") String path, @QueryParam("type") String type, @ApiParam(value = "CRC32 hash of the file content") @QueryParam("hash") String hash, - @ApiParam(value = "force overriding existing file") @DefaultValue("false") @FormDataParam("force") Boolean force, - @ApiParam(value = "file content") @FormDataParam("file") InputStream fileInputStream, - @FormDataParam("file") FormDataContentDisposition fileMetaData) { + @ApiParam(value = "force overriding existing file") @DefaultValue("false") @FormParam("force") Boolean force, + @ApiParam(value = "file content") @FormParam("file") Object fileParam) { MountedFile target; try { - target = new MountedFile(Paths.get(path, fileMetaData.getFileName()).toString()); + MultipartRequestMap map = new MultipartRequestMap(request); + File file = map.getFileParameter("file"); + target = new MountedFile(Paths.get(path, file.getName()).toString()); File folder = target.toFile().toPath().getParent().toFile(); if (!target.exists() || force) { if (!target.isReadonlyMount() && folder.canWrite()) { try { - FsUtil.getInstance().saveFile(target.toFile(), fileInputStream, hash); + FsUtil.getInstance().saveFile(target.toFile(), new FileInputStream(file), hash); return Response.ok().build(); } catch (FileOperationException e) { return FsUtil.createErrorResponse(e); diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/HiddenConfigResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/HiddenConfigResource.java index 7c4b580bb..2e8a8c7d1 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/HiddenConfigResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/HiddenConfigResource.java @@ -30,6 +30,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.ui.cometvisu.internal.Config; import org.openhab.ui.cometvisu.internal.ManagerSettings; @@ -37,6 +38,11 @@ import org.openhab.ui.cometvisu.internal.backend.model.rest.ConfigSection; import org.openhab.ui.cometvisu.internal.backend.model.rest.HiddenConfig; import org.openhab.ui.cometvisu.internal.util.FsUtil; import org.osgi.service.component.annotations.Component; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,9 +59,13 @@ import io.swagger.annotations.ApiResponses; * Hidden configuration backend for the cometvisu manager. * * @author Tobias Bräutigam - Initial contribution - * + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/config") +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/config") @Api(Config.COMETVISU_BACKEND_ALIAS + "/config") public class HiddenConfigResource implements RESTResource { diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/LoginResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/LoginResource.java index db6ce14f2..728348d38 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/LoginResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/LoginResource.java @@ -22,12 +22,18 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.ui.cometvisu.internal.Config; import org.openhab.ui.cometvisu.internal.backend.model.ConfigBean; import org.openhab.ui.cometvisu.internal.backend.model.LoginBean; import org.openhab.ui.cometvisu.internal.backend.model.ResourcesBean; import org.osgi.service.component.annotations.Component; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -39,8 +45,13 @@ import io.swagger.annotations.ApiResponses; * currently this is just a placeholder and does no real authentification * * @author Tobias Bräutigam - Initial contribution + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_LOGIN_ALIAS) +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_LOGIN_ALIAS) @Api(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_LOGIN_ALIAS) public class LoginResource implements RESTResource { diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/MoveResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/MoveResource.java index eed7c0adb..cbdc0a8e8 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/MoveResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/MoveResource.java @@ -23,12 +23,18 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.ui.cometvisu.internal.Config; import org.openhab.ui.cometvisu.internal.util.FileOperationException; import org.openhab.ui.cometvisu.internal.util.FsUtil; import org.openhab.ui.cometvisu.internal.util.MountedFile; import org.osgi.service.component.annotations.Component; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,9 +48,13 @@ import io.swagger.annotations.ApiResponses; * Move/renames files for the CometVisu manager. * * @author Tobias Bräutigam - Initial contribution - * + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/fs/move") +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/fs/move") @Api(Config.COMETVISU_BACKEND_ALIAS + "/fs/move") public class MoveResource implements RESTResource { diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/MultipartRequestMap.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/MultipartRequestMap.java new file mode 100644 index 000000000..447e7362a --- /dev/null +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/MultipartRequestMap.java @@ -0,0 +1,124 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.ui.cometvisu.internal.backend.rest; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.Part; + +/** + * Helper object for getting files from multi-part {@link HttpServletRequest}s. + * + * @author Wouter Born - Initial contribution + */ +public class MultipartRequestMap extends HashMap> { + + private static final long serialVersionUID = 1L; + private static final String DEFAULT_ENCODING = "UTF-8"; + + private String encoding; + private String tempLocation; + + public MultipartRequestMap(HttpServletRequest request) { + this(request, System.getProperty("java.io.tmpdir")); + } + + public MultipartRequestMap(HttpServletRequest request, String tempLocation) { + super(); + try { + this.tempLocation = tempLocation; + + encoding = request.getCharacterEncoding(); + if (encoding == null) { + try { + encoding = DEFAULT_ENCODING; + request.setCharacterEncoding(DEFAULT_ENCODING); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("Unsupported encoding: " + encoding, e); + } + } + + for (Part part : request.getParts()) { + String fileName = part.getSubmittedFileName(); + if (fileName == null) { + putMulti(part.getName(), getValue(part)); + } else { + processFilePart(part, fileName); + } + } + } catch (IOException | ServletException e) { + throw new IllegalStateException("Failed to get request parts", e); + } + } + + public String getStringParameter(String name) { + List list = get(name); + return (list != null) ? (String) get(name).get(0) : null; + } + + public File getFileParameter(String name) { + List list = get(name); + return (list != null) ? (File) get(name).get(0) : null; + } + + private void processFilePart(Part part, String fileName) throws IOException { + File tempFile = new File(tempLocation, fileName); + tempFile.createNewFile(); + tempFile.deleteOnExit(); + + try (BufferedInputStream input = new BufferedInputStream(part.getInputStream(), 8192); + BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(tempFile), 8192);) { + + byte[] buffer = new byte[8192]; + for (int length = 0; ((length = input.read(buffer)) > 0);) { + output.write(buffer, 0, length); + } + } + part.delete(); + putMulti(part.getName(), tempFile); + } + + private String getValue(Part part) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), encoding)); + StringBuilder value = new StringBuilder(); + char[] buffer = new char[8192]; + for (int length; (length = reader.read(buffer)) > 0;) { + value.append(buffer, 0, length); + } + return value.toString(); + } + + private void putMulti(final String key, final T value) { + List values = super.get(key); + + if (values == null) { + values = new ArrayList<>(); + values.add(value); + put(key, values); + } else { + values.add(value); + } + } +} diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ReadResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ReadResource.java index 42721c5e9..e0eaa8a36 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ReadResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/ReadResource.java @@ -29,12 +29,16 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; +import javax.ws.rs.sse.Sse; +import javax.ws.rs.sse.SseEventSink; -import org.glassfish.jersey.media.sse.EventOutput; -import org.glassfish.jersey.media.sse.SseBroadcaster; -import org.glassfish.jersey.media.sse.SseFeature; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; +import org.openhab.core.io.rest.SseBroadcaster; import org.openhab.core.items.GenericItem; import org.openhab.core.items.Item; import org.openhab.core.items.ItemFactory; @@ -45,8 +49,15 @@ import org.openhab.ui.cometvisu.internal.Config; import org.openhab.ui.cometvisu.internal.backend.model.StateBean; import org.openhab.ui.cometvisu.internal.listeners.StateEventListener; import org.openhab.ui.cometvisu.internal.util.SseUtil; +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.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,48 +71,56 @@ import io.swagger.annotations.ApiResponses; * SSE communication * * @author Tobias Bräutigam - Initial contribution + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component(immediate = true) +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_READ_ALIAS) +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_READ_ALIAS) @Api(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_READ_ALIAS) +@NonNullByDefault public class ReadResource implements EventBroadcaster, RESTResource { private final Logger logger = LoggerFactory.getLogger(ReadResource.class); - private SseBroadcaster broadcaster = new SseBroadcaster(); + private SseBroadcaster broadcaster = new SseBroadcaster<>(); - private final ExecutorService executorService; + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); - private ItemRegistry itemRegistry; + private final ItemRegistry itemRegistry; - private StateEventListener stateEventListener; + private final StateEventListener stateEventListener = new StateEventListener(this); private List itemNames = new ArrayList<>(); - private Map>> items = new HashMap<>(); + private Map>> items = new HashMap<>(); @Context - private UriInfo uriInfo; + private @NonNullByDefault({}) UriInfo uriInfo; @Context - private HttpServletResponse response; + private @NonNullByDefault({}) HttpServletResponse response; @Context - private HttpServletRequest request; + private @NonNullByDefault({}) HttpServletRequest request; + + private @NonNullByDefault({}) Sse sse; private Collection itemFactories = new CopyOnWriteArrayList<>(); - public ReadResource() { - this.executorService = Executors.newSingleThreadExecutor(); - this.stateEventListener = new StateEventListener(); - this.stateEventListener.setEventBroadcaster(this); - } - - @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { + @Activate + public ReadResource(@Reference ItemRegistry itemRegistry) { this.itemRegistry = itemRegistry; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + @Deactivate + public void deactivate() { + broadcaster.close(); + } + + @Context + public void setSse(final Sse sse) { + this.sse = sse; } protected void addItemFactory(ItemFactory itemFactory) { @@ -123,16 +142,15 @@ public class ReadResource implements EventBroadcaster, RESTResource { * @throws InterruptedException */ @GET - @Produces(SseFeature.SERVER_SENT_EVENTS) + @Produces(MediaType.SERVER_SENT_EVENTS) @ApiOperation(value = "Creates the SSE stream for item states, sends all requested states once and then only changes states") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") }) - public Object getStates(@QueryParam("a") List itemNames, @QueryParam("i") long index, - @QueryParam("t") long time) throws IOException, InterruptedException { - final EventOutput eventOutput = new EventOutput(); + public void getStates(@Context final SseEventSink sseEventSink, @QueryParam("a") List itemNames, + @QueryParam("i") long index, @QueryParam("t") long time) throws IOException, InterruptedException { this.itemNames = itemNames; - broadcaster.add(eventOutput); + broadcaster.add(sseEventSink, new SseSinkInfo(itemNames, index, time)); // get all requested items and send their states to the client items = new HashMap<>(); @@ -175,12 +193,10 @@ public class ReadResource implements EventBroadcaster, RESTResource { } } logger.debug("initially broadcasting {}/{} item states", states.size(), itemNames.size()); - broadcaster.broadcast(SseUtil.buildEvent(states)); + broadcaster.send(SseUtil.buildEvent(sse.newEventBuilder(), states)); } // listen to state changes of the requested items registerItems(); - - return eventOutput; } /** @@ -196,11 +212,9 @@ public class ReadResource implements EventBroadcaster, RESTResource { } /** - * listens to state changes of the given item, if it is part of the - * requested items + * listens to state changes of the given item, if it is part of the requested items * - * @param item - * - the new item, that should be listened to + * @param item the new item, that should be listened to */ @Override public void registerItem(Item item) { @@ -216,8 +230,7 @@ public class ReadResource implements EventBroadcaster, RESTResource { * listens to state changes of the given item, if it is part of the * requested items * - * @param item - * - the new item, that should be listened to + * @param item the new item, that should be listened to */ @Override public void unregisterItem(Item item) { @@ -234,20 +247,23 @@ public class ReadResource implements EventBroadcaster, RESTResource { * Broadcasts an event described by the given parameters to all currently * listening clients. * - * @param item - * - the item which has changed - * @param eventObject - * - bean that can be converted to a JSON object. + * @param item the item which has changed + * @param eventObject bean that can be converted to a JSON object. */ @Override public void broadcastEvent(final Object eventObject) { + if (sse == null) { + logger.trace("broadcast skipped (no one listened since activation)"); + return; + } + executorService.execute(() -> { - broadcaster.broadcast(SseUtil.buildEvent(eventObject)); + broadcaster.send(SseUtil.buildEvent(sse.newEventBuilder(), eventObject)); }); } @Override - public Map> getClientItems(Item item) { + public Map> getClientItems(Item item) { return items.get(item); } } diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/SseSinkInfo.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/SseSinkInfo.java new file mode 100644 index 000000000..235747f75 --- /dev/null +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/SseSinkInfo.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.ui.cometvisu.internal.backend.rest; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The specific information we need to hold for a SSE sink. + * + * @author Wouter Born - Initial contribution + */ +@NonNullByDefault +public class SseSinkInfo { + + public List itemNames; + public long index; + public long time; + + public SseSinkInfo(List itemNames, long index, long time) { + this.itemNames = itemNames; + this.index = index; + this.time = time; + } +} diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/WriteResource.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/WriteResource.java index e610de20c..8796feda5 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/WriteResource.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/backend/rest/WriteResource.java @@ -24,6 +24,7 @@ import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import org.openhab.core.events.EventPublisher; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.core.items.Item; import org.openhab.core.items.ItemNotFoundException; @@ -35,6 +36,11 @@ import org.openhab.ui.cometvisu.internal.Config; import org.openhab.ui.cometvisu.internal.backend.model.SuccessBean; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,8 +54,13 @@ import io.swagger.annotations.ApiResponses; * handles state updates send by the CometVisu client and forwars them to the EventPublisher * * @author Tobias Bräutigam - Initial contribution + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_WRITE_ALIAS) +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @Path(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_WRITE_ALIAS) @Api(Config.COMETVISU_BACKEND_ALIAS + "/" + Config.COMETVISU_BACKEND_WRITE_ALIAS) public class WriteResource implements RESTResource { diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/listeners/StateEventListener.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/listeners/StateEventListener.java index 4e35dbd54..d31e14c59 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/listeners/StateEventListener.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/listeners/StateEventListener.java @@ -30,6 +30,10 @@ public class StateEventListener implements StateChangeListener { private EventBroadcaster eventBroadcaster; + public StateEventListener(EventBroadcaster eventBroadcaster) { + this.eventBroadcaster = eventBroadcaster; + } + public void setEventBroadcaster(EventBroadcaster eventBroadcaster) { this.eventBroadcaster = eventBroadcaster; } diff --git a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/util/SseUtil.java b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/util/SseUtil.java index 5cb6cbb32..d828e3b84 100644 --- a/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/util/SseUtil.java +++ b/bundles/org.openhab.ui.cometvisu/src/main/java/org/openhab/ui/cometvisu/internal/util/SseUtil.java @@ -15,8 +15,9 @@ package org.openhab.ui.cometvisu.internal.util; import java.util.Date; import javax.ws.rs.core.MediaType; +import javax.ws.rs.sse.OutboundSseEvent; -import org.glassfish.jersey.media.sse.OutboundEvent; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.ui.cometvisu.internal.StateBeanMessageBodyWriter; import org.openhab.ui.cometvisu.internal.backend.model.StateBean; @@ -24,8 +25,9 @@ import org.openhab.ui.cometvisu.internal.backend.model.StateBean; * Utility class containing helper methods for the SSE implementation. * * @author Tobias Bräutigam - Initial Contribution and API - * + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ +@NonNullByDefault public class SseUtil { /** @@ -33,29 +35,23 @@ public class SseUtil { * {@link StateBean} created for the given eventType, objectIdentifier, * eventObject. * - * @param eventType - * - the event type for the event - * @param objectIdentifier - * - the identifier for the main event object - * @param eventObject - * - the eventObject to be included - * @return a new OutboundEvent. + * @param eventType the event type for the event + * @param objectIdentifier the identifier for the main event object + * @param eventObject the eventObject to be included + * @return a new OutboundSseEvent */ - public static OutboundEvent buildEvent(Object eventObject) { - OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder(); + public static OutboundSseEvent buildEvent(OutboundSseEvent.Builder eventBuilder, Object eventObject) { StateBeanMessageBodyWriter writer = new StateBeanMessageBodyWriter(); Date date = new Date(); - OutboundEvent event = eventBuilder.mediaType(MediaType.APPLICATION_JSON_TYPE) - .data(writer.serialize(eventObject)).id(String.valueOf(date.getTime())).build(); - - return event; + return eventBuilder.mediaType(MediaType.APPLICATION_JSON_TYPE).data(writer.serialize(eventObject)) + .id(String.valueOf(date.getTime())).build(); } /** * Used to mark our current thread(request processing) that SSE blocking * should be enabled. */ - private static ThreadLocal blockingSseEnabled = new ThreadLocal() { + private static ThreadLocal blockingSseEnabled = new ThreadLocal<>() { @Override protected Boolean initialValue() { return false; diff --git a/bundles/org.openhab.ui.habot/src/main/java/org/openhab/ui/habot/rest/internal/HABotResource.java b/bundles/org.openhab.ui.habot/src/main/java/org/openhab/ui/habot/rest/internal/HABotResource.java index 9547e43f0..b0b3b627a 100644 --- a/bundles/org.openhab.ui.habot/src/main/java/org/openhab/ui/habot/rest/internal/HABotResource.java +++ b/bundles/org.openhab.ui.habot/src/main/java/org/openhab/ui/habot/rest/internal/HABotResource.java @@ -38,6 +38,7 @@ import javax.ws.rs.core.Response.Status; import org.eclipse.jdt.annotation.NonNull; import org.openhab.core.auth.Role; import org.openhab.core.io.rest.LocaleService; +import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.core.voice.VoiceManager; import org.openhab.core.voice.text.InterpretationException; @@ -54,6 +55,11 @@ import org.osgi.service.component.annotations.Component; 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.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,8 +75,13 @@ import io.swagger.annotations.ApiResponses; * This class describes the /habot resource of the REST API. * * @author Yannick Schaus - Initial contribution + * @author Wouter Born - Migrated to JAX-RS Whiteboard Specification */ @Component +@JaxrsResource +@JaxrsName(HABotResource.PATH_HABOT) +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") +@JSONRequired @RolesAllowed({ Role.USER, Role.ADMIN }) @Path(HABotResource.PATH_HABOT) @Api(HABotResource.PATH_HABOT) diff --git a/bundles/org.openhab.ui/.classpath b/bundles/org.openhab.ui/.classpath index a31748559..4f0c23319 100644 --- a/bundles/org.openhab.ui/.classpath +++ b/bundles/org.openhab.ui/.classpath @@ -6,23 +6,6 @@ - - - - - - - - - - - - - - - - - @@ -33,14 +16,15 @@ - + - + - + + diff --git a/bundles/org.openhab.ui/src/main/java/org/openhab/ui/internal/UIService.java b/bundles/org.openhab.ui/src/main/java/org/openhab/ui/internal/UIService.java index 953df27d6..93af7dd69 100644 --- a/bundles/org.openhab.ui/src/main/java/org/openhab/ui/internal/UIService.java +++ b/bundles/org.openhab.ui/src/main/java/org/openhab/ui/internal/UIService.java @@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory; * * @author Yannick Schaus - Initial contribution */ -@Component(immediate = true, name = "org.openhab.ui") +@Component(immediate = true, name = "org.openhab.ui", property = { "httpContext.id:String=oh-ui-http-ctx" }) public class UIService implements HttpContext { private static final String APP_BASE = "app"; diff --git a/features/src/main/feature/feature.xml b/features/src/main/feature/feature.xml index e200177a9..841909147 100644 --- a/features/src/main/feature/feature.xml +++ b/features/src/main/feature/feature.xml @@ -32,7 +32,6 @@ openhab-core-ui openhab.tp-jaxb openhab.tp-jackson - openhab.tp-kat.cpy-jersey-min-2.22.2 mvn:org.rrd4j/rrd4j/3.4 mvn:org.openhab.ui.bundles/org.openhab.ui.cometvisu/${project.version} @@ -89,7 +88,7 @@ openhab-core-ui - openhab.tp-swagger-jax-rs-provider + openhab-core-io-rest-swagger mvn:org.openhab.ui.bundles/org.openhab.ui.restdocs/${project.version}