class GossipDeviceStore extends AbstractStore<DeviceEvent, DeviceStoreDelegate> implements DeviceStore {

    @Override
    public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId,
                                                         DeviceId deviceId,
                                                         DeviceDescription deviceDescription) {
        NodeId localNode = clusterService.getLocalNode().id();
        NodeId deviceNode = mastershipService.getMasterFor(deviceId);

        // Process device update only if we're the master,
        // otherwise signal the actual master.
        DeviceEvent deviceEvent = null;
        if (localNode.equals(deviceNode)) {

            final Timestamp newTimestamp = deviceClockService.getTimestamp(deviceId);
            final Timestamped<DeviceDescription> deltaDesc = new Timestamped<>(deviceDescription, newTimestamp);
            final Timestamped<DeviceDescription> mergedDesc;
            final Map<ProviderId, DeviceDescriptions> device = getOrCreateDeviceDescriptionsMap(deviceId);

            synchronized (device) {
                deviceEvent = createOrUpdateDeviceInternal(providerId, deviceId, deltaDesc);
                mergedDesc = device.get(providerId).getDeviceDesc();
            }

            if (deviceEvent != null) {
                log.debug("Notifying peers of a device update topology event for providerId: {} and deviceId: {}",
                         providerId, deviceId);
                notifyPeers(new InternalDeviceEvent(providerId, deviceId, mergedDesc));
            }

        } else {
            // Only forward for ConfigProvider
            // Forwarding was added as a workaround for ONOS-490
            if (!providerId.scheme().equals("cfg")) {
                return null;
            }
            // FIXME Temporary hack for NPE (ONOS-1171).
            // Proper fix is to implement forwarding to master on ConfigProvider
            // redo ONOS-490
            if (deviceNode == null) {
                // silently ignore
                return null;
            }


            DeviceInjectedEvent deviceInjectedEvent = new DeviceInjectedEvent(
                    providerId, deviceId, deviceDescription);

            // TODO check unicast return value
            clusterCommunicator.unicast(deviceInjectedEvent, DEVICE_INJECTED, SERIALIZER::encode, deviceNode);
            /* error log:
            log.warn("Failed to process injected device id: {} desc: {} " +
                            "(cluster messaging failed: {})",
                    deviceId, deviceDescription, e);
            */
        }

        return deviceEvent;
    }

}