Skip to content

Commit

Permalink
Refactor ThingManagerImpl
Browse files Browse the repository at this point in the history
This

- moves config description URI to type-base class
- decouples the thing manager from bundle loading
- makes sure that all thing/channel-types and config descriptions are available when the thing is initialized
- enables thing type updates

Signed-off-by: Jan N. Klug <github@klug.nrw>
  • Loading branch information
J-N-K committed Jan 23, 2023
1 parent dd756b8 commit f8b78bd
Show file tree
Hide file tree
Showing 20 changed files with 1,184 additions and 605 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
@NonNullByDefault
public enum ThingStatusDetail {
NONE,
NOT_YET_READY,
HANDLER_MISSING_ERROR,
HANDLER_REGISTERING_ERROR,
HANDLER_INITIALIZING_ERROR,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -74,6 +76,19 @@ public static ThingBuilder create(ThingTypeUID thingTypeUID, ThingUID thingUID)
return new ThingBuilder(thingTypeUID, thingUID);
}

/**
* Create a new thing {@link ThingBuilder} for a copy of the given thing
*
* @param thing the {@link Thing} to create this builder from
* @return the created {@link ThingBuilder}
*
*/
public static ThingBuilder create(Thing thing) {
return ThingBuilder.create(thing.getThingTypeUID(), thing.getUID()).withBridge(thing.getBridgeUID())
.withChannels(thing.getChannels()).withConfiguration(thing.getConfiguration())
.withLabel(thing.getLabel()).withLocation(thing.getLocation()).withProperties(thing.getProperties());
}

/**
* Build the thing
*
Expand Down Expand Up @@ -200,6 +215,20 @@ public ThingBuilder withBridge(@Nullable ThingUID bridgeUID) {
return this;
}

/**
* Set / replace a single property for this thing
*
* @param key the key / name of the property
* @param value the value of the property
* @return the {@link ThingBuilder} itself
*/
public ThingBuilder withProperty(String key, String value) {
Map<String, String> oldProperties = Objects.requireNonNullElse(this.properties, Map.of());
Map<String, String> newProperties = new HashMap<>(oldProperties);
newProperties.put(key, value);
return withProperties(newProperties);
}

/**
* Set/replace the properties for this thing
*
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2010-2023 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.core.thing.internal.update;

import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.builder.ThingBuilder;

/**
* The {@link RemoveChannelInstructionImpl} implements a {@link ThingUpdateInstruction} that removes a channel from a
* thing.
* <p />
* Parameters are:
* <ul>
* <li>channelId - the id of the channel</li>
* </ul>
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class RemoveChannelInstructionImpl implements ThingUpdateInstruction {
private final int thingTypeVersion;
private final List<String> parameters;

RemoveChannelInstructionImpl(int thingTypeVersion, List<String> parameters) {
this.thingTypeVersion = thingTypeVersion;
this.parameters = parameters;
}

@Override
public int getThingTypeVersion() {
return thingTypeVersion;
}

@Override
public void perform(Thing thing, ThingBuilder thingBuilder) {
ChannelUID affectedChannelUid = new ChannelUID(thing.getUID(), parameters.get(0));
thingBuilder.withoutChannel(affectedChannelUid);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2010-2023 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.core.thing.internal.update;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.builder.ThingBuilder;

/**
* The {@link ThingUpdateInstruction} is an interface that can be implemented to perform updates on things when the
* thing-type changes
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public interface ThingUpdateInstruction {

/**
* Get the thing type version for which this update is needed
*
* @return the thing-type version (always > 0)
*/
int getThingTypeVersion();

/**
* Perform the update in this instruction for a given {@link Thing} using the given {@link ThingBuilder}
* <p />
* Note: the thing type version is not updated as there may be several instructions to perform for a single version.
*
* @param thing the thing that should be updated
* @param thingBuilder the thing builder to use
*/
void perform(Thing thing, ThingBuilder thingBuilder);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2010-2023 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.core.thing.internal.update;

import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;

/**
* The {@link ThingUpdateInstructionImpl} is a
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class ThingUpdateInstructionImpl implements ThingUpdateInstruction {
private final int thingTypeVersion;
private final UpdateCommand updateCommand;
private final String channelId;
private final List<String> parameters;

ThingUpdateInstructionImpl(int thingTypeVersion, UpdateCommand updateCommand, String channelId,
List<String> parameters) {
this.thingTypeVersion = thingTypeVersion;
this.updateCommand = updateCommand;
this.channelId = channelId;
this.parameters = parameters;
}

@Override
public int getThingTypeVersion() {
return thingTypeVersion;
}

@Override
public void perform(Thing thing, ThingBuilder thingBuilder) {
ChannelUID affectedChannelUid = new ChannelUID(thing.getUID(), channelId);
switch (updateCommand) {
case UPDATE_CHANNEL:
thingBuilder.withoutChannel(affectedChannelUid);
// fall-through to add channel
case ADD_CHANNEL:
ChannelBuilder channelBuilder = ChannelBuilder.create(affectedChannelUid)
.withType(new ChannelTypeUID(parameters.get(1)));
if (parameters.size() >= 3) {
// label is optional (could be inherited from thing-type)
channelBuilder.withLabel(parameters.get(2));
}
if (parameters.size() == 4) {
// description is optional (could be inherited from thing-type)
channelBuilder.withDescription(parameters.get(3));
}
thingBuilder.withChannel(channelBuilder.build());
break;
case REMOVE_CHANNEL:
thingBuilder.withoutChannel(affectedChannelUid);
break;
}
}

public enum UpdateCommand {
ADD_CHANNEL(2, 4),
REMOVE_CHANNEL(0, 0),
UPDATE_CHANNEL(2, 4);

private final int minParameterCount;
private final int maxParameterCount;

UpdateCommand(int minParameterCount, int maxParameterCount) {
this.minParameterCount = minParameterCount;
this.maxParameterCount = maxParameterCount;
}

public boolean isValidParameterSet(int parameterCount) {
return parameterCount >= minParameterCount && parameterCount <= maxParameterCount;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Copyright (c) 2010-2023 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.core.thing.internal.update;

import java.util.List;
import java.util.Map;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.binding.ThingHandlerFactory;

/**
* The {@link ThingUpdateInstructionReader} is used to read instructions for a given {@link ThingHandlerFactory} and
* create a list of {@link ThingUpdateInstruction}s
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public interface ThingUpdateInstructionReader {
Map<UpdateInstructionKey, List<ThingUpdateInstruction>> readForFactory(ThingHandlerFactory factory);

record UpdateInstructionKey(ThingHandlerFactory factory, String thingTypeId) {
}
}
Loading

0 comments on commit f8b78bd

Please sign in to comment.