Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bundles/org.openhab.core.io.rest.core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
<artifactId>org.openhab.core.persistence</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.sitemap</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.config.discovery</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.util.List;

import org.openhab.core.sitemap.dto.SitemapDefinitionDTO;
import org.openhab.core.thing.dto.ThingDTO;

import io.swagger.v3.oas.annotations.media.Schema;
Expand All @@ -23,6 +24,7 @@
* in a file format (items, things, ...).
*
* @author Laurent Garnier - Initial contribution
* @author Mark Herwege - Add sitemaps
*/
@Schema(name = "FileFormat")
public class FileFormatDTO {
Expand All @@ -31,4 +33,6 @@ public class FileFormatDTO {
public List<FileFormatItemDTO> items;
@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED)
public List<ThingDTO> things;
@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED)
public List<SitemapDefinitionDTO> sitemaps;
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,19 @@
*/
package org.openhab.core.io.rest.sitemap.internal;

import org.openhab.core.sitemap.dto.AbstractSitemapDTO;

import io.swagger.v3.oas.annotations.media.Schema;

/**
* This is a data transfer object that is used to serialize sitemaps.
*
*
* @author Kai Kreuzer - Initial contribution
* @author Chris Jackson - Initial contribution
* @author Mark Herwege - Moved to abstract class and extend
*/
@Schema(name = "Sitemap")
public class SitemapDTO {

public String name;
public String icon;
public String label;
public class SitemapDTO extends AbstractSitemapDTO {

public String link;

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
*/
package org.openhab.core.io.rest.sitemap.internal;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.openhab.core.io.rest.core.item.EnrichedItemDTO;
import org.openhab.core.sitemap.dto.AbstractWidgetDTO;

import io.swagger.v3.oas.annotations.media.Schema;

Expand All @@ -31,56 +31,22 @@
* @author Danny Baumann - New field labelSource
* @author Laurent Garnier - Remove field columns
* @author Laurent Garnier - New fields row, column, command, releaseCommand and stateless for Button element
* @author Mark Herwege - Extends abstract widget DTO
*/
@Schema(name = "Widget")
public class WidgetDTO {
public class WidgetDTO extends AbstractWidgetDTO {

public String widgetId;
public String type;
public String name;
public boolean visibility;

public String label;
public String labelSource;
public String icon;
/**
* staticIcon is a boolean indicating if the widget state must be ignored when requesting the icon.
* It is set to true when the widget has either the staticIcon property set or the icon property set
* with conditional rules.
*/
public Boolean staticIcon;

public String labelcolor;
public String valuecolor;
public String iconcolor;

public String pattern;
public String unit;

// widget-specific attributes
public final List<MappingDTO> mappings = new ArrayList<>();
public Boolean switchSupport;
public Boolean releaseOnly;
public Integer refresh;
public Integer height;
public BigDecimal minValue;
public BigDecimal maxValue;
public BigDecimal step;
public String inputHint;
public String url;
public String encoding;
public String service;
public String period;
public String yAxisDecimalPattern;
public String interpolation;
public Boolean legend;
public Boolean forceAsItem;
public Integer row;
public Integer column;
public String command;
public String releaseCommand;
public Boolean stateless;
public String state;

public EnrichedItemDTO item;
public PageDTO linkedPage;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

import java.util.ArrayList;
Expand Down Expand Up @@ -52,10 +53,14 @@
import org.openhab.core.sitemap.Rule;
import org.openhab.core.sitemap.Sitemap;
import org.openhab.core.sitemap.Widget;
import org.openhab.core.sitemap.dto.SitemapDefinitionDTO;
import org.openhab.core.sitemap.internal.SitemapImpl;
import org.openhab.core.sitemap.registry.SitemapFactory;
import org.openhab.core.sitemap.registry.SitemapRegistry;
import org.openhab.core.test.java.JavaTest;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.ui.components.ManagedSitemapProvider;
import org.openhab.core.ui.items.ItemUIRegistry;
import org.openhab.core.ui.items.ItemUIRegistry.WidgetLabelSource;
import org.osgi.framework.BundleContext;
Expand Down Expand Up @@ -116,7 +121,9 @@ public class SitemapResourceTest extends JavaTest {
private @Mock @NonNullByDefault({}) TimeZoneProvider timeZoneProviderMock;
private @Mock @NonNullByDefault({}) LocaleService localeServiceMock;
private @Mock @NonNullByDefault({}) HttpServletRequest requestMock;
private @Mock @NonNullByDefault({}) SitemapFactory sitemapFactory;
private @Mock @NonNullByDefault({}) SitemapRegistry sitemapRegistryMock;
private @Mock @NonNullByDefault({}) ManagedSitemapProvider managedSitemapProviderMock;
private @Mock @NonNullByDefault({}) UriInfo uriInfoMock;
private @Mock @NonNullByDefault({}) BundleContext bundleContextMock;

Expand All @@ -127,8 +134,8 @@ public void setup() throws Exception {
subscriptions = new SitemapSubscriptionService(Collections.emptyMap(), itemUIRegistryMock, sitemapRegistryMock,
timeZoneProviderMock, bundleContextMock);

sitemapResource = new SitemapResource(itemUIRegistryMock, sitemapRegistryMock, localeServiceMock,
timeZoneProviderMock, subscriptions);
sitemapResource = new SitemapResource(itemUIRegistryMock, sitemapFactory, sitemapRegistryMock,
managedSitemapProviderMock, localeServiceMock, timeZoneProviderMock, subscriptions);

when(uriInfoMock.getAbsolutePathBuilder()).thenReturn(UriBuilder.fromPath(SITEMAP_PATH));
when(uriInfoMock.getBaseUriBuilder()).thenReturn(UriBuilder.fromPath(SITEMAP_PATH));
Expand Down Expand Up @@ -156,6 +163,103 @@ public void setup() throws Exception {
when(headersMock.getRequestHeader(HTTP_HEADER_X_ATMOSPHERE_TRANSPORT)).thenReturn(null);
}

@Test
public void whenGetSitemapsDefinition_shouldSetEditableFlag() {
// sitemapRegistryMock.getAll() already returns Set.of(defaultSitemapMock) via configureSitemapRegistryMock
// This test will have that sitemap be a managed sitemap
when(managedSitemapProviderMock.get(SITEMAP_NAME)).thenReturn(new SitemapImpl(SITEMAP_NAME));

Response resp = sitemapResource.getSitemapsDefinition();
assertThat(resp.getStatus(), is(200));

@SuppressWarnings("unchecked")
List<SitemapDefinitionDTO> body = (List<SitemapDefinitionDTO>) resp.getEntity();
assertThat(body, hasSize(1));
assertThat(body.get(0).name, is(SITEMAP_NAME));
assertThat(body.get(0).editable, is(true));
}

@Test
public void whenGetSitemapDefinition_notFound_shouldReturn404() {
when(sitemapRegistryMock.get("noexist")).thenReturn(null);
Response resp = sitemapResource.getSitemapDefinition(headersMock, "noexist");
assertThat(resp.getStatus(), is(Response.Status.NOT_FOUND.getStatusCode()));
}

@Test
public void whenCreateOrUpdateSitemap_nullBody_shouldReturnBadRequest() {
Object resp = sitemapResource.createOrUpdateSitemap(headersMock, "any", null);
assertThat(((Response) resp).getStatus(), is(Response.Status.BAD_REQUEST.getStatusCode()));
}

@Test
public void whenCreateOrUpdateSitemap_nameMismatch_shouldReturnBadRequest() {
SitemapDefinitionDTO dto = new SitemapDefinitionDTO();
dto.name = "other";
Object resp = sitemapResource.createOrUpdateSitemap(headersMock, "pathName", dto);
assertThat(((Response) resp).getStatus(), is(Response.Status.BAD_REQUEST.getStatusCode()));
}

@Test
public void whenCreateOrUpdateSitemap_createNew_shouldAddManagedSitemap() {
SitemapDefinitionDTO dto = new SitemapDefinitionDTO();
dto.name = "s1";

when(sitemapRegistryMock.get("s1")).thenReturn(null);
when(sitemapFactory.createSitemap("s1")).thenReturn(new SitemapImpl("s1"));

Object respObj = sitemapResource.createOrUpdateSitemap(headersMock, "s1", dto);
Response resp = (Response) respObj;
assertThat(resp.getStatus(), is(Response.Status.CREATED.getStatusCode()));

verify(managedSitemapProviderMock, times(1)).add(any());
}

@Test
public void whenCreateOrUpdateSitemap_updateManaged_shouldUpdateManagedSitemap() {
SitemapDefinitionDTO dto = new SitemapDefinitionDTO();
dto.name = "s2";

when(sitemapRegistryMock.get("s2")).thenReturn(mock(Sitemap.class));
when(managedSitemapProviderMock.get("s2")).thenReturn(mock(Sitemap.class));
when(sitemapFactory.createSitemap("s2")).thenReturn(new SitemapImpl("s2"));

Object respObj = sitemapResource.createOrUpdateSitemap(headersMock, "s2", dto);
Response resp = (Response) respObj;
assertThat(resp.getStatus(), is(Response.Status.OK.getStatusCode()));

verify(managedSitemapProviderMock, times(1)).update(any());
}

@Test
public void whenRemoveSitemap_notFound_shouldReturn404() {
when(sitemapRegistryMock.get("xyz")).thenReturn(null);
Response resp = sitemapResource.removeSitemap("xyz");
assertThat(resp.getStatus(), is(Response.Status.NOT_FOUND.getStatusCode()));
}

@Test
public void whenRemoveSitemap_notManaged_shouldReturnMethodNotAllowed() {
Sitemap sitemap = mock(Sitemap.class);
when(sitemapRegistryMock.get("sdel")).thenReturn(sitemap);
when(managedSitemapProviderMock.remove("sdel")).thenReturn(null);

Response resp = sitemapResource.removeSitemap("sdel");
assertThat(resp.getStatus(), is(Response.Status.METHOD_NOT_ALLOWED.getStatusCode()));
verify(managedSitemapProviderMock, times(1)).remove("sdel");
}

@Test
public void whenRemoveSitemap_managed_shouldReturnOk() {
Sitemap sitemap = mock(Sitemap.class);
when(sitemapRegistryMock.get("sdel2")).thenReturn(sitemap);
when(managedSitemapProviderMock.remove("sdel2")).thenReturn(sitemap);

Response resp = sitemapResource.removeSitemap("sdel2");
assertThat(resp.getStatus(), is(Response.Status.OK.getStatusCode()));
verify(managedSitemapProviderMock, times(1)).remove("sdel2");
}

@Test
public void whenSitemapsAreProvidedShouldReturnSitemapBeans() {
Response sitemaps = sitemapResource.getSitemaps();
Expand Down
1 change: 1 addition & 0 deletions bundles/org.openhab.core.model.sitemap/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Import-Package: org.apache.log4j,\
org.openhab.core.items.dto,\
org.openhab.core.model.core,\
org.openhab.core.sitemap, \
org.openhab.core.sitemap.fileconverter, \
org.openhab.core.sitemap.registry, \
org.eclipse.xtext.xbase.lib,\
org.osgi.framework,\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import org.eclipse.xtext.conversion.IValueConverterService
import org.eclipse.xtext.linking.lazy.LazyURIEncoder
import com.google.inject.Binder
import com.google.inject.name.Names
import org.eclipse.xtext.formatting.IFormatter
import org.openhab.core.model.sitemap.formatting.SitemapFormatter

/**
* Use this class to register components to be used at runtime / without the Equinox extension registry.
Expand All @@ -30,6 +32,10 @@ class SitemapRuntimeModule extends org.openhab.core.model.sitemap.AbstractSitema
return SitemapConverters
}

override Class<? extends IFormatter> bindIFormatter() {
return SitemapFormatter
}

override void configureUseIndexFragmentsForLazyLinking(Binder binder) {
binder.bind(Boolean.TYPE).annotatedWith(Names.named(LazyURIEncoder.USE_INDEXED_FRAGMENTS_BINDING)).toInstance(
Boolean.FALSE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ package org.openhab.core.model.sitemap.formatting

import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter
import org.eclipse.xtext.formatting.impl.FormattingConfig
// import com.google.inject.Inject;
// import org.openhab.core.model.services.SitemapGrammarAccess
import org.openhab.core.model.sitemap.services.SitemapGrammarAccess
import com.google.inject.Inject

/**
* This class contains custom formatting description.
Expand All @@ -30,13 +30,55 @@ import org.eclipse.xtext.formatting.impl.FormattingConfig
*/
class SitemapFormatter extends AbstractDeclarativeFormatter {

// @Inject extension SitemapGrammarAccess

override protected void configureFormatting(FormattingConfig c) {
// It's usually a good idea to activate the following three statements.
// They will add and preserve newlines around comments
// c.setLinewrap(0, 1, 2).before(SL_COMMENTRule)
// c.setLinewrap(0, 1, 2).before(ML_COMMENTRule)
// c.setLinewrap(0, 1, 1).after(ML_COMMENTRule)
}
@Inject extension SitemapGrammarAccess

override protected void configureFormatting(FormattingConfig c) {
c.autoLinewrap = 200

c.setLinewrap(1, 1, 2).before(modelWidgetRule)

c.setIndentationIncrement.after("{")
c.setLinewrap().before("}")
c.setIndentationDecrement.before("}")
c.setLinewrap().after("}")

c.setNoSpace().withinKeywordPairs("[", "]")

c.setNoSpace().after("item=", "label=", "icon=", "staticIcon=")
c.setNoSpace().after("url=", "refresh=", "encoding=", "service=", "period=", "legend=", "forceasitem=", "yAxisDecimalPattern=", "interpolation=", "height=")
c.setNoSpace().after("minValue=", "maxValue=", "step=", "inputHint=", "row=", "column=", "click=", "release=")
c.setNoSpace().after("labelcolor=", "valuecolor=", "iconcolor=", "visibility=", "mappings=", "buttons=")

c.setNoSpace().before(",")
c.setNoSpace().around(":", "=")

c.setLinewrap(0, 1, 2).before(SL_COMMENTRule)
c.setLinewrap(0, 1, 2).before(ML_COMMENTRule)
c.setLinewrap(0, 1, 1).after(ML_COMMENTRule)
}

def withinKeywordPairs(FormattingConfig.NoSpaceLocator locator, String leftKW, String rightKW) {
for (pair : findKeywordPairs(leftKW, rightKW)) {
locator.after(pair.first)
locator.before(pair.second)
}
}

def around(FormattingConfig.ElementLocator locator, String ... listKW) {
for (keyword : findKeywords(listKW)) {
locator.around(keyword)
}
}

def after(FormattingConfig.ElementLocator locator, String ... listKW) {
for (keyword : findKeywords(listKW)) {
locator.after(keyword)
}
}

def before(FormattingConfig.ElementLocator locator, String ... listKW) {
for (keyword : findKeywords(listKW)) {
locator.before(keyword)
}
}
}
Loading
Loading