[REST] Fix API to get file format when applied to a subset of elements (#4786)

Fix #4778

Things and items are now sorted in output only when all elements are requested.
If the API is requested only for a subset of elements (things or items), the output respects the input order of elements.

DSL generator for things and items is also fixed to avoid a crash when called with 0 element.

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
pull/4779/head
lolodomo 2025-05-06 20:16:24 +02:00 committed by GitHub
parent 3fb76c9fae
commit 8d3c3575a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 18 additions and 10 deletions

View File

@ -249,9 +249,9 @@ public class FileFormatResource implements RESTResource {
return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE) return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE)
.entity("Unsupported media type '" + acceptHeader + "'!").build(); .entity("Unsupported media type '" + acceptHeader + "'!").build();
} }
Collection<Item> items = null; List<Item> items;
if (itemNames == null || itemNames.isEmpty()) { if (itemNames == null || itemNames.isEmpty()) {
items = itemRegistry.getAll(); items = getAllItemsSorted();
} else { } else {
items = new ArrayList<>(); items = new ArrayList<>();
for (String itemname : itemNames) { for (String itemname : itemNames) {
@ -264,7 +264,7 @@ public class FileFormatResource implements RESTResource {
} }
} }
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
generator.generateFileFormat(outputStream, sortItems(items), getMetadata(items), hideDefaultParameters); generator.generateFileFormat(outputStream, items, getMetadata(items), hideDefaultParameters);
return Response.ok(new String(outputStream.toByteArray())).build(); return Response.ok(new String(outputStream.toByteArray())).build();
} }
@ -290,9 +290,9 @@ public class FileFormatResource implements RESTResource {
return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE) return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE)
.entity("Unsupported media type '" + acceptHeader + "'!").build(); .entity("Unsupported media type '" + acceptHeader + "'!").build();
} }
Collection<Thing> things = null; List<Thing> things;
if (thingUIDs == null || thingUIDs.isEmpty()) { if (thingUIDs == null || thingUIDs.isEmpty()) {
things = thingRegistry.getAll(); things = getAllThingsSorted();
} else { } else {
try { try {
things = getThingsOrDiscoveryResult(thingUIDs); things = getThingsOrDiscoveryResult(thingUIDs);
@ -301,7 +301,7 @@ public class FileFormatResource implements RESTResource {
} }
} }
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
generator.generateFileFormat(outputStream, sortThings(things), hideDefaultParameters); generator.generateFileFormat(outputStream, things, hideDefaultParameters);
return Response.ok(new String(outputStream.toByteArray())).build(); return Response.ok(new String(outputStream.toByteArray())).build();
} }
@ -326,14 +326,15 @@ public class FileFormatResource implements RESTResource {
} }
/* /*
* Sort the items in such a way: * Get all items from registry sorted in such a way:
* - group items are before non group items * - group items are before non group items
* - group items are sorted to have as much as possible ancestors before their children * - group items are sorted to have as much as possible ancestors before their children
* - items not linked to a channel are before items linked to a channel * - items not linked to a channel are before items linked to a channel
* - items linked to a channel are grouped by thing UID * - items linked to a channel are grouped by thing UID
* - items linked to the same thing UID are sorted by item name * - items linked to the same thing UID are sorted by item name
*/ */
private List<Item> sortItems(Collection<Item> items) { private List<Item> getAllItemsSorted() {
Collection<Item> items = itemRegistry.getAll();
List<Item> groups = items.stream().filter(item -> item instanceof GroupItem).sorted((item1, item2) -> { List<Item> groups = items.stream().filter(item -> item instanceof GroupItem).sorted((item1, item2) -> {
return item1.getName().compareTo(item2.getName()); return item1.getName().compareTo(item2.getName());
}).toList(); }).toList();
@ -387,12 +388,13 @@ public class FileFormatResource implements RESTResource {
} }
/* /*
* Sort the things in such a way: * Get all things from registry sorted in such a way:
* - things are grouped by binding, sorted by natural order of binding name * - things are grouped by binding, sorted by natural order of binding name
* - all things of a binding are sorted to follow the tree, that is bridge thing is before its sub-things * - all things of a binding are sorted to follow the tree, that is bridge thing is before its sub-things
* - all things of a binding at a certain tree depth are sorted by thing UID * - all things of a binding at a certain tree depth are sorted by thing UID
*/ */
private List<Thing> sortThings(Collection<Thing> things) { private List<Thing> getAllThingsSorted() {
Collection<Thing> things = thingRegistry.getAll();
List<Thing> thingTree = new ArrayList<>(); List<Thing> thingTree = new ArrayList<>();
Set<String> bindings = things.stream().map(thing -> thing.getUID().getBindingId()).collect(Collectors.toSet()); Set<String> bindings = things.stream().map(thing -> thing.getUID().getBindingId()).collect(Collectors.toSet());
for (String binding : bindings.stream().sorted().toList()) { for (String binding : bindings.stream().sorted().toList()) {

View File

@ -82,6 +82,9 @@ public class DslItemFileConverter extends AbstractItemFileGenerator {
@Override @Override
public synchronized void generateFileFormat(OutputStream out, List<Item> items, Collection<Metadata> metadata, public synchronized void generateFileFormat(OutputStream out, List<Item> items, Collection<Metadata> metadata,
boolean hideDefaultParameters) { boolean hideDefaultParameters) {
if (items.isEmpty()) {
return;
}
ItemModel model = ItemsFactory.eINSTANCE.createItemModel(); ItemModel model = ItemsFactory.eINSTANCE.createItemModel();
for (Item item : items) { for (Item item : items) {
model.getItems().add(buildModelItem(item, getChannelLinks(metadata, item.getName()), model.getItems().add(buildModelItem(item, getChannelLinks(metadata, item.getName()),

View File

@ -76,6 +76,9 @@ public class DslThingFileConverter extends AbstractThingFileGenerator {
@Override @Override
public synchronized void generateFileFormat(OutputStream out, List<Thing> things, boolean hideDefaultParameters) { public synchronized void generateFileFormat(OutputStream out, List<Thing> things, boolean hideDefaultParameters) {
if (things.isEmpty()) {
return;
}
ThingModel model = ThingFactory.eINSTANCE.createThingModel(); ThingModel model = ThingFactory.eINSTANCE.createThingModel();
Set<Thing> handledThings = new HashSet<>(); Set<Thing> handledThings = new HashSet<>();
for (Thing thing : things) { for (Thing thing : things) {