ExposedThing::destroy invocation after Wot::destroy is a no-op (or a warning).
Observed Behavior
ExposedThing::destroy invocation after Wot::destroy is a NullPointerException.
Consider the following code:
public class Test {
public static void main(String[] args) throws WotException, ExecutionException, InterruptedException {
Config config = ConfigFactory
.parseString("wot.servient.servers = [\"city.sane.wot.binding.mqtt.MqttProtocolServer\"]");
config = config.withFallback(ConfigFactory.load());
Wot wot = DefaultWot.serverOnly(config);
Thing thing = new Thing.Builder().build();
ExposedThing exposedThing = wot.produce(thing).expose().get();
wot.destroy();
exposedThing.destroy().get();
}
}
Output:
21:41:16.078 | main | DEBUG | city.sane.wot.ServientConfig | Servient storing credentials for '[]'
21:41:16.080 | main | INFO | city.sane.wot.Servient | Start Servient
21:41:16.083 | main | INFO | c.s.w.b.mqtt.MqttProtocolServer | Start MqttServer
21:41:16.090 | ForkJoinPool.commonPool-worker-3 | DEBUG | city.sane.RefCountResource | First Reference. Create Resource.
21:41:16.218 | ForkJoinPool.commonPool-worker-3 | INFO | c.s.w.b.mqtt.MqttProtocolSettings | MqttClient trying to connect to broker at 'tcp://localhost:1883' with client ID 'wot29755222508026'
21:41:16.540 | ForkJoinPool.commonPool-worker-3 | INFO | c.s.w.b.mqtt.MqttProtocolSettings | MqttClient connected to broker at 'tcp://localhost:1883'
21:41:16.680 | main | DEBUG | city.sane.wot.thing.ExposedThing | 'null' created
21:41:16.682 | main | WARN | city.sane.wot.Servient | Servient generating ID for 'ExposedThing{objectType='null', objectContext=null, id='null', title='null', titles=null, description='null', descriptions=null, properties={}, actions={}, events={}, forms=[], security=[], securityDefinitions={}, base='null'}'
21:41:16.714 | main | DEBUG | city.sane.wot.thing.ExposedThing | Expose all Interactions and TD for 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84'
21:41:16.714 | main | INFO | city.sane.wot.Servient | Servient exposing 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84'
21:41:16.717 | main | INFO | c.s.w.b.mqtt.MqttProtocolServer | MqttServer exposes 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84' at 'mqtt://localhost:1883/urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84/*'
21:41:16.718 | main | DEBUG | c.s.w.b.mqtt.MqttProtocolServer | Publish 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84' Thing Description to topic 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84'
21:41:16.803 | main | DEBUG | city.sane.wot.content.ContentManager | Content serializing to 'application/json'
21:41:16.808 | main | DEBUG | city.sane.wot.thing.ExposedThing | TD has changed. Inform observers.
21:41:16.809 | main | INFO | city.sane.wot.Servient | Stop Servient
21:41:16.810 | main | INFO | c.s.w.b.mqtt.MqttProtocolServer | Stop MqttServer
21:41:16.810 | main | DEBUG | city.sane.wot.thing.ExposedThing | Stop exposing all Interactions and TD for 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84'
21:41:16.810 | main | INFO | city.sane.wot.Servient | Servient stop exposing 'ExposedThing{objectType='null', objectContext=null, id='urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84', title='null', titles=null, description='null', descriptions=null, properties={}, actions={}, events={}, forms=[], security=[], securityDefinitions={}, base=''}'
21:41:16.812 | main | INFO | c.s.w.b.mqtt.MqttProtocolServer | MqttServer stop exposing 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84' as unique '/urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84/*'
21:41:16.812 | main | DEBUG | c.s.w.b.mqtt.MqttProtocolServer | Remove published 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84' Thing Description at topic 'urn:uuid:5b13492d-78aa-48b6-abcf-9ca6329a6d84'
21:41:16.811 | ForkJoinPool.commonPool-worker-3 | DEBUG | city.sane.RefCountResource | No more References. Cleanup Resource: Pair{first=city.sane.wot.binding.mqtt.MqttProtocolSettings@d46d7f4, second=org.eclipse.paho.client.mqttv3.MqttClient@2edcc234}
Exception in thread "main" java.lang.NullPointerException
at city.sane.wot.binding.mqtt.MqttProtocolServer.unexposeTD(MqttProtocolServer.java:260)
at city.sane.wot.binding.mqtt.MqttProtocolServer.destroy(MqttProtocolServer.java:130)
at city.sane.wot.Servient.lambda$destroy$16(Servient.java:213)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:550)
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:517)
at city.sane.wot.Servient.destroy(Servient.java:213)
at city.sane.wot.thing.ExposedThing.destroy(ExposedThing.java:561)
at ru.mipt.wot.cloud.example.Test.main(Test.java:23)
Expected behavior
ExposedThing::destroy
invocation afterWot::destroy
is a no-op (or a warning).Observed Behavior
ExposedThing::destroy
invocation afterWot::destroy
is aNullPointerException
.Consider the following code:
Output:
Exception is raised because
settingsClientPair
field is null on the following line insideMqttProtocolServer::unexposeTD
: https://github.com/sane-city/wot-servient/blob/490d03304cfb8b95a9a38e866016fa316ff7541d/wot-servient-binding-mqtt/src/main/java/city/sane/wot/binding/mqtt/MqttProtocolServer.java#L260 Its happening becauseMqttProtocolServer::destroy
won't checksettingsClientPair != null
beforeunexposeTD
invocation. I believe, that in the case ofsettingsClientPair == null
it's safe to simply exitMqttProtocolServer::destroy
, as destroyedProtocolServer
shoudn't have any exposed things (which isn't completly true due to https://github.com/sane-city/wot-servient/issues/6).