Skip to content

Commit c67044f

Browse files
committed
Add optional item state formatters
Signed-off-by: Laurent Garnier <lg.hc@free.fr>
1 parent 73f12a3 commit c67044f

8 files changed

Lines changed: 68 additions & 23 deletions

File tree

bundles/org.openhab.core.io.rest.core/src/main/java/org/openhab/core/io/rest/core/fileformat/FileFormatItemDTO.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public class FileFormatItemDTO extends ItemDTO {
2929

3030
public String groupType;
3131
public GroupFunctionDTO function;
32+
public String format;
3233
public Map<String, MetadataDTO> metadata;
3334
public List<FileFormatChannelLinkDTO> channelLinks;
3435

bundles/org.openhab.core.io.rest.core/src/main/java/org/openhab/core/io/rest/core/fileformat/FileFormatItemDTOMapper.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,17 @@ public class FileFormatItemDTOMapper {
4646
*
4747
* @param item the item
4848
* @param metadata some metadata
49+
* @param format the format to be used to format the item state, can be NULL
4950
* @param channelLinks some items channel links
5051
* @return file format item DTO object
5152
*/
52-
public static FileFormatItemDTO map(Item item, Collection<Metadata> metadata,
53+
public static FileFormatItemDTO map(Item item, Collection<Metadata> metadata, @Nullable String format,
5354
Collection<ItemChannelLink> channelLinks) {
5455
ItemDTO itemDto = ItemDTOMapper.map(item);
5556
FileFormatItemDTO dto = new FileFormatItemDTO(itemDto, itemDto instanceof GroupItemDTO);
5657

58+
dto.format = format;
59+
5760
Map<String, MetadataDTO> metadataDTO = new LinkedHashMap<>();
5861
metadata.forEach(md -> {
5962
if (item.getName().equals(md.getUID().getItemName())) {

bundles/org.openhab.core.io.rest.core/src/main/java/org/openhab/core/io/rest/core/internal/fileformat/FileFormatResource.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
import org.openhab.core.thing.type.ThingType;
8888
import org.openhab.core.thing.type.ThingTypeRegistry;
8989
import org.openhab.core.thing.util.ThingHelper;
90+
import org.openhab.core.types.StateDescription;
9091
import org.osgi.service.component.annotations.Activate;
9192
import org.osgi.service.component.annotations.Component;
9293
import org.osgi.service.component.annotations.Deactivate;
@@ -316,7 +317,15 @@ public Response createFileFormatForItems(final @Context HttpHeaders httpHeaders,
316317
}
317318
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
318319
String genId = GEN_ID_PATTERN.formatted(++counter);
319-
generator.setItemsToBeGenerated(genId, items, getMetadata(items), hideDefaultParameters);
320+
Map<String, String> stateFormatters = new HashMap<>();
321+
items.forEach(item -> {
322+
StateDescription stateDescr = item.getStateDescription();
323+
String format = stateDescr == null ? null : stateDescr.getPattern();
324+
if (format != null) {
325+
stateFormatters.put(item.getName(), format);
326+
}
327+
});
328+
generator.setItemsToBeGenerated(genId, items, getMetadata(items), stateFormatters, hideDefaultParameters);
320329
generator.generateFileFormat(genId, outputStream);
321330
return Response.ok(new String(outputStream.toByteArray())).build();
322331
}
@@ -384,8 +393,9 @@ public Response create(final @Context HttpHeaders httpHeaders,
384393
List<Thing> things = new ArrayList<>();
385394
List<Item> items = new ArrayList<>();
386395
List<Metadata> metadata = new ArrayList<>();
396+
Map<String, String> stateFormatters = new HashMap<>();
387397
List<String> errors = new ArrayList<>();
388-
if (!convertFromFileFormatDTO(data, things, items, metadata, errors)) {
398+
if (!convertFromFileFormatDTO(data, things, items, metadata, stateFormatters, errors)) {
389399
return Response.status(Response.Status.BAD_REQUEST).entity(String.join("\n", errors)).build();
390400
}
391401

@@ -412,7 +422,7 @@ public Response create(final @Context HttpHeaders httpHeaders,
412422
return Response.status(Response.Status.BAD_REQUEST).entity("No item loaded from input").build();
413423
}
414424
itemGenerator.setItemsToBeGenerated(genId, items, hideChannelLinksAndMetadata ? List.of() : metadata,
415-
hideDefaultParameters);
425+
stateFormatters, hideDefaultParameters);
416426
itemGenerator.generateFileFormat(genId, outputStream);
417427
break;
418428
case "application/yaml":
@@ -421,7 +431,7 @@ public Response create(final @Context HttpHeaders httpHeaders,
421431
}
422432
if (itemGenerator != null) {
423433
itemGenerator.setItemsToBeGenerated(genId, items,
424-
hideChannelLinksAndMetadata ? List.of() : metadata, hideDefaultParameters);
434+
hideChannelLinksAndMetadata ? List.of() : metadata, stateFormatters, hideDefaultParameters);
425435
}
426436
if (thingGenerator != null) {
427437
thingGenerator.generateFileFormat(genId, outputStream);
@@ -459,6 +469,7 @@ public Response parse(final @Context HttpHeaders httpHeaders,
459469
Collection<Item> items = List.of();
460470
Collection<Metadata> metadata = List.of();
461471
Collection<ItemChannelLink> channelLinks = List.of();
472+
Map<String, String> stateFormatters = Map.of();
462473
List<String> errors = new ArrayList<>();
463474
List<String> warnings = new ArrayList<>();
464475
ThingFileParser thingParser = getThingFileParser(contentTypeHeader);
@@ -496,6 +507,7 @@ public Response parse(final @Context HttpHeaders httpHeaders,
496507
return Response.status(Response.Status.BAD_REQUEST).entity("No item loaded from input").build();
497508
}
498509
metadata = itemParser.getParsedMetadata(modelName2);
510+
stateFormatters = itemParser.getParsedStateFormatters(modelName2);
499511
// We need to go through the thing parser to retrieve the items channel links
500512
// But there is no need to parse again the input
501513
if (thingParser != null) {
@@ -524,13 +536,16 @@ public Response parse(final @Context HttpHeaders httpHeaders,
524536
.getParsedItems(modelName != null ? modelName : Objects.requireNonNull(modelName2));
525537
metadata = itemParser
526538
.getParsedMetadata(modelName != null ? modelName : Objects.requireNonNull(modelName2));
539+
stateFormatters = itemParser.getParsedStateFormatters(
540+
modelName != null ? modelName : Objects.requireNonNull(modelName2));
527541
}
528542
break;
529543
default:
530544
return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE)
531545
.entity("Unsupported content type '" + contentTypeHeader + "'!").build();
532546
}
533-
ExtendedFileFormatDTO result = convertToFileFormatDTO(things, items, metadata, channelLinks, warnings);
547+
ExtendedFileFormatDTO result = convertToFileFormatDTO(things, items, metadata, stateFormatters, channelLinks,
548+
warnings);
534549
if (modelName != null && thingParser != null) {
535550
thingParser.finishParsingFileFormat(modelName);
536551
}
@@ -739,7 +754,7 @@ private List<Thing> getThingsOrDiscoveryResult(List<String> thingUIDs) {
739754
}
740755

741756
private boolean convertFromFileFormatDTO(FileFormatDTO data, List<Thing> things, List<Item> items,
742-
List<Metadata> metadata, List<String> errors) {
757+
List<Metadata> metadata, Map<String, String> stateFormatters, List<String> errors) {
743758
boolean ok = true;
744759
if (data.things != null) {
745760
for (ThingDTO thingBean : data.things) {
@@ -823,13 +838,17 @@ private boolean convertFromFileFormatDTO(FileFormatDTO data, List<Thing> things,
823838
}
824839
items.add(item);
825840
metadata.addAll(FileFormatItemDTOMapper.mapMetadata(itemData));
841+
if (itemData.format != null) {
842+
stateFormatters.put(name, itemData.format);
843+
}
826844
}
827845
}
828846
return ok;
829847
}
830848

831849
private ExtendedFileFormatDTO convertToFileFormatDTO(Collection<Thing> things, Collection<Item> items,
832-
Collection<Metadata> metadata, Collection<ItemChannelLink> channelLinks, List<String> warnings) {
850+
Collection<Metadata> metadata, Map<String, String> stateFormatters,
851+
Collection<ItemChannelLink> channelLinks, List<String> warnings) {
833852
ExtendedFileFormatDTO dto = new ExtendedFileFormatDTO();
834853
dto.warnings = warnings.isEmpty() ? null : warnings;
835854
if (!things.isEmpty()) {
@@ -841,7 +860,8 @@ private ExtendedFileFormatDTO convertToFileFormatDTO(Collection<Thing> things, C
841860
if (!items.isEmpty()) {
842861
dto.items = new ArrayList<>();
843862
items.forEach(item -> {
844-
dto.items.add(FileFormatItemDTOMapper.map(item, metadata, channelLinks));
863+
dto.items.add(
864+
FileFormatItemDTOMapper.map(item, metadata, stateFormatters.get(item.getName()), channelLinks));
845865
});
846866
}
847867
return dto;

bundles/org.openhab.core.model.item/src/org/openhab/core/model/item/internal/GenericItemProvider.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ public Collection<Item> getAllFromModel(String modelName) {
176176
return itemsMap.getOrDefault(modelName, List.of());
177177
}
178178

179+
public Map<String, String> getStateFormattezrsFromModel(String modelName) {
180+
// TODO to implement
181+
return Map.of();
182+
}
183+
179184
private Collection<Item> getItemsFromModel(String modelName) {
180185
logger.debug("Read items from model '{}'", modelName);
181186

@@ -538,7 +543,6 @@ private Map<String, Item> toItemMap(@Nullable Collection<Item> items) {
538543

539544
@Override
540545
public @Nullable StateDescriptionFragment getStateDescriptionFragment(String itemName, @Nullable Locale locale) {
541-
// FIXME: what to do for isolated models to not override data for items in item registry ?
542546
return stateDescriptionFragments.get(itemName);
543547
}
544548
}

bundles/org.openhab.core.model.item/src/org/openhab/core/model/item/internal/fileconverter/DslItemFileConverter.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
import org.openhab.core.model.items.ModelItem;
5151
import org.openhab.core.model.items.ModelProperty;
5252
import org.openhab.core.types.State;
53-
import org.openhab.core.types.StateDescription;
5453
import org.osgi.service.component.annotations.Activate;
5554
import org.osgi.service.component.annotations.Component;
5655
import org.osgi.service.component.annotations.Reference;
@@ -94,14 +93,14 @@ public String getFileFormatGenerator() {
9493

9594
@Override
9695
public void setItemsToBeGenerated(String id, List<Item> items, Collection<Metadata> metadata,
97-
boolean hideDefaultParameters) {
96+
Map<String, String> stateFormatters, boolean hideDefaultParameters) {
9897
if (items.isEmpty()) {
9998
return;
10099
}
101100
ItemModel model = ItemsFactory.eINSTANCE.createItemModel();
102101
for (Item item : items) {
103102
model.getItems().add(buildModelItem(item, getChannelLinks(metadata, item.getName()),
104-
getMetadata(metadata, item.getName()), hideDefaultParameters));
103+
getMetadata(metadata, item.getName()), stateFormatters, hideDefaultParameters));
105104
}
106105
elementsToGenerate.put(id, model);
107106
}
@@ -115,7 +114,7 @@ public void generateFileFormat(String id, OutputStream out) {
115114
}
116115

117116
private ModelItem buildModelItem(Item item, List<Metadata> channelLinks, List<Metadata> metadata,
118-
boolean hideDefaultParameters) {
117+
Map<String, String> stateFormatters, boolean hideDefaultParameters) {
119118
ModelItem model;
120119
if (item instanceof GroupItem groupItem) {
121120
ModelGroupItem modelGroup = ItemsFactory.eINSTANCE.createModelGroupItem();
@@ -144,8 +143,7 @@ private ModelItem buildModelItem(Item item, List<Metadata> channelLinks, List<Me
144143
boolean patternInjected = false;
145144
String defaultPattern = getDefaultStatePattern(item);
146145
if (label != null && !label.isEmpty()) {
147-
StateDescription stateDescr = item.getStateDescription();
148-
String statePattern = stateDescr == null ? null : stateDescr.getPattern();
146+
String statePattern = stateFormatters.get(item.getName());
149147
String patterToInject = statePattern != null && !statePattern.equals(defaultPattern) ? statePattern : null;
150148
if (patterToInject != null) {
151149
// Inject the pattern in the label
@@ -322,6 +320,11 @@ public Collection<Metadata> getParsedMetadata(String modelName) {
322320
return metadataProvider.getAllFromModel(modelName);
323321
}
324322

323+
@Override
324+
public Map<String, String> getParsedStateFormatters(String modelName) {
325+
return itemProvider.getStateFormattezrsFromModel(modelName);
326+
}
327+
325328
@Override
326329
public void finishParsingFileFormat(String modelName) {
327330
modelRepository.removeModel(modelName);

bundles/org.openhab.core.model.yaml/src/main/java/org/openhab/core/model/yaml/internal/items/fileconverter/YamlItemFileConverter.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
import org.openhab.core.model.yaml.internal.items.YamlMetadataDTO;
5252
import org.openhab.core.model.yaml.internal.items.YamlMetadataProvider;
5353
import org.openhab.core.types.State;
54-
import org.openhab.core.types.StateDescription;
5554
import org.osgi.service.component.annotations.Activate;
5655
import org.osgi.service.component.annotations.Component;
5756
import org.osgi.service.component.annotations.Reference;
@@ -91,11 +90,11 @@ public String getFileFormatGenerator() {
9190

9291
@Override
9392
public void setItemsToBeGenerated(String id, List<Item> items, Collection<Metadata> metadata,
94-
boolean hideDefaultParameters) {
93+
Map<String, String> stateFormatters, boolean hideDefaultParameters) {
9594
List<YamlElement> elements = new ArrayList<>();
9695
items.forEach(item -> {
9796
elements.add(buildItemDTO(item, getChannelLinks(metadata, item.getName()),
98-
getMetadata(metadata, item.getName()), hideDefaultParameters));
97+
getMetadata(metadata, item.getName()), stateFormatters, hideDefaultParameters));
9998
});
10099
modelRepository.addElementsToBeGenerated(id, elements);
101100
}
@@ -106,7 +105,7 @@ public void generateFileFormat(String id, OutputStream out) {
106105
}
107106

108107
private YamlItemDTO buildItemDTO(Item item, List<Metadata> channelLinks, List<Metadata> metadata,
109-
boolean hideDefaultParameters) {
108+
Map<String, String> stateFormatters, boolean hideDefaultParameters) {
110109
YamlItemDTO dto = new YamlItemDTO();
111110
dto.name = item.getName();
112111

@@ -115,8 +114,7 @@ private YamlItemDTO buildItemDTO(Item item, List<Metadata> channelLinks, List<Me
115114
String defaultPattern = getDefaultStatePattern(item);
116115
if (label != null && !label.isEmpty()) {
117116
dto.label = item.getLabel();
118-
StateDescription stateDescr = item.getStateDescription();
119-
String statePattern = stateDescr == null ? null : stateDescr.getPattern();
117+
String statePattern = stateFormatters.get(item.getName());
120118
String patterToSet = statePattern != null && !statePattern.equals(defaultPattern) ? statePattern : null;
121119
dto.format = patterToSet;
122120
patternSet = patterToSet != null;
@@ -291,6 +289,11 @@ public Collection<Metadata> getParsedMetadata(String modelName) {
291289
return metadataProvider.getAllFromModel(modelName);
292290
}
293291

292+
@Override
293+
public Map<String, String> getParsedStateFormatters(String modelName) {
294+
return Map.of();
295+
}
296+
294297
@Override
295298
public void finishParsingFileFormat(String modelName) {
296299
modelRepository.removeIsolatedModel(modelName);

bundles/org.openhab.core/src/main/java/org/openhab/core/items/fileconverter/ItemFileGenerator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.io.OutputStream;
1616
import java.util.Collection;
1717
import java.util.List;
18+
import java.util.Map;
1819

1920
import org.eclipse.jdt.annotation.NonNullByDefault;
2021
import org.openhab.core.items.Item;
@@ -42,10 +43,11 @@ public interface ItemFileGenerator {
4243
* @param id the identifier of the file format generation
4344
* @param items the items
4445
* @param metadata the provided collection of metadata for these items (including channel links)
46+
* @param stateFormatters the optional state formatter for each item
4547
* @param hideDefaultParameters true to hide the configuration parameters having the default value
4648
*/
4749
void setItemsToBeGenerated(String id, List<Item> items, Collection<Metadata> metadata,
48-
boolean hideDefaultParameters);
50+
Map<String, String> stateFormatters, boolean hideDefaultParameters);
4951

5052
/**
5153
* Generate the file format for all data that were associated to the provided identifier.

bundles/org.openhab.core/src/main/java/org/openhab/core/items/fileconverter/ItemFileParser.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import java.util.Collection;
1616
import java.util.List;
17+
import java.util.Map;
1718

1819
import org.eclipse.jdt.annotation.NonNullByDefault;
1920
import org.eclipse.jdt.annotation.Nullable;
@@ -62,6 +63,14 @@ public interface ItemFileParser {
6263
*/
6364
Collection<Metadata> getParsedMetadata(String modelName);
6465

66+
/**
67+
* Get the state formatters found when parsing the file format.
68+
*
69+
* @param modelName the model name used for parsing
70+
* @return the state formatters as a Map per item name
71+
*/
72+
Map<String, String> getParsedStateFormatters(String modelName);
73+
6574
/**
6675
* Release the data from a previously started file format parsing.
6776
*

0 commit comments

Comments
 (0)