LwM2M: default object version (#10731)
* lwm2m: object-id-version default 1.0 * lwm2m: delete translate * lwm2m: delete translate3 * lwm2m: object id ver comment4 * lwm2m: object id ver comment5 * lwm2m: object id ver comment6
This commit is contained in:
		
							parent
							
								
									a6e47c3b13
								
							
						
					
					
						commit
						6c499fd342
					
				@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.StringUtils;
 | 
				
			|||||||
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
 | 
					import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
 | 
				
			||||||
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential;
 | 
					import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential;
 | 
				
			||||||
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode;
 | 
					import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode;
 | 
				
			||||||
import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.data.device.data.DeviceData;
 | 
					import org.thingsboard.server.common.data.device.data.DeviceData;
 | 
				
			||||||
import org.thingsboard.server.common.data.device.data.PowerMode;
 | 
					import org.thingsboard.server.common.data.device.data.PowerMode;
 | 
				
			||||||
import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
 | 
					import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
 | 
				
			||||||
@ -68,6 +67,8 @@ import java.util.Set;
 | 
				
			|||||||
import java.util.concurrent.locks.Lock;
 | 
					import java.util.concurrent.locks.Lock;
 | 
				
			||||||
import java.util.concurrent.locks.ReentrantLock;
 | 
					import java.util.concurrent.locks.ReentrantLock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.eclipse.leshan.core.LwM2m.Version.V1_0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Service
 | 
					@Service
 | 
				
			||||||
@TbCoreComponent
 | 
					@TbCoreComponent
 | 
				
			||||||
@RequiredArgsConstructor
 | 
					@RequiredArgsConstructor
 | 
				
			||||||
@ -256,7 +257,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration();
 | 
					                    Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration();
 | 
				
			||||||
                    transportConfiguration.setBootstrap(Collections.emptyList());
 | 
					                    transportConfiguration.setBootstrap(Collections.emptyList());
 | 
				
			||||||
                    transportConfiguration.setClientLwM2mSettings(new OtherConfiguration(1, 1, 1, PowerMode.DRX, null, null, null, null, null));
 | 
					                    transportConfiguration.setClientLwM2mSettings(new OtherConfiguration(1, 1, 1, PowerMode.DRX, null, null, null, null, null, V1_0.toString()));
 | 
				
			||||||
                    transportConfiguration.setObserveAttr(new TelemetryMappingConfiguration(Collections.emptyMap(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptyMap()));
 | 
					                    transportConfiguration.setObserveAttr(new TelemetryMappingConfiguration(Collections.emptyMap(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptyMap()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    DeviceProfileData deviceProfileData = new DeviceProfileData();
 | 
					                    DeviceProfileData deviceProfileData = new DeviceProfileData();
 | 
				
			||||||
 | 
				
			|||||||
@ -39,4 +39,5 @@ public class OtherConfiguration extends PowerSavingConfiguration {
 | 
				
			|||||||
    private Long pagingTransmissionWindow;
 | 
					    private Long pagingTransmissionWindow;
 | 
				
			||||||
    private String fwUpdateResource;
 | 
					    private String fwUpdateResource;
 | 
				
			||||||
    private String swUpdateResource;
 | 
					    private String swUpdateResource;
 | 
				
			||||||
 | 
					    private String defaultObjectIDVer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,7 @@ import org.eclipse.leshan.server.registration.Registration;
 | 
				
			|||||||
import org.eclipse.leshan.server.registration.RegistrationListener;
 | 
					import org.eclipse.leshan.server.registration.RegistrationListener;
 | 
				
			||||||
import org.eclipse.leshan.server.registration.RegistrationUpdate;
 | 
					import org.eclipse.leshan.server.registration.RegistrationUpdate;
 | 
				
			||||||
import org.eclipse.leshan.server.send.SendListener;
 | 
					import org.eclipse.leshan.server.send.SendListener;
 | 
				
			||||||
 | 
					import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
 | 
				
			||||||
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
 | 
					import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
@ -101,7 +102,10 @@ public class LwM2mServerListener {
 | 
				
			|||||||
        @Override
 | 
					        @Override
 | 
				
			||||||
        public void onResponse(SingleObservation observation, Registration registration, ObserveResponse response) {
 | 
					        public void onResponse(SingleObservation observation, Registration registration, ObserveResponse response) {
 | 
				
			||||||
            if (registration != null) {
 | 
					            if (registration != null) {
 | 
				
			||||||
                service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), registration), response);
 | 
					                LwM2mClient lwM2MClient = service.getClientContext().getClientByEndpoint(registration.getEndpoint());
 | 
				
			||||||
 | 
					                if (lwM2MClient != null) {
 | 
				
			||||||
 | 
					                    service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), lwM2MClient), response);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -27,10 +27,10 @@ import org.springframework.stereotype.Service;
 | 
				
			|||||||
import org.thingsboard.server.common.data.TbResource;
 | 
					import org.thingsboard.server.common.data.TbResource;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					import org.thingsboard.server.common.data.id.TenantId;
 | 
				
			||||||
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
 | 
					import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
 | 
				
			||||||
 | 
					import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
 | 
				
			||||||
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
 | 
					import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Base64;
 | 
					 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.Optional;
 | 
					import java.util.Optional;
 | 
				
			||||||
@ -107,7 +107,8 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        @Override
 | 
					        @Override
 | 
				
			||||||
        public ObjectModel getObjectModel(int objectId) {
 | 
					        public ObjectModel getObjectModel(int objectId) {
 | 
				
			||||||
            String version = String.valueOf(registration.getSupportedVersion(objectId));
 | 
					            LwM2mClient lwM2mClient = lwM2mClientContext.getClientByEndpoint(registration.getEndpoint());
 | 
				
			||||||
 | 
					            String version = lwM2mClient.getSupportedObjectVersion(objectId).toString();
 | 
				
			||||||
            if (version != null) {
 | 
					            if (version != null) {
 | 
				
			||||||
                return this.getObjectModelDynamic(objectId, version);
 | 
					                return this.getObjectModelDynamic(objectId, version);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -116,7 +117,8 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        @Override
 | 
					        @Override
 | 
				
			||||||
        public Collection<ObjectModel> getObjectModels() {
 | 
					        public Collection<ObjectModel> getObjectModels() {
 | 
				
			||||||
            Map<Integer, LwM2m.Version> supportedObjects = this.registration.getSupportedObject();
 | 
					            LwM2mClient lwM2mClient = lwM2mClientContext.getClientByEndpoint(registration.getEndpoint());
 | 
				
			||||||
 | 
					            Map<Integer, LwM2m.Version> supportedObjects = lwM2mClient.getSupportedClientObjects();
 | 
				
			||||||
            Collection<ObjectModel> result = new ArrayList<>(supportedObjects.size());
 | 
					            Collection<ObjectModel> result = new ArrayList<>(supportedObjects.size());
 | 
				
			||||||
            for (Map.Entry<Integer, LwM2m.Version> supportedObject : supportedObjects.entrySet()) {
 | 
					            for (Map.Entry<Integer, LwM2m.Version> supportedObject : supportedObjects.entrySet()) {
 | 
				
			||||||
                ObjectModel objectModel = this.getObjectModelDynamic(supportedObject.getKey(), String.valueOf(supportedObject.getValue()));
 | 
					                ObjectModel objectModel = this.getObjectModelDynamic(supportedObject.getKey(), String.valueOf(supportedObject.getValue()));
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,10 @@ import lombok.Setter;
 | 
				
			|||||||
import lombok.ToString;
 | 
					import lombok.ToString;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
import org.eclipse.leshan.core.LwM2m;
 | 
					import org.eclipse.leshan.core.LwM2m;
 | 
				
			||||||
 | 
					import org.eclipse.leshan.core.LwM2m.Version;
 | 
				
			||||||
 | 
					import org.eclipse.leshan.core.link.Link;
 | 
				
			||||||
import org.eclipse.leshan.core.link.attributes.Attribute;
 | 
					import org.eclipse.leshan.core.link.attributes.Attribute;
 | 
				
			||||||
 | 
					import org.eclipse.leshan.core.link.lwm2m.MixedLwM2mLink;
 | 
				
			||||||
import org.eclipse.leshan.core.model.ObjectModel;
 | 
					import org.eclipse.leshan.core.model.ObjectModel;
 | 
				
			||||||
import org.eclipse.leshan.core.model.ResourceModel;
 | 
					import org.eclipse.leshan.core.model.ResourceModel;
 | 
				
			||||||
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
 | 
					import org.eclipse.leshan.core.node.LwM2mMultipleResource;
 | 
				
			||||||
@ -37,6 +40,7 @@ import org.thingsboard.server.common.data.Device;
 | 
				
			|||||||
import org.thingsboard.server.common.data.DeviceProfile;
 | 
					import org.thingsboard.server.common.data.DeviceProfile;
 | 
				
			||||||
import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration;
 | 
					import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration;
 | 
				
			||||||
import org.thingsboard.server.common.data.device.data.PowerMode;
 | 
					import org.thingsboard.server.common.data.device.data.PowerMode;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					import org.thingsboard.server.common.data.id.TenantId;
 | 
				
			||||||
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
 | 
					import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
 | 
				
			||||||
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
 | 
					import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
 | 
				
			||||||
@ -61,8 +65,8 @@ import java.util.stream.Collectors;
 | 
				
			|||||||
import java.util.stream.Stream;
 | 
					import java.util.stream.Stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
 | 
					import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
 | 
				
			||||||
 | 
					import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT;
 | 
				
			||||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertMultiResourceValuesFromRpcBody;
 | 
					import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertMultiResourceValuesFromRpcBody;
 | 
				
			||||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertObjectIdToVersionedId;
 | 
					 | 
				
			||||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.equalsResourceTypeGetSimpleName;
 | 
					import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.equalsResourceTypeGetSimpleName;
 | 
				
			||||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId;
 | 
					import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId;
 | 
				
			||||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.getVerFromPathIdVerOrId;
 | 
					import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.getVerFromPathIdVerOrId;
 | 
				
			||||||
@ -129,6 +133,12 @@ public class LwM2mClient {
 | 
				
			|||||||
    @Setter
 | 
					    @Setter
 | 
				
			||||||
    private UUID lastSentRpcId;
 | 
					    private UUID lastSentRpcId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Setter
 | 
				
			||||||
 | 
					    private LwM2m.Version defaultObjectIDVer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Getter
 | 
				
			||||||
 | 
					    private Map<Integer, Version> supportedClientObjects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public Object clone() throws CloneNotSupportedException {
 | 
					    public Object clone() throws CloneNotSupportedException {
 | 
				
			||||||
        return super.clone();
 | 
					        return super.clone();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -142,6 +152,7 @@ public class LwM2mClient {
 | 
				
			|||||||
        this.state = LwM2MClientState.CREATED;
 | 
					        this.state = LwM2MClientState.CREATED;
 | 
				
			||||||
        this.lock = new ReentrantLock();
 | 
					        this.lock = new ReentrantLock();
 | 
				
			||||||
        this.retryAttempts = new AtomicInteger(0);
 | 
					        this.retryAttempts = new AtomicInteger(0);
 | 
				
			||||||
 | 
					        this.supportedClientObjects = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void init(ValidateDeviceCredentialsResponse credentials, UUID sessionId) {
 | 
					    public void init(ValidateDeviceCredentialsResponse credentials, UUID sessionId) {
 | 
				
			||||||
@ -153,12 +164,14 @@ public class LwM2mClient {
 | 
				
			|||||||
        this.edrxCycle = credentials.getDeviceInfo().getEdrxCycle();
 | 
					        this.edrxCycle = credentials.getDeviceInfo().getEdrxCycle();
 | 
				
			||||||
        this.psmActivityTimer = credentials.getDeviceInfo().getPsmActivityTimer();
 | 
					        this.psmActivityTimer = credentials.getDeviceInfo().getPsmActivityTimer();
 | 
				
			||||||
        this.pagingTransmissionWindow = credentials.getDeviceInfo().getPagingTransmissionWindow();
 | 
					        this.pagingTransmissionWindow = credentials.getDeviceInfo().getPagingTransmissionWindow();
 | 
				
			||||||
 | 
					        this.defaultObjectIDVer = getObjectIDVerFromDeviceProfile(credentials.getDeviceProfile());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setRegistration(Registration registration) {
 | 
					    public void setRegistration(Registration registration) {
 | 
				
			||||||
        this.registration = registration;
 | 
					        this.registration = registration;
 | 
				
			||||||
        this.clientSupportContentFormats = clientSupportContentFormat(registration);
 | 
					        this.clientSupportContentFormats = clientSupportContentFormat(registration);
 | 
				
			||||||
        this.defaultContentFormat = calculateDefaultContentFormat(registration);
 | 
					        this.defaultContentFormat = calculateDefaultContentFormat(registration);
 | 
				
			||||||
 | 
					        this.setSupportedClientObjects();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void lock() {
 | 
					    public void lock() {
 | 
				
			||||||
@ -197,6 +210,15 @@ public class LwM2mClient {
 | 
				
			|||||||
        builder.setDeviceType(deviceProfile.getName());
 | 
					        builder.setDeviceType(deviceProfile.getName());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private LwM2m.Version getObjectIDVerFromDeviceProfile(DeviceProfile deviceProfile) {
 | 
				
			||||||
 | 
					        String defaultObjectIdVer = ((Lwm2mDeviceProfileTransportConfiguration)deviceProfile
 | 
				
			||||||
 | 
					                .getProfileData()
 | 
				
			||||||
 | 
					                .getTransportConfiguration())
 | 
				
			||||||
 | 
					                .getClientLwM2mSettings()
 | 
				
			||||||
 | 
					                .getDefaultObjectIDVer();
 | 
				
			||||||
 | 
					        return new Version(defaultObjectIdVer == null ? LWM2M_OBJECT_VERSION_DEFAULT : defaultObjectIdVer);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void refreshSessionId(String nodeId) {
 | 
					    public void refreshSessionId(String nodeId) {
 | 
				
			||||||
        UUID newId = UUID.randomUUID();
 | 
					        UUID newId = UUID.randomUUID();
 | 
				
			||||||
        SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session);
 | 
					        SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session);
 | 
				
			||||||
@ -240,67 +262,28 @@ public class LwM2mClient {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public Object getResourceValue(String pathRezIdVer, String pathRezId) {
 | 
					 | 
				
			||||||
        String pathRez = pathRezIdVer == null ? convertObjectIdToVersionedId(pathRezId, this.registration) : pathRezIdVer;
 | 
					 | 
				
			||||||
        if (this.resources.get(pathRez) != null) {
 | 
					 | 
				
			||||||
            return this.resources.get(pathRez).getLwM2mResource().getValue();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Object getResourceNameByRezId(String pathRezIdVer, String pathRezId) {
 | 
					 | 
				
			||||||
        String pathRez = pathRezIdVer == null ? convertObjectIdToVersionedId(pathRezId, this.registration) : pathRezIdVer;
 | 
					 | 
				
			||||||
        if (this.resources.get(pathRez) != null) {
 | 
					 | 
				
			||||||
            return this.resources.get(pathRez).getResourceModel().name;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public String getRezIdByResourceNameAndObjectInstanceId(String resourceName, String pathObjectInstanceIdVer, LwM2mModelProvider modelProvider) {
 | 
					 | 
				
			||||||
        LwM2mPath pathIds = getLwM2mPathFromString(pathObjectInstanceIdVer);
 | 
					 | 
				
			||||||
        if (pathIds.isObjectInstance()) {
 | 
					 | 
				
			||||||
            Set<Integer> rezIds = modelProvider.getObjectModel(registration)
 | 
					 | 
				
			||||||
                    .getObjectModel(pathIds.getObjectId()).resources.entrySet()
 | 
					 | 
				
			||||||
                    .stream()
 | 
					 | 
				
			||||||
                    .filter(map -> resourceName.equals(map.getValue().name))
 | 
					 | 
				
			||||||
                    .map(map -> map.getKey())
 | 
					 | 
				
			||||||
                    .collect(Collectors.toSet());
 | 
					 | 
				
			||||||
            return rezIds.size() > 0 ? String.valueOf(rezIds.stream().findFirst().get()) : null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) {
 | 
					    public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) {
 | 
				
			||||||
        LwM2mPath pathIds = getLwM2mPathFromString(pathIdVer);
 | 
					        LwM2mPath pathIds = getLwM2mPathFromString(pathIdVer);
 | 
				
			||||||
        String verSupportedObject = String.valueOf(registration.getSupportedObject().get(pathIds.getObjectId()));
 | 
					        String verSupportedObject = String.valueOf(this.getSupportedObjectVersion(pathIds.getObjectId()));
 | 
				
			||||||
        String verRez = getVerFromPathIdVerOrId(pathIdVer);
 | 
					        String verRez = getVerFromPathIdVerOrId(pathIdVer);
 | 
				
			||||||
        return verRez != null && verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
 | 
					        return verRez != null && verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
 | 
				
			||||||
                .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null;
 | 
					                .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean isResourceMultiInstances(String pathIdVer, LwM2mModelProvider modelProvider) {
 | 
					 | 
				
			||||||
        var resourceModel = getResourceModel(pathIdVer, modelProvider);
 | 
					 | 
				
			||||||
        if (resourceModel != null && resourceModel.multiple != null) {
 | 
					 | 
				
			||||||
            return resourceModel.multiple;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) {
 | 
					    public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            LwM2mPath pathIds = getLwM2mPathFromString(pathIdVer);
 | 
					            LwM2mPath pathIds = getLwM2mPathFromString(pathIdVer);
 | 
				
			||||||
            String verSupportedObject = String.valueOf(registration.getSupportedObject().get(pathIds.getObjectId()));
 | 
					            String verSupportedObject = String.valueOf(this.getSupportedObjectVersion(pathIds.getObjectId()));
 | 
				
			||||||
            String verRez = getVerFromPathIdVerOrId(pathIdVer);
 | 
					            String verRez = getVerFromPathIdVerOrId(pathIdVer);
 | 
				
			||||||
            return verRez != null && verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
 | 
					            return verRez != null && verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
 | 
				
			||||||
                    .getObjectModel(pathIds.getObjectId()) : null;
 | 
					                    .getObjectModel(pathIds.getObjectId()) : null;
 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
            if (registration == null) {
 | 
					            if (registration == null) {
 | 
				
			||||||
                log.error("[{}] Failed Registration is null, GetObjectModelRegistration. ", this.endpoint, e);
 | 
					                log.error("[{}] Failed Registration is null, GetObjectModelRegistration. ", this.endpoint, e);
 | 
				
			||||||
            } else if (registration.getSupportedObject() == null) {
 | 
					            } else if (this.getSupportedClientObjects() == null) {
 | 
				
			||||||
                log.error("[{}] Failed SupportedObject in Registration, GetObjectModelRegistration.", this.endpoint, e);
 | 
					                log.error("[{}] Failed SupportedObject in Registration, GetObjectModelRegistration.", this.endpoint, e);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                log.error("[{}] Failed ModelProvider.getObjectModel [{}] in Registration. ", this.endpoint, registration.getSupportedObject(), e);
 | 
					                log.error("[{}] Failed ModelProvider.getObjectModel [{}] in Registration. ", this.endpoint, this.getSupportedClientObjects(), e);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -371,7 +354,7 @@ public class LwM2mClient {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public String isValidObjectVersion(String path) {
 | 
					    public String isValidObjectVersion(String path) {
 | 
				
			||||||
        LwM2mPath pathIds = getLwM2mPathFromString(path);
 | 
					        LwM2mPath pathIds = getLwM2mPathFromString(path);
 | 
				
			||||||
        LwM2m.Version verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
 | 
					        LwM2m.Version verSupportedObject = this.getSupportedObjectVersion(pathIds.getObjectId());
 | 
				
			||||||
        if (verSupportedObject == null) {
 | 
					        if (verSupportedObject == null) {
 | 
				
			||||||
            return String.format("Specified object id %s absent in the list supported objects of the client or is security object!", pathIds.getObjectId());
 | 
					            return String.format("Specified object id %s absent in the list supported objects of the client or is security object!", pathIds.getObjectId());
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -460,5 +443,34 @@ public class LwM2mClient {
 | 
				
			|||||||
        return new LwM2mPath(fromVersionedIdToObjectId(path));
 | 
					        return new LwM2mPath(fromVersionedIdToObjectId(path));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public LwM2m.Version getDefaultObjectIDVer() {
 | 
				
			||||||
 | 
					        return this.defaultObjectIDVer == null ? new Version(LWM2M_OBJECT_VERSION_DEFAULT) : this.defaultObjectIDVer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public LwM2m.Version getSupportedObjectVersion(Integer objectid) {
 | 
				
			||||||
 | 
					        return this.supportedClientObjects.get(objectid);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void setSupportedClientObjects(){
 | 
				
			||||||
 | 
					        this.supportedClientObjects = new ConcurrentHashMap<>();
 | 
				
			||||||
 | 
					        for (Link link: this.registration.getSortedObjectLinks()) {
 | 
				
			||||||
 | 
					            MixedLwM2mLink mixedLwM2mLink = (MixedLwM2mLink)link;
 | 
				
			||||||
 | 
					            if(!mixedLwM2mLink.getPath().isRoot()){
 | 
				
			||||||
 | 
					                LwM2mPath lwM2mPath = mixedLwM2mLink.getPath();
 | 
				
			||||||
 | 
					                if (lwM2mPath.isObject()) {
 | 
				
			||||||
 | 
					                    LwM2m.Version ver;
 | 
				
			||||||
 | 
					                    if (mixedLwM2mLink.getAttributes().get("ver")!= null) {
 | 
				
			||||||
 | 
					                        ver = (Version) mixedLwM2mLink.getAttributes().get("ver").getValue();
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        ver = getDefaultObjectIDVer();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    this.supportedClientObjects.put(lwM2mPath.getObjectId(), ver);
 | 
				
			||||||
 | 
					                } else if (this.supportedClientObjects.get(lwM2mPath.getObjectId()) == null){
 | 
				
			||||||
 | 
					                    this.supportedClientObjects.put(lwM2mPath.getObjectId(), getDefaultObjectIDVer());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -396,7 +396,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
 | 
				
			|||||||
        Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> {
 | 
					        Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> {
 | 
				
			||||||
            LwM2mPath pathIds = new LwM2mPath(link.getUriReference());
 | 
					            LwM2mPath pathIds = new LwM2mPath(link.getUriReference());
 | 
				
			||||||
            if (!pathIds.isRoot()) {
 | 
					            if (!pathIds.isRoot()) {
 | 
				
			||||||
                clientObjects.add(convertObjectIdToVersionedId(link.getUriReference(), client.getRegistration()));
 | 
					                clientObjects.add(convertObjectIdToVersionedId(link.getUriReference(), client));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        return (clientObjects.size() > 0) ? clientObjects : null;
 | 
					        return (clientObjects.size() > 0) ? clientObjects : null;
 | 
				
			||||||
 | 
				
			|||||||
@ -481,7 +481,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void startUpdateUsingUrl(LwM2mClient client, String id, String url) {
 | 
					    private void startUpdateUsingUrl(LwM2mClient client, String id, String url) {
 | 
				
			||||||
        String targetIdVer = convertObjectIdToVersionedId(id, client.getRegistration());
 | 
					        String targetIdVer = convertObjectIdToVersionedId(id, client);
 | 
				
			||||||
        TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(clientContext.getRequestTimeout(client)).build();
 | 
					        TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(clientContext.getRequestTimeout(client)).build();
 | 
				
			||||||
        downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, targetIdVer));
 | 
					        downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, targetIdVer));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -512,10 +512,10 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            switch (strategy) {
 | 
					            switch (strategy) {
 | 
				
			||||||
                case OBJ_5_BINARY:
 | 
					                case OBJ_5_BINARY:
 | 
				
			||||||
                    startUpdateUsingBinary(client, convertObjectIdToVersionedId(FW_PACKAGE_5_ID, client.getRegistration()), otaPackageId);
 | 
					                    startUpdateUsingBinary(client, convertObjectIdToVersionedId(FW_PACKAGE_5_ID, client), otaPackageId);
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                case OBJ_19_BINARY:
 | 
					                case OBJ_19_BINARY:
 | 
				
			||||||
                    startUpdateUsingBinary(client, convertObjectIdToVersionedId(FW_PACKAGE_19_ID, client.getRegistration()), otaPackageId);
 | 
					                    startUpdateUsingBinary(client, convertObjectIdToVersionedId(FW_PACKAGE_19_ID, client), otaPackageId);
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                case OBJ_5_TEMP_URL:
 | 
					                case OBJ_5_TEMP_URL:
 | 
				
			||||||
                    startUpdateUsingUrl(client, FW_URL_ID, info.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + otaPackageId.toString());
 | 
					                    startUpdateUsingUrl(client, FW_URL_ID, info.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + otaPackageId.toString());
 | 
				
			||||||
@ -534,7 +534,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
 | 
				
			|||||||
            LwM2MSoftwareUpdateStrategy strategy = info.getStrategy();
 | 
					            LwM2MSoftwareUpdateStrategy strategy = info.getStrategy();
 | 
				
			||||||
            switch (strategy) {
 | 
					            switch (strategy) {
 | 
				
			||||||
                case BINARY:
 | 
					                case BINARY:
 | 
				
			||||||
                    startUpdateUsingBinary(client, convertObjectIdToVersionedId(SW_PACKAGE_ID, client.getRegistration()), otaPackageId);
 | 
					                    startUpdateUsingBinary(client, convertObjectIdToVersionedId(SW_PACKAGE_ID, client), otaPackageId);
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                case TEMP_URL:
 | 
					                case TEMP_URL:
 | 
				
			||||||
                    startUpdateUsingUrl(client, SW_PACKAGE_URI_ID, info.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + otaPackageId.toString());
 | 
					                    startUpdateUsingUrl(client, SW_PACKAGE_URI_ID, info.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + otaPackageId.toString());
 | 
				
			||||||
@ -566,19 +566,19 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void executeFwUpdate(LwM2mClient client) {
 | 
					    private void executeFwUpdate(LwM2mClient client) {
 | 
				
			||||||
        String fwExecuteVerId = convertObjectIdToVersionedId(FW_EXECUTE_ID, client.getRegistration());
 | 
					        String fwExecuteVerId = convertObjectIdToVersionedId(FW_EXECUTE_ID, client);
 | 
				
			||||||
        TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(fwExecuteVerId).timeout(clientContext.getRequestTimeout(client)).build();
 | 
					        TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(fwExecuteVerId).timeout(clientContext.getRequestTimeout(client)).build();
 | 
				
			||||||
        downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, fwExecuteVerId));
 | 
					        downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, fwExecuteVerId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void executeSwInstall(LwM2mClient client) {
 | 
					    private void executeSwInstall(LwM2mClient client) {
 | 
				
			||||||
        String swInstallVerId = convertObjectIdToVersionedId(SW_INSTALL_ID, client.getRegistration());
 | 
					        String swInstallVerId = convertObjectIdToVersionedId(SW_INSTALL_ID, client);
 | 
				
			||||||
        TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(swInstallVerId).timeout(clientContext.getRequestTimeout(client)).build();
 | 
					        TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(swInstallVerId).timeout(clientContext.getRequestTimeout(client)).build();
 | 
				
			||||||
        downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, swInstallVerId));
 | 
					        downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, swInstallVerId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void executeSwUninstallForUpdate(LwM2mClient client) {
 | 
					    private void executeSwUninstallForUpdate(LwM2mClient client) {
 | 
				
			||||||
        String swInInstallVerId = convertObjectIdToVersionedId(SW_UN_INSTALL_ID, client.getRegistration());
 | 
					        String swInInstallVerId = convertObjectIdToVersionedId(SW_UN_INSTALL_ID, client);
 | 
				
			||||||
        TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(swInInstallVerId).params("1").timeout(clientContext.getRequestTimeout(client)).build();
 | 
					        TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(swInInstallVerId).params("1").timeout(clientContext.getRequestTimeout(client)).build();
 | 
				
			||||||
        downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, swInInstallVerId));
 | 
					        downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, swInInstallVerId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -107,6 +107,8 @@ public class LwM2MClientSerDes {
 | 
				
			|||||||
        if (client.getPagingTransmissionWindow() != null) {
 | 
					        if (client.getPagingTransmissionWindow() != null) {
 | 
				
			||||||
            o.addProperty("pagingTransmissionWindow", client.getPagingTransmissionWindow());
 | 
					            o.addProperty("pagingTransmissionWindow", client.getPagingTransmissionWindow());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        o.addProperty("defaultObjectIDVer", client.getDefaultObjectIDVer().toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (client.getRegistration() != null) {
 | 
					        if (client.getRegistration() != null) {
 | 
				
			||||||
            String registrationAddress = client.getRegistration().getAddress().toString();
 | 
					            String registrationAddress = client.getRegistration().getAddress().toString();
 | 
				
			||||||
            JsonNode registrationNode = registrationSerDes.jSerialize(client.getRegistration());
 | 
					            JsonNode registrationNode = registrationSerDes.jSerialize(client.getRegistration());
 | 
				
			||||||
@ -339,6 +341,13 @@ public class LwM2MClientSerDes {
 | 
				
			|||||||
            pagingTransmissionWindowField.set(lwM2mClient, pagingTransmissionWindow.getAsLong());
 | 
					            pagingTransmissionWindowField.set(lwM2mClient, pagingTransmissionWindow.getAsLong());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        JsonElement defaultObjectIDVer = o.get("defaultObjectIDVer");
 | 
				
			||||||
 | 
					        if (defaultObjectIDVer != null) {
 | 
				
			||||||
 | 
					            Field defaultObjectIDVerField = lwM2mClientClass.getDeclaredField("defaultObjectIDVer");
 | 
				
			||||||
 | 
					            defaultObjectIDVerField.setAccessible(true);
 | 
				
			||||||
 | 
					            defaultObjectIDVerField.set(lwM2mClient, defaultObjectIDVer.getAsString());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        JsonElement registration = o.get("registration");
 | 
					        JsonElement registration = o.get("registration");
 | 
				
			||||||
        if (registration != null) {
 | 
					        if (registration != null) {
 | 
				
			||||||
            lwM2mClient.setRegistration(registrationSerDes.deserialize(toJsonNode(registration.getAsString())));
 | 
					            lwM2mClient.setRegistration(registrationSerDes.deserialize(toJsonNode(registration.getAsString())));
 | 
				
			||||||
 | 
				
			|||||||
@ -368,7 +368,7 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl
 | 
				
			|||||||
            LwM2mPath path = entry.getKey();
 | 
					            LwM2mPath path = entry.getKey();
 | 
				
			||||||
            LwM2mNode node = entry.getValue();
 | 
					            LwM2mNode node = entry.getValue();
 | 
				
			||||||
            LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
 | 
					            LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
 | 
				
			||||||
            String stringPath = convertObjectIdToVersionedId(path.toString(), registration);
 | 
					            String stringPath = convertObjectIdToVersionedId(path.toString(), lwM2MClient);
 | 
				
			||||||
            ObjectModel objectModelVersion = lwM2MClient.getObjectModel(stringPath, modelProvider);
 | 
					            ObjectModel objectModelVersion = lwM2MClient.getObjectModel(stringPath, modelProvider);
 | 
				
			||||||
            if (objectModelVersion != null) {
 | 
					            if (objectModelVersion != null) {
 | 
				
			||||||
                if (node instanceof LwM2mObject) {
 | 
					                if (node instanceof LwM2mObject) {
 | 
				
			||||||
@ -584,27 +584,27 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl
 | 
				
			|||||||
    private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode, int code) {
 | 
					    private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode, int code) {
 | 
				
			||||||
        Registration registration = lwM2MClient.getRegistration();
 | 
					        Registration registration = lwM2MClient.getRegistration();
 | 
				
			||||||
        if (lwM2MClient.saveResourceValue(path, lwM2mResource, modelProvider, mode)) {
 | 
					        if (lwM2MClient.saveResourceValue(path, lwM2mResource, modelProvider, mode)) {
 | 
				
			||||||
            if (path.equals(convertObjectIdToVersionedId(FW_NAME_ID, registration))) {
 | 
					            if (path.equals(convertObjectIdToVersionedId(FW_NAME_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentFirmwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue());
 | 
					                otaService.onCurrentFirmwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(FW_3_VER_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(FW_3_VER_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentFirmwareVersion3Update(lwM2MClient, (String) lwM2mResource.getValue());
 | 
					                otaService.onCurrentFirmwareVersion3Update(lwM2MClient, (String) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(FW_VER_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(FW_VER_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentFirmwareVersionUpdate(lwM2MClient, (String) lwM2mResource.getValue());
 | 
					                otaService.onCurrentFirmwareVersionUpdate(lwM2MClient, (String) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(FW_STATE_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(FW_STATE_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentFirmwareStateUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
					                otaService.onCurrentFirmwareStateUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(FW_RESULT_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(FW_RESULT_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentFirmwareResultUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
					                otaService.onCurrentFirmwareResultUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(FW_DELIVERY_METHOD, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(FW_DELIVERY_METHOD, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentFirmwareDeliveryMethodUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
					                otaService.onCurrentFirmwareDeliveryMethodUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(SW_NAME_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(SW_NAME_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentSoftwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue());
 | 
					                otaService.onCurrentSoftwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(SW_VER_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(SW_VER_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentSoftwareVersionUpdate(lwM2MClient, (String) lwM2mResource.getValue());
 | 
					                otaService.onCurrentSoftwareVersionUpdate(lwM2MClient, (String) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(SW_3_VER_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(SW_3_VER_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentSoftwareVersion3Update(lwM2MClient, (String) lwM2mResource.getValue());
 | 
					                otaService.onCurrentSoftwareVersion3Update(lwM2MClient, (String) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(SW_STATE_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(SW_STATE_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentSoftwareStateUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
					                otaService.onCurrentSoftwareStateUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
				
			||||||
            } else if (path.equals(convertObjectIdToVersionedId(SW_RESULT_ID, registration))) {
 | 
					            } else if (path.equals(convertObjectIdToVersionedId(SW_RESULT_ID, lwM2MClient))) {
 | 
				
			||||||
                otaService.onCurrentSoftwareResultUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
					                otaService.onCurrentSoftwareResultUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ResponseCode.BAD_REQUEST.getCode() > code) {
 | 
					            if (ResponseCode.BAD_REQUEST.getCode() > code) {
 | 
				
			||||||
@ -969,6 +969,10 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public LwM2mClientContext getClientContext(){
 | 
				
			||||||
 | 
					        return this.clientContext;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Map<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {
 | 
					    private Map<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {
 | 
				
			||||||
        Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId());
 | 
					        Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId());
 | 
				
			||||||
        return profile.getObserveAttr().getKeyName();
 | 
					        return profile.getObserveAttr().getKeyName();
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
 | 
				
			|||||||
import org.thingsboard.server.gen.transport.TransportProtos;
 | 
					import org.thingsboard.server.gen.transport.TransportProtos;
 | 
				
			||||||
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
 | 
					import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
 | 
				
			||||||
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
 | 
					import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
 | 
				
			||||||
 | 
					import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.Optional;
 | 
					import java.util.Optional;
 | 
				
			||||||
@ -77,4 +78,5 @@ public interface LwM2mUplinkMsgHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    LwM2mValueConverter getConverter();
 | 
					    LwM2mValueConverter getConverter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LwM2mClientContext getClientContext();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -20,16 +20,13 @@ import lombok.extern.slf4j.Slf4j;
 | 
				
			|||||||
import org.eclipse.californium.elements.config.Configuration;
 | 
					import org.eclipse.californium.elements.config.Configuration;
 | 
				
			||||||
import org.eclipse.leshan.core.model.LwM2mModel;
 | 
					import org.eclipse.leshan.core.model.LwM2mModel;
 | 
				
			||||||
import org.eclipse.leshan.core.model.ObjectLoader;
 | 
					import org.eclipse.leshan.core.model.ObjectLoader;
 | 
				
			||||||
import org.eclipse.leshan.core.model.ObjectModel;
 | 
					 | 
				
			||||||
import org.eclipse.leshan.core.model.ResourceModel;
 | 
					import org.eclipse.leshan.core.model.ResourceModel;
 | 
				
			||||||
import org.eclipse.leshan.core.model.StaticModel;
 | 
					import org.eclipse.leshan.core.model.StaticModel;
 | 
				
			||||||
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
 | 
					import org.eclipse.leshan.core.node.LwM2mMultipleResource;
 | 
				
			||||||
import org.eclipse.leshan.core.node.LwM2mPath;
 | 
					import org.eclipse.leshan.core.node.LwM2mPath;
 | 
				
			||||||
import org.eclipse.leshan.core.node.LwM2mResource;
 | 
					import org.eclipse.leshan.core.node.LwM2mResource;
 | 
				
			||||||
import org.eclipse.leshan.core.node.LwM2mSingleResource;
 | 
					import org.eclipse.leshan.core.node.LwM2mSingleResource;
 | 
				
			||||||
import org.eclipse.leshan.core.node.codec.CodecException;
 | 
					 | 
				
			||||||
import org.eclipse.leshan.core.util.Hex;
 | 
					import org.eclipse.leshan.core.util.Hex;
 | 
				
			||||||
import org.eclipse.leshan.server.registration.Registration;
 | 
					 | 
				
			||||||
import org.thingsboard.common.util.JacksonUtil;
 | 
					import org.thingsboard.common.util.JacksonUtil;
 | 
				
			||||||
import org.thingsboard.server.common.data.DeviceProfile;
 | 
					import org.thingsboard.server.common.data.DeviceProfile;
 | 
				
			||||||
import org.thingsboard.server.common.data.DeviceTransportType;
 | 
					import org.thingsboard.server.common.data.DeviceTransportType;
 | 
				
			||||||
@ -49,8 +46,6 @@ import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdate
 | 
				
			|||||||
import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult;
 | 
					import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult;
 | 
				
			||||||
import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState;
 | 
					import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Arrays;
 | 
					 | 
				
			||||||
import java.util.Date;
 | 
					 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
@ -84,56 +79,6 @@ public class LwM2MTransportUtil {
 | 
				
			|||||||
    public static final String LOG_LWM2M_WARN = "warn";
 | 
					    public static final String LOG_LWM2M_WARN = "warn";
 | 
				
			||||||
    public static final int BOOTSTRAP_DEFAULT_SHORT_ID_0 = 0;
 | 
					    public static final int BOOTSTRAP_DEFAULT_SHORT_ID_0 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public enum LwM2MClientStrategy {
 | 
					 | 
				
			||||||
        CLIENT_STRATEGY_1(1, "Read only resources marked as observation"),
 | 
					 | 
				
			||||||
        CLIENT_STRATEGY_2(2, "Read all client resources");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public int code;
 | 
					 | 
				
			||||||
        public String type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        LwM2MClientStrategy(int code, String type) {
 | 
					 | 
				
			||||||
            this.code = code;
 | 
					 | 
				
			||||||
            this.type = type;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public static LwM2MClientStrategy fromStrategyClientByType(String type) {
 | 
					 | 
				
			||||||
            for (LwM2MClientStrategy to : LwM2MClientStrategy.values()) {
 | 
					 | 
				
			||||||
                if (to.type.equals(type)) {
 | 
					 | 
				
			||||||
                    return to;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            throw new IllegalArgumentException(String.format("Unsupported Client Strategy type  : %s", type));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public static LwM2MClientStrategy fromStrategyClientByCode(int code) {
 | 
					 | 
				
			||||||
            for (LwM2MClientStrategy to : LwM2MClientStrategy.values()) {
 | 
					 | 
				
			||||||
                if (to.code == code) {
 | 
					 | 
				
			||||||
                    return to;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            throw new IllegalArgumentException(String.format("Unsupported Client Strategy code : %s", code));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath
 | 
					 | 
				
			||||||
            resourcePath) throws CodecException {
 | 
					 | 
				
			||||||
        switch (type) {
 | 
					 | 
				
			||||||
            case BOOLEAN:
 | 
					 | 
				
			||||||
            case INTEGER:
 | 
					 | 
				
			||||||
            case FLOAT:
 | 
					 | 
				
			||||||
                return String.valueOf(valueOld).equals(String.valueOf(valueNew));
 | 
					 | 
				
			||||||
            case TIME:
 | 
					 | 
				
			||||||
                return ((Date) valueOld).getTime() == ((Date) valueNew).getTime();
 | 
					 | 
				
			||||||
            case STRING:
 | 
					 | 
				
			||||||
            case OBJLNK:
 | 
					 | 
				
			||||||
                return valueOld.equals(valueNew);
 | 
					 | 
				
			||||||
            case OPAQUE:
 | 
					 | 
				
			||||||
                return Arrays.equals(Hex.decodeHex(((String) valueOld).toCharArray()), Hex.decodeHex(((String) valueNew).toCharArray()));
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                throw new CodecException("Invalid value type for resource %s, type %s", resourcePath, type);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) {
 | 
					    public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) {
 | 
				
			||||||
        String path = fromVersionedIdToObjectId(pathIdVer);
 | 
					        String path = fromVersionedIdToObjectId(pathIdVer);
 | 
				
			||||||
        LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert();
 | 
					        LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert();
 | 
				
			||||||
@ -210,22 +155,8 @@ public class LwM2MTransportUtil {
 | 
				
			|||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static String validPathIdVer(String pathIdVer, Registration registration) throws
 | 
					    public static String convertObjectIdToVersionedId(String path, LwM2mClient lwM2MClient) {
 | 
				
			||||||
            IllegalArgumentException {
 | 
					        String ver = String.valueOf(lwM2MClient.getSupportedObjectVersion(new LwM2mPath(path).getObjectId()));
 | 
				
			||||||
        if (!pathIdVer.contains(LWM2M_SEPARATOR_PATH)) {
 | 
					 | 
				
			||||||
            throw new IllegalArgumentException(String.format("Error:"));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH);
 | 
					 | 
				
			||||||
            if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
 | 
					 | 
				
			||||||
                return pathIdVer;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                return convertObjectIdToVersionedId(pathIdVer, registration);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static String convertObjectIdToVersionedId(String path, Registration registration) {
 | 
					 | 
				
			||||||
        String ver = String.valueOf(registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()));
 | 
					 | 
				
			||||||
        return convertObjectIdToVerId(path, ver);
 | 
					        return convertObjectIdToVerId(path, ver);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public static String convertObjectIdToVerId(String path, String ver) {
 | 
					    public static String convertObjectIdToVerId(String path, String ver) {
 | 
				
			||||||
@ -243,14 +174,6 @@ public class LwM2MTransportUtil {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static String validateObjectVerFromKey(String key) {
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            return (key.split(LWM2M_SEPARATOR_PATH)[1].split(LWM2M_SEPARATOR_KEY)[1]);
 | 
					 | 
				
			||||||
        } catch (Exception e) {
 | 
					 | 
				
			||||||
            return ObjectModel.DEFAULT_VERSION;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * "UNSIGNED_INTEGER":  // Number -> Integer Example:
 | 
					     * "UNSIGNED_INTEGER":  // Number -> Integer Example:
 | 
				
			||||||
     * Alarm Timestamp [32-bit unsigned integer]
 | 
					     * Alarm Timestamp [32-bit unsigned integer]
 | 
				
			||||||
 | 
				
			|||||||
@ -12,14 +12,14 @@
 | 
				
			|||||||
    "transportConfiguration": {
 | 
					    "transportConfiguration": {
 | 
				
			||||||
      "observeAttr": {
 | 
					      "observeAttr": {
 | 
				
			||||||
        "observe": [
 | 
					        "observe": [
 | 
				
			||||||
          "/3_1.1/0/0"
 | 
					          "/3_1.0/0/0"
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "attribute": [],
 | 
					        "attribute": [],
 | 
				
			||||||
        "telemetry": [
 | 
					        "telemetry": [
 | 
				
			||||||
          "/3_1.1/0/0"
 | 
					          "/3_1.0/0/0"
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "keyName": {
 | 
					        "keyName": {
 | 
				
			||||||
          "/3_1.1/0/0": "testData"
 | 
					          "/3_1.0/0/0": "testData"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "attributeLwm2m": {}
 | 
					        "attributeLwm2m": {}
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -44,8 +44,7 @@
 | 
				
			|||||||
        "clientOnlyObserveAfterConnect": 1,
 | 
					        "clientOnlyObserveAfterConnect": 1,
 | 
				
			||||||
        "fwUpdateStrategy": 1,
 | 
					        "fwUpdateStrategy": 1,
 | 
				
			||||||
        "swUpdateStrategy": 1,
 | 
					        "swUpdateStrategy": 1,
 | 
				
			||||||
        "powerMode": "DRX",
 | 
					        "powerMode": "DRX"
 | 
				
			||||||
        "compositeOperationsSupport": false
 | 
					 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "bootstrapServerUpdateEnable": false,
 | 
					      "bootstrapServerUpdateEnable": false,
 | 
				
			||||||
      "type": "LWM2M"
 | 
					      "type": "LWM2M"
 | 
				
			||||||
 | 
				
			|||||||
@ -23,9 +23,9 @@
 | 
				
			|||||||
        <Description1>
 | 
					        <Description1>
 | 
				
			||||||
            <![CDATA[]]></Description1>
 | 
					            <![CDATA[]]></Description1>
 | 
				
			||||||
        <ObjectID>3</ObjectID>
 | 
					        <ObjectID>3</ObjectID>
 | 
				
			||||||
        <ObjectURN>urn:oma:lwm2m:oma:3:1.1</ObjectURN>
 | 
					        <ObjectURN>urn:oma:lwm2m:oma:3</ObjectURN>
 | 
				
			||||||
        <LWM2MVersion>1.1</LWM2MVersion>
 | 
					        <LWM2MVersion>1.1</LWM2MVersion>
 | 
				
			||||||
        <ObjectVersion>1.1</ObjectVersion>
 | 
					        <ObjectVersion>1.0</ObjectVersion>
 | 
				
			||||||
        <MultipleInstances>Single</MultipleInstances>
 | 
					        <MultipleInstances>Single</MultipleInstances>
 | 
				
			||||||
        <Mandatory>Mandatory</Mandatory>
 | 
					        <Mandatory>Mandatory</Mandatory>
 | 
				
			||||||
        <Resources>
 | 
					        <Resources>
 | 
				
			||||||
 | 
				
			|||||||
@ -2,5 +2,5 @@
 | 
				
			|||||||
  "title": "",
 | 
					  "title": "",
 | 
				
			||||||
  "resourceType": "LWM2M_MODEL",
 | 
					  "resourceType": "LWM2M_MODEL",
 | 
				
			||||||
  "fileName": "test-model.xml",
 | 
					  "fileName": "test-model.xml",
 | 
				
			||||||
  "data": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLQoKICAgIENvcHlyaWdodCDCqSAyMDE2LTIwMjIgVGhlIFRoaW5nc2JvYXJkIEF1dGhvcnMKCiAgICBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICAgIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCiAgICBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAgICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiAgICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAgICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCi0tPgo8TFdNMk0geG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIKICAgICAgIHhzaTpub05hbWVzcGFjZVNjaGVtYUxvY2F0aW9uPSJodHRwOi8vd3d3Lm9wZW5tb2JpbGVhbGxpYW5jZS5vcmcvdGVjaC9wcm9maWxlcy9MV00yTS12MV8xLnhzZCI+CiAgICA8T2JqZWN0IE9iamVjdFR5cGU9Ik1PRGVmaW5pdGlvbiI+CiAgICAgICAgPE5hbWU+THdNMk0gTW9uaXRvcmluZzwvTmFtZT4KICAgICAgICA8RGVzY3JpcHRpb24xPgogICAgICAgICAgICA8IVtDREFUQVtdXT48L0Rlc2NyaXB0aW9uMT4KICAgICAgICA8T2JqZWN0SUQ+MzwvT2JqZWN0SUQ+CiAgICAgICAgPE9iamVjdFVSTj51cm46b21hOmx3bTJtOm9tYTozOjEuMTwvT2JqZWN0VVJOPgogICAgICAgIDxMV00yTVZlcnNpb24+MS4xPC9MV00yTVZlcnNpb24+CiAgICAgICAgPE9iamVjdFZlcnNpb24+MS4xPC9PYmplY3RWZXJzaW9uPgogICAgICAgIDxNdWx0aXBsZUluc3RhbmNlcz5TaW5nbGU8L011bHRpcGxlSW5zdGFuY2VzPgogICAgICAgIDxNYW5kYXRvcnk+TWFuZGF0b3J5PC9NYW5kYXRvcnk+CiAgICAgICAgPFJlc291cmNlcz4KICAgICAgICAgICAgPEl0ZW0gSUQ9IjAiPgogICAgICAgICAgICAgICAgPE5hbWU+VGVzdCBkYXRhPC9OYW1lPgogICAgICAgICAgICAgICAgPE9wZXJhdGlvbnM+UjwvT3BlcmF0aW9ucz4KICAgICAgICAgICAgICAgIDxNdWx0aXBsZUluc3RhbmNlcz5TaW5nbGU8L011bHRpcGxlSW5zdGFuY2VzPgogICAgICAgICAgICAgICAgPE1hbmRhdG9yeT5PcHRpb25hbDwvTWFuZGF0b3J5PgogICAgICAgICAgICAgICAgPFR5cGU+U3RyaW5nPC9UeXBlPgogICAgICAgICAgICAgICAgPFJhbmdlRW51bWVyYXRpb24+PC9SYW5nZUVudW1lcmF0aW9uPgogICAgICAgICAgICAgICAgPFVuaXRzPjwvVW5pdHM+CiAgICAgICAgICAgICAgICA8RGVzY3JpcHRpb24+PCFbQ0RBVEFbVGVzdCBkYXRhXV0+PC9EZXNjcmlwdGlvbj4KICAgICAgICAgICAgPC9JdGVtPgogICAgICAgIDwvUmVzb3VyY2VzPgogICAgICAgIDxEZXNjcmlwdGlvbjI+PC9EZXNjcmlwdGlvbjI+CiAgICA8L09iamVjdD4KPC9MV00yTT4K"
 | 
					  "data": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLQoKICAgIENvcHlyaWdodCDCqSAyMDE2LTIwMjQgVGhlIFRoaW5nc2JvYXJkIEF1dGhvcnMKCiAgICBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICAgIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCiAgICBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAgICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiAgICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAgICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCi0tPgo8TFdNMk0geG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIKICAgICAgIHhzaTpub05hbWVzcGFjZVNjaGVtYUxvY2F0aW9uPSJodHRwOi8vd3d3Lm9wZW5tb2JpbGVhbGxpYW5jZS5vcmcvdGVjaC9wcm9maWxlcy9MV00yTS12MV8xLnhzZCI+CiAgICA8T2JqZWN0IE9iamVjdFR5cGU9Ik1PRGVmaW5pdGlvbiI+CiAgICAgICAgPE5hbWU+THdNMk0gTW9uaXRvcmluZzwvTmFtZT4KICAgICAgICA8RGVzY3JpcHRpb24xPgogICAgICAgICAgICA8IVtDREFUQVtdXT48L0Rlc2NyaXB0aW9uMT4KICAgICAgICA8T2JqZWN0SUQ+MzwvT2JqZWN0SUQ+CiAgICAgICAgPE9iamVjdFVSTj51cm46b21hOmx3bTJtOm9tYTozPC9PYmplY3RVUk4+CiAgICAgICAgPExXTTJNVmVyc2lvbj4xLjE8L0xXTTJNVmVyc2lvbj4KICAgICAgICA8T2JqZWN0VmVyc2lvbj4xLjA8L09iamVjdFZlcnNpb24+CiAgICAgICAgPE11bHRpcGxlSW5zdGFuY2VzPlNpbmdsZTwvTXVsdGlwbGVJbnN0YW5jZXM+CiAgICAgICAgPE1hbmRhdG9yeT5NYW5kYXRvcnk8L01hbmRhdG9yeT4KICAgICAgICA8UmVzb3VyY2VzPgogICAgICAgICAgICA8SXRlbSBJRD0iMCI+CiAgICAgICAgICAgICAgICA8TmFtZT5UZXN0IGRhdGE8L05hbWU+CiAgICAgICAgICAgICAgICA8T3BlcmF0aW9ucz5SPC9PcGVyYXRpb25zPgogICAgICAgICAgICAgICAgPE11bHRpcGxlSW5zdGFuY2VzPlNpbmdsZTwvTXVsdGlwbGVJbnN0YW5jZXM+CiAgICAgICAgICAgICAgICA8TWFuZGF0b3J5Pk9wdGlvbmFsPC9NYW5kYXRvcnk+CiAgICAgICAgICAgICAgICA8VHlwZT5TdHJpbmc8L1R5cGU+CiAgICAgICAgICAgICAgICA8UmFuZ2VFbnVtZXJhdGlvbj48L1JhbmdlRW51bWVyYXRpb24+CiAgICAgICAgICAgICAgICA8VW5pdHM+PC9Vbml0cz4KICAgICAgICAgICAgICAgIDxEZXNjcmlwdGlvbj48IVtDREFUQVtUZXN0IGRhdGFdXT48L0Rlc2NyaXB0aW9uPgogICAgICAgICAgICA8L0l0ZW0+CiAgICAgICAgPC9SZXNvdXJjZXM+CiAgICAgICAgPERlc2NyaXB0aW9uMj48L0Rlc2NyaXB0aW9uMj4KICAgIDwvT2JqZWN0Pgo8L0xXTTJNPgo="
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user