4747import org .openhab .core .model .item .BindingConfigReader ;
4848import org .openhab .core .model .items .ItemModel ;
4949import org .openhab .core .model .items .ModelBinding ;
50- import org .openhab .core .model .items .ModelGroupFunction ;
51- import org .openhab .core .model .items .ModelGroupItem ;
5250import org .openhab .core .model .items .ModelItem ;
53- import org .openhab .core .model .items .ModelNormalItem ;
5451import org .openhab .core .types .StateDescriptionFragment ;
5552import org .openhab .core .types .StateDescriptionFragmentBuilder ;
5653import org .openhab .core .types .StateDescriptionFragmentProvider ;
@@ -234,62 +231,54 @@ private void processBindingConfigsFromModel(String modelName, EventType type) {
234231 }
235232
236233 private @ Nullable Item createItemFromModelItem (ModelItem modelItem , String modelName ) {
237- Item item ;
238- if (modelItem instanceof ModelGroupItem modelGroupItem ) {
239- Item baseItem ;
240- try {
241- baseItem = createItemOfType (modelGroupItem .getType (), modelGroupItem .getName ());
242- } catch (IllegalArgumentException e ) {
243- logger .debug ("Error creating base item for group item '{}', item will be ignored: {}" ,
244- modelGroupItem .getName (), e .getMessage ());
245- return null ;
246- }
247- if (baseItem != null ) {
248- // if the user did not specify a function the first value of the enum in xtext (EQUAL) will be used
249- ModelGroupFunction function = modelGroupItem .getFunction ();
250- item = applyGroupFunction (baseItem , modelGroupItem , function );
251- } else {
252- item = new GroupItem (modelGroupItem .getName ());
253- }
254- } else {
255- ModelNormalItem normalItem = (ModelNormalItem ) modelItem ;
256- try {
257- item = createItemOfType (normalItem .getType (), normalItem .getName ());
258- } catch (IllegalArgumentException e ) {
259- logger .debug ("Error creating item '{}', item will be ignored: {}" , normalItem .getName (),
260- e .getMessage ());
261- return null ;
262- }
234+ String itemType = modelItem .getType ();
235+ if (itemType == null || itemType .isBlank ()) {
236+ logger .warn ("Item '{}' has no type defined, ignoring it." , modelItem .getName ());
237+ return null ;
263238 }
264- if (item instanceof ActiveItem activeItem ) {
265- String label = modelItem .getLabel ();
266- String format = extractFormat (label );
267- if (format != null ) {
268- label = label .substring (0 , label .indexOf ("[" )).trim ();
269- Map <String , String > formatters = Objects
270- .requireNonNull (stateFormattersMap .computeIfAbsent (modelName , k -> new HashMap <>()));
271- formatters .put (modelItem .getName (), format );
272- if (!isIsolatedModel (modelName )) {
273- stateDescriptionFragments .put (modelItem .getName (),
274- StateDescriptionFragmentBuilder .create ().withPattern (format ).build ());
275- }
276- } else {
277- Map <String , String > formatters = stateFormattersMap .get (modelName );
278- if (formatters != null ) {
279- formatters .remove (modelItem .getName ());
280- if (formatters .isEmpty ()) {
281- stateFormattersMap .remove (modelName );
239+
240+ try {
241+ String [] itemTypeSegments = itemType .split (ItemUtil .EXTENSION_SEPARATOR );
242+ String mainItemType = itemTypeSegments [0 ];
243+
244+ Item item = switch (mainItemType ) {
245+ case "Group" -> createGroupItem (modelItem , itemTypeSegments );
246+ default -> createItemOfType (itemType , modelItem .getName ());
247+ };
248+
249+ if (item instanceof ActiveItem activeItem ) {
250+ String label = modelItem .getLabel ();
251+ String format = extractFormat (label );
252+ if (format != null ) {
253+ label = label .substring (0 , label .indexOf ("[" )).trim ();
254+ Map <String , String > formatters = Objects
255+ .requireNonNull (stateFormattersMap .computeIfAbsent (modelName , k -> new HashMap <>()));
256+ formatters .put (modelItem .getName (), format );
257+ if (!isIsolatedModel (modelName )) {
258+ stateDescriptionFragments .put (modelItem .getName (),
259+ StateDescriptionFragmentBuilder .create ().withPattern (format ).build ());
260+ }
261+ } else {
262+ Map <String , String > formatters = stateFormattersMap .get (modelName );
263+ if (formatters != null ) {
264+ formatters .remove (modelItem .getName ());
265+ if (formatters .isEmpty ()) {
266+ stateFormattersMap .remove (modelName );
267+ }
268+ }
269+ if (!isIsolatedModel (modelName )) {
270+ stateDescriptionFragments .remove (modelItem .getName ());
282271 }
283272 }
284- if (!isIsolatedModel (modelName )) {
285- stateDescriptionFragments .remove (modelItem .getName ());
286- }
273+ activeItem .setLabel (label );
274+ activeItem .setCategory (modelItem .getIcon ());
275+ assignTags (modelItem , activeItem );
276+ return item ;
277+ } else {
278+ return null ;
287279 }
288- activeItem .setLabel (label );
289- activeItem .setCategory (modelItem .getIcon ());
290- assignTags (modelItem , activeItem );
291- return item ;
292- } else {
280+ } catch (IllegalArgumentException e ) {
281+ logger .debug ("Error creating item '{}', item will be ignored: {}" , modelItem .getName (), e .getMessage ());
293282 return null ;
294283 }
295284 }
@@ -312,14 +301,14 @@ private void assignTags(ModelItem modelItem, ActiveItem item) {
312301 }
313302 }
314303
315- private GroupItem applyGroupFunction (Item baseItem , ModelGroupItem modelGroupItem , ModelGroupFunction function ) {
304+ private GroupItem applyGroupFunction (Item baseItem , ModelItem modelItem , String function ) {
316305 GroupFunctionDTO dto = new GroupFunctionDTO ();
317- dto .name = function . getName () ;
318- dto .params = modelGroupItem .getArgs ().toArray (new String [0 ]);
306+ dto .name = function ;
307+ dto .params = modelItem .getArgs ().toArray (new String [0 ]);
319308
320309 GroupFunction groupFunction = ItemDTOMapper .mapFunction (baseItem , dto );
321310
322- return new GroupItem (modelGroupItem .getName (), baseItem , groupFunction );
311+ return new GroupItem (modelItem .getName (), baseItem , groupFunction );
323312 }
324313
325314 private void dispatchBindingsPerItemType (String [] itemTypes ) {
@@ -529,6 +518,47 @@ private Map<String, Item> toItemMap(@Nullable Collection<Item> items) {
529518 return ret ;
530519 }
531520
521+ /**
522+ * Creates a new GroupItem based on the given ModelItem and item type segments.
523+ *
524+ * @param modelItem The ModelItem to create the GroupItem from.
525+ * @param itemTypeSegments The segments of the item type.
526+ * @return A new GroupItem or null if the item type is invalid.
527+ */
528+ private @ Nullable GroupItem createGroupItem (ModelItem modelItem , String [] itemTypeSegments ) {
529+ if (itemTypeSegments .length == 1 ) {
530+ // Just plain "Group" with no base type
531+ return new GroupItem (modelItem .getName ());
532+ }
533+
534+ String function = GroupFunction .DEFAULT ;
535+
536+ String baseItemType = switch (itemTypeSegments .length ) {
537+ case 2 -> itemTypeSegments [1 ];
538+ case 3 -> {
539+ // 3 segments could either be Group:Type:Function, or Group:Number:Dimension -> Find out which one it is
540+ if (!modelItem .getArgs ().isEmpty () || GroupFunction .VALID_FUNCTIONS .contains (itemTypeSegments [2 ])) {
541+ // It's Group:Type:Function because there are arguments or the third segment is a valid function
542+ function = itemTypeSegments [2 ];
543+ yield itemTypeSegments [1 ];
544+ } else {
545+ // Otherwise, it must be Group:Number:Dimension
546+ yield itemTypeSegments [1 ] + ItemUtil .EXTENSION_SEPARATOR + itemTypeSegments [2 ];
547+ }
548+ }
549+ case 4 -> {
550+ // 4 segments: "Group:Number:Dimension:Function"
551+ function = itemTypeSegments [3 ];
552+ yield itemTypeSegments [1 ] + ItemUtil .EXTENSION_SEPARATOR + itemTypeSegments [2 ];
553+ }
554+ default -> throw new IllegalArgumentException ("Invalid group item type: " + modelItem .getType ()
555+ + ". Expected formats are 'Group', 'Group:Type', 'Group:Type:Function', or 'Group:Number:Dimension:Function' with a maximum of 4 segments." );
556+ };
557+
558+ Item baseItem = createItemOfType (baseItemType , modelItem .getName ());
559+ return applyGroupFunction (baseItem , modelItem , function );
560+ }
561+
532562 /**
533563 * Creates a new item of type {@code itemType} by utilizing an appropriate {@link ItemFactory}.
534564 *
0 commit comments