Migrate to JAX-RS Whiteboard (#242)

* Update REST Docs feature dependency
* Annotate habot for whiteboard
* Fix default UI classpath, fix null context ID warning
* Annotate cometvisu for whiteboard

Signed-off-by: Wouter Born <github@maindrain.net>
pull/249/head
Wouter Born 2020-05-15 14:03:44 +02:00 committed by GitHub
parent e624727564
commit aa05fab9d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 372 additions and 533 deletions

View File

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.ui.bundles</groupId>
<artifactId>org.openhab.ui.reactor.bundles</artifactId>
<version>2.5.0</version>
</parent>
<artifactId>org.openhab.ui.cometvisu.php</artifactId>
<name>openHAB UI :: Bundles :: CometVisu :: PHP Support</name>
<dependencies>
<dependency>
<groupId>org.openhab</groupId>
<artifactId>com.caucho.quercus</artifactId>
<version>4.0.45</version>
</dependency>
<dependency>
<groupId>org.openhab.ui.bundles</groupId>
<artifactId>org.openhab.ui.cometvisu</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.ui.bundles</groupId>
<artifactId>org.openhab.ui.dashboard</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.model.sitemap</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.ui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.ui.icon</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -28,19 +28,16 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src/gen/java">
<attributes>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/classes" path="src-gen">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1,2 +0,0 @@
Bundle-SymbolicName: ${project.artifactId}
Bundle-Activator: org.openhab.ui.cometvisu.internal.CvActivator

View File

@ -68,11 +68,6 @@
<artifactId>jackson-annotations</artifactId>
<version>2.9.10</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.22.2</version>
</dependency>
</dependencies>
<build>

View File

@ -1,100 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.ui.bundles</groupId>
<artifactId>org.openhab.ui.reactor.bundles</artifactId>
<version>2.5.0</version>
</parent>
<artifactId>org.openhab.ui.cometvisu</artifactId>
<name>openHAB UI :: Bundles :: CometVisu :: Backend</name>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.ui.bundles</groupId>
<artifactId>org.openhab.ui.dashboard</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.model.sitemap</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.ui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.ui.icon</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.rrd4j</groupId>
<artifactId>rrd4j</artifactId>
<version>3.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<generatedSourcesDirectory>src/gen/java</generatedSourcesDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- The package of your generated sources -->
<packageName>org.openhab.ui.cometvisu.internal.config.beans</packageName>
<sources>
<source>src/main/resources/visu_config.xsd</source>
</sources>
<outputDirectory>src/gen/java</outputDirectory>
<locale>en</locale>
<clearOutputDir>false</clearOutputDir>
<generateEpisode>false</generateEpisode>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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!");
}
}
}
}

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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);

View File

@ -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 {

View File

@ -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<String, Class<? extends State>> getClientItems(Item item);
public Map<String, @Nullable Class<? extends State>> getClientItems(Item item);
}

View File

@ -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);

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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<String, List<Object>> {
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<Object> list = get(name);
return (list != null) ? (String) get(name).get(0) : null;
}
public File getFileParameter(String name) {
List<Object> 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 <T> void putMulti(final String key, final T value) {
List<Object> values = super.get(key);
if (values == null) {
values = new ArrayList<>();
values.add(value);
put(key, values);
} else {
values.add(value);
}
}
}

View File

@ -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<SseSinkInfo> 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<String> itemNames = new ArrayList<>();
private Map<Item, Map<String, Class<? extends State>>> items = new HashMap<>();
private Map<Item, Map<String, @Nullable Class<? extends State>>> 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<ItemFactory> 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<String> 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<String> 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<String, Class<? extends State>> getClientItems(Item item) {
public Map<String, @Nullable Class<? extends State>> getClientItems(Item item) {
return items.get(item);
}
}

View File

@ -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<String> itemNames;
public long index;
public long time;
public SseSinkInfo(List<String> itemNames, long index, long time) {
this.itemNames = itemNames;
this.index = index;
this.time = time;
}
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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<Boolean> blockingSseEnabled = new ThreadLocal<Boolean>() {
private static ThreadLocal<Boolean> blockingSseEnabled = new ThreadLocal<>() {
@Override
protected Boolean initialValue() {
return false;

View File

@ -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)

View File

@ -6,23 +6,6 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="web">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
@ -33,14 +16,15 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<classpathentry excluding="**" kind="src" output="target/classes" path="web/www">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>

View File

@ -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";

View File

@ -32,7 +32,6 @@
<feature>openhab-core-ui</feature>
<feature dependency="true">openhab.tp-jaxb</feature>
<feature dependency="true">openhab.tp-jackson</feature>
<feature dependency="true">openhab.tp-kat.cpy-jersey-min-2.22.2</feature>
<bundle dependency="true">mvn:org.rrd4j/rrd4j/3.4</bundle>
<bundle>mvn:org.openhab.ui.bundles/org.openhab.ui.cometvisu/${project.version}</bundle>
<config name="cometvisu">
@ -89,7 +88,7 @@
<feature name="openhab-ui-restdocs" description="REST Documentation" version="${project.version}">
<feature>openhab-core-ui</feature>
<feature>openhab.tp-swagger-jax-rs-provider</feature>
<feature>openhab-core-io-rest-swagger</feature>
<bundle>mvn:org.openhab.ui.bundles/org.openhab.ui.restdocs/${project.version}</bundle>
</feature>