committed by
GitHub
281 changed files with 9782 additions and 6530 deletions
@ -1,40 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.actors.device; |
|
||||
|
|
||||
import lombok.AllArgsConstructor; |
|
||||
import lombok.Data; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
import java.util.Optional; |
|
||||
|
|
||||
/** |
|
||||
* Created by ashvayka on 17.04.18. |
|
||||
*/ |
|
||||
@Data |
|
||||
@AllArgsConstructor |
|
||||
public final class PendingSessionMsgData { |
|
||||
|
|
||||
private final SessionId sessionId; |
|
||||
private final Optional<ServerAddress> serverAddress; |
|
||||
private final SessionMsgType sessionMsgType; |
|
||||
private final int requestId; |
|
||||
private final boolean replyOnQueueAck; |
|
||||
private int ackMsgCount; |
|
||||
|
|
||||
} |
|
||||
@ -1,156 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.actors.session; |
|
||||
|
|
||||
import akka.actor.ActorContext; |
|
||||
import akka.event.LoggingAdapter; |
|
||||
import org.thingsboard.server.actors.ActorSystemContext; |
|
||||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.common.msg.core.AttributesSubscribeMsg; |
|
||||
import org.thingsboard.server.common.msg.core.ResponseMsg; |
|
||||
import org.thingsboard.server.common.msg.core.RpcSubscribeMsg; |
|
||||
import org.thingsboard.server.common.msg.core.SessionCloseMsg; |
|
||||
import org.thingsboard.server.common.msg.core.SessionOpenMsg; |
|
||||
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.BasicSessionActorToAdaptorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.ex.SessionException; |
|
||||
|
|
||||
import java.util.HashMap; |
|
||||
import java.util.Map; |
|
||||
import java.util.Optional; |
|
||||
|
|
||||
class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
|
||||
|
|
||||
private boolean firstMsg = true; |
|
||||
private Map<Integer, DeviceToDeviceActorMsg> pendingMap = new HashMap<>(); |
|
||||
private Optional<ServerAddress> currentTargetServer; |
|
||||
private boolean subscribedToAttributeUpdates; |
|
||||
private boolean subscribedToRpcCommands; |
|
||||
|
|
||||
public ASyncMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { |
|
||||
super(ctx, logger, sessionId); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { |
|
||||
updateSessionCtx(msg, SessionType.ASYNC); |
|
||||
DeviceToDeviceActorMsg pendingMsg = toDeviceMsg(msg); |
|
||||
FromDeviceMsg fromDeviceMsg = pendingMsg.getPayload(); |
|
||||
if (firstMsg) { |
|
||||
if (fromDeviceMsg.getMsgType() != SessionMsgType.SESSION_OPEN) { |
|
||||
toDeviceMsg(new SessionOpenMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); |
|
||||
} |
|
||||
firstMsg = false; |
|
||||
} |
|
||||
switch (fromDeviceMsg.getMsgType()) { |
|
||||
case POST_TELEMETRY_REQUEST: |
|
||||
case POST_ATTRIBUTES_REQUEST: |
|
||||
FromDeviceRequestMsg requestMsg = (FromDeviceRequestMsg) fromDeviceMsg; |
|
||||
if (requestMsg.getRequestId() >= 0) { |
|
||||
logger.debug("[{}] Pending request {} registered", requestMsg.getRequestId(), requestMsg.getMsgType()); |
|
||||
//TODO: handle duplicates.
|
|
||||
pendingMap.put(requestMsg.getRequestId(), pendingMsg); |
|
||||
} |
|
||||
break; |
|
||||
case SUBSCRIBE_ATTRIBUTES_REQUEST: |
|
||||
subscribedToAttributeUpdates = true; |
|
||||
break; |
|
||||
case UNSUBSCRIBE_ATTRIBUTES_REQUEST: |
|
||||
subscribedToAttributeUpdates = false; |
|
||||
break; |
|
||||
case SUBSCRIBE_RPC_COMMANDS_REQUEST: |
|
||||
subscribedToRpcCommands = true; |
|
||||
break; |
|
||||
case UNSUBSCRIBE_RPC_COMMANDS_REQUEST: |
|
||||
subscribedToRpcCommands = false; |
|
||||
break; |
|
||||
default: |
|
||||
break; |
|
||||
} |
|
||||
currentTargetServer = forwardToAppActor(ctx, pendingMsg); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { |
|
||||
try { |
|
||||
if (msg.getSessionMsgType() != SessionMsgType.SESSION_CLOSE) { |
|
||||
switch (msg.getSessionMsgType()) { |
|
||||
case STATUS_CODE_RESPONSE: |
|
||||
case GET_ATTRIBUTES_RESPONSE: |
|
||||
ResponseMsg responseMsg = (ResponseMsg) msg; |
|
||||
if (responseMsg.getRequestId() >= 0) { |
|
||||
logger.debug("[{}] Pending request processed: {}", responseMsg.getRequestId(), responseMsg); |
|
||||
pendingMap.remove(responseMsg.getRequestId()); |
|
||||
} |
|
||||
break; |
|
||||
default: |
|
||||
break; |
|
||||
} |
|
||||
sessionCtx.onMsg(new BasicSessionActorToAdaptorMsg(this.sessionCtx, msg)); |
|
||||
} else { |
|
||||
sessionCtx.onMsg(org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg.onCredentialsRevoked(sessionCtx.getSessionId())); |
|
||||
} |
|
||||
} catch (SessionException e) { |
|
||||
logger.warning("Failed to push session response msg", e); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg) { |
|
||||
// TODO Auto-generated method stub
|
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
protected void cleanupSession(ActorContext ctx) { |
|
||||
toDeviceMsg(new SessionCloseMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { |
|
||||
if (pendingMap.size() > 0 || subscribedToAttributeUpdates || subscribedToRpcCommands) { |
|
||||
Optional<ServerAddress> newTargetServer = systemContext.getRoutingService().resolveById(getDeviceId()); |
|
||||
if (!newTargetServer.equals(currentTargetServer)) { |
|
||||
firstMsg = true; |
|
||||
currentTargetServer = newTargetServer; |
|
||||
pendingMap.values().forEach(v -> { |
|
||||
forwardToAppActor(context, v, currentTargetServer); |
|
||||
if (currentTargetServer.isPresent()) { |
|
||||
logger.debug("[{}] Forwarded msg to new server: {}", sessionId, currentTargetServer.get()); |
|
||||
} else { |
|
||||
logger.debug("[{}] Forwarded msg to local server.", sessionId); |
|
||||
} |
|
||||
}); |
|
||||
if (subscribedToAttributeUpdates) { |
|
||||
toDeviceMsg(new AttributesSubscribeMsg()).ifPresent(m -> forwardToAppActor(context, m, currentTargetServer)); |
|
||||
logger.debug("[{}] Forwarded attributes subscription.", sessionId); |
|
||||
} |
|
||||
if (subscribedToRpcCommands) { |
|
||||
toDeviceMsg(new RpcSubscribeMsg()).ifPresent(m -> forwardToAppActor(context, m, currentTargetServer)); |
|
||||
logger.debug("[{}] Forwarded rpc commands subscription.", sessionId); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,122 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.actors.session; |
|
||||
|
|
||||
import akka.actor.ActorContext; |
|
||||
import akka.actor.ActorRef; |
|
||||
import akka.event.LoggingAdapter; |
|
||||
import org.thingsboard.server.actors.ActorSystemContext; |
|
||||
import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
|
||||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|
||||
import org.thingsboard.server.common.data.id.DeviceId; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.common.msg.device.BasicDeviceToDeviceActorMsg; |
|
||||
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.AdaptorToSessionActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionContext; |
|
||||
import org.thingsboard.server.common.msg.session.SessionCtrlMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; |
|
||||
|
|
||||
import java.util.Optional; |
|
||||
|
|
||||
abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgProcessor { |
|
||||
|
|
||||
protected final SessionId sessionId; |
|
||||
protected SessionContext sessionCtx; |
|
||||
protected DeviceToDeviceActorMsg deviceToDeviceActorMsgPrototype; |
|
||||
|
|
||||
protected AbstractSessionActorMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { |
|
||||
super(ctx, logger); |
|
||||
this.sessionId = sessionId; |
|
||||
} |
|
||||
|
|
||||
protected abstract void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg); |
|
||||
|
|
||||
protected abstract void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg); |
|
||||
|
|
||||
protected abstract void processToDeviceMsg(ActorContext context, ToDeviceMsg msg); |
|
||||
|
|
||||
public abstract void processClusterEvent(ActorContext context, ClusterEventMsg msg); |
|
||||
|
|
||||
protected void processSessionCtrlMsg(ActorContext ctx, SessionCtrlMsg msg) { |
|
||||
if (msg instanceof SessionCloseMsg) { |
|
||||
cleanupSession(ctx); |
|
||||
terminateSession(ctx, sessionId); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected void cleanupSession(ActorContext ctx) { |
|
||||
} |
|
||||
|
|
||||
protected void updateSessionCtx(TransportToDeviceSessionActorMsg msg, SessionType type) { |
|
||||
sessionCtx = msg.getSessionMsg().getSessionContext(); |
|
||||
deviceToDeviceActorMsgPrototype = new BasicDeviceToDeviceActorMsg(msg, type); |
|
||||
} |
|
||||
|
|
||||
protected DeviceToDeviceActorMsg toDeviceMsg(TransportToDeviceSessionActorMsg msg) { |
|
||||
AdaptorToSessionActorMsg adaptorMsg = msg.getSessionMsg(); |
|
||||
return new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, adaptorMsg.getMsg()); |
|
||||
} |
|
||||
|
|
||||
protected Optional<DeviceToDeviceActorMsg> toDeviceMsg(FromDeviceMsg msg) { |
|
||||
if (deviceToDeviceActorMsgPrototype != null) { |
|
||||
return Optional.of(new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, msg)); |
|
||||
} else { |
|
||||
return Optional.empty(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward) { |
|
||||
Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); |
|
||||
forwardToAppActor(ctx, toForward, address); |
|
||||
return address; |
|
||||
} |
|
||||
|
|
||||
protected Optional<ServerAddress> forwardToAppActorIfAddressChanged(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) { |
|
||||
|
|
||||
Optional<ServerAddress> newAddress = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); |
|
||||
if (!newAddress.equals(oldAddress)) { |
|
||||
getAppActor().tell(new SendToClusterMsg(toForward.getDeviceId(), toForward |
|
||||
.toOtherAddress(systemContext.getRoutingService().getCurrentServer())), ctx.self()); |
|
||||
} |
|
||||
return newAddress; |
|
||||
} |
|
||||
|
|
||||
protected void forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> address) { |
|
||||
if (address.isPresent()) { |
|
||||
systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(address.get(), |
|
||||
toForward.toOtherAddress(systemContext.getRoutingService().getCurrentServer()))); |
|
||||
} else { |
|
||||
getAppActor().tell(toForward, ctx.self()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static void terminateSession(ActorContext ctx, SessionId sessionId) { |
|
||||
ctx.parent().tell(new SessionTerminationMsg(sessionId), ActorRef.noSender()); |
|
||||
ctx.stop(ctx.self()); |
|
||||
} |
|
||||
|
|
||||
public DeviceId getDeviceId() { |
|
||||
return deviceToDeviceActorMsgPrototype.getDeviceId(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,143 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.actors.session; |
|
||||
|
|
||||
import akka.actor.OneForOneStrategy; |
|
||||
import akka.actor.SupervisorStrategy; |
|
||||
import akka.event.Logging; |
|
||||
import akka.event.LoggingAdapter; |
|
||||
import org.thingsboard.server.actors.ActorSystemContext; |
|
||||
import org.thingsboard.server.actors.service.ContextAwareActor; |
|
||||
import org.thingsboard.server.actors.service.ContextBasedCreator; |
|
||||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|
||||
import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionCtrlMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionType; |
|
||||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; |
|
||||
import scala.concurrent.duration.Duration; |
|
||||
|
|
||||
public class SessionActor extends ContextAwareActor { |
|
||||
|
|
||||
private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); |
|
||||
|
|
||||
private final SessionId sessionId; |
|
||||
private AbstractSessionActorMsgProcessor processor; |
|
||||
|
|
||||
private SessionActor(ActorSystemContext systemContext, SessionId sessionId) { |
|
||||
super(systemContext); |
|
||||
this.sessionId = sessionId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SupervisorStrategy supervisorStrategy() { |
|
||||
return new OneForOneStrategy(-1, Duration.Inf(), |
|
||||
throwable -> { |
|
||||
logger.error(throwable, "Unknown session error"); |
|
||||
if (throwable instanceof Error) { |
|
||||
return OneForOneStrategy.escalate(); |
|
||||
} else { |
|
||||
return OneForOneStrategy.resume(); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
protected boolean process(TbActorMsg msg) { |
|
||||
switch (msg.getMsgType()) { |
|
||||
case TRANSPORT_TO_DEVICE_SESSION_ACTOR_MSG: |
|
||||
processTransportToSessionMsg((TransportToDeviceSessionActorMsg) msg); |
|
||||
break; |
|
||||
case ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG: |
|
||||
processActorsToSessionMsg((ActorSystemToDeviceSessionActorMsg) msg); |
|
||||
break; |
|
||||
case SESSION_TIMEOUT_MSG: |
|
||||
processTimeoutMsg((SessionTimeoutMsg) msg); |
|
||||
break; |
|
||||
case SESSION_CTRL_MSG: |
|
||||
processSessionCloseMsg((SessionCtrlMsg) msg); |
|
||||
break; |
|
||||
case CLUSTER_EVENT_MSG: |
|
||||
processClusterEvent((ClusterEventMsg) msg); |
|
||||
break; |
|
||||
default: return false; |
|
||||
} |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
private void processClusterEvent(ClusterEventMsg msg) { |
|
||||
processor.processClusterEvent(context(), msg); |
|
||||
} |
|
||||
|
|
||||
private void processTransportToSessionMsg(TransportToDeviceSessionActorMsg msg) { |
|
||||
initProcessor(msg); |
|
||||
processor.processToDeviceActorMsg(context(), msg); |
|
||||
} |
|
||||
|
|
||||
private void processActorsToSessionMsg(ActorSystemToDeviceSessionActorMsg msg) { |
|
||||
processor.processToDeviceMsg(context(), msg.getMsg()); |
|
||||
} |
|
||||
|
|
||||
private void processTimeoutMsg(SessionTimeoutMsg msg) { |
|
||||
if (processor != null) { |
|
||||
processor.processTimeoutMsg(context(), msg); |
|
||||
} else { |
|
||||
logger.warning("[{}] Can't process timeout msg: {} without processor", sessionId, msg); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void processSessionCloseMsg(SessionCtrlMsg msg) { |
|
||||
if (processor != null) { |
|
||||
processor.processSessionCtrlMsg(context(), msg); |
|
||||
} else if (msg instanceof SessionCloseMsg) { |
|
||||
AbstractSessionActorMsgProcessor.terminateSession(context(), sessionId); |
|
||||
} else { |
|
||||
logger.warning("[{}] Can't process session ctrl msg: {} without processor", sessionId, msg); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void initProcessor(TransportToDeviceSessionActorMsg msg) { |
|
||||
if (processor == null) { |
|
||||
SessionMsg sessionMsg = (SessionMsg) msg.getSessionMsg(); |
|
||||
if (sessionMsg.getSessionContext().getSessionType() == SessionType.SYNC) { |
|
||||
processor = new SyncMsgProcessor(systemContext, logger, sessionId); |
|
||||
} else { |
|
||||
processor = new ASyncMsgProcessor(systemContext, logger, sessionId); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static class ActorCreator extends ContextBasedCreator<SessionActor> { |
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
private final SessionId sessionId; |
|
||||
|
|
||||
public ActorCreator(ActorSystemContext context, SessionId sessionId) { |
|
||||
super(context); |
|
||||
this.sessionId = sessionId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionActor create() throws Exception { |
|
||||
return new SessionActor(context, sessionId); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,180 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.actors.session; |
|
||||
|
|
||||
import akka.actor.ActorInitializationException; |
|
||||
import akka.actor.ActorRef; |
|
||||
import akka.actor.InvalidActorNameException; |
|
||||
import akka.actor.LocalActorRef; |
|
||||
import akka.actor.OneForOneStrategy; |
|
||||
import akka.actor.Props; |
|
||||
import akka.actor.SupervisorStrategy; |
|
||||
import akka.actor.Terminated; |
|
||||
import akka.event.Logging; |
|
||||
import akka.event.LoggingAdapter; |
|
||||
import akka.japi.Function; |
|
||||
import org.thingsboard.server.actors.ActorSystemContext; |
|
||||
import org.thingsboard.server.actors.service.ContextAwareActor; |
|
||||
import org.thingsboard.server.actors.service.ContextBasedCreator; |
|
||||
import org.thingsboard.server.actors.service.DefaultActorService; |
|
||||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|
||||
import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; |
|
||||
import org.thingsboard.server.common.msg.core.SessionCloseMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionCtrlMsg; |
|
||||
import scala.concurrent.duration.Duration; |
|
||||
|
|
||||
import java.util.HashMap; |
|
||||
import java.util.Map; |
|
||||
|
|
||||
public class SessionManagerActor extends ContextAwareActor { |
|
||||
|
|
||||
private static final int INITIAL_SESSION_MAP_SIZE = 1024; |
|
||||
|
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().system(), this); |
|
||||
|
|
||||
private final Map<String, ActorRef> sessionActors; |
|
||||
|
|
||||
SessionManagerActor(ActorSystemContext systemContext) { |
|
||||
super(systemContext); |
|
||||
this.sessionActors = new HashMap<>(INITIAL_SESSION_MAP_SIZE); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SupervisorStrategy supervisorStrategy() { |
|
||||
return strategy; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
protected boolean process(TbActorMsg msg) { |
|
||||
//TODO Move everything here, to work with TbActorMsg
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onReceive(Object msg) throws Exception { |
|
||||
if (msg instanceof SessionCtrlMsg) { |
|
||||
onSessionCtrlMsg((SessionCtrlMsg) msg); |
|
||||
} else if (msg instanceof SessionAwareMsg) { |
|
||||
forwardToSessionActor((SessionAwareMsg) msg); |
|
||||
} else if (msg instanceof SessionTerminationMsg) { |
|
||||
onSessionTermination((SessionTerminationMsg) msg); |
|
||||
} else if (msg instanceof Terminated) { |
|
||||
onTermination((Terminated) msg); |
|
||||
} else if (msg instanceof SessionTimeoutMsg) { |
|
||||
onSessionTimeout((SessionTimeoutMsg) msg); |
|
||||
} else if (msg instanceof ClusterEventMsg) { |
|
||||
broadcast(msg); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void broadcast(Object msg) { |
|
||||
sessionActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
|
||||
} |
|
||||
|
|
||||
private void onSessionTimeout(SessionTimeoutMsg msg) { |
|
||||
String sessionIdStr = msg.getSessionId().toUidStr(); |
|
||||
ActorRef sessionActor = sessionActors.get(sessionIdStr); |
|
||||
if (sessionActor != null) { |
|
||||
sessionActor.tell(msg, ActorRef.noSender()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void onSessionCtrlMsg(SessionCtrlMsg msg) { |
|
||||
String sessionIdStr = msg.getSessionId().toUidStr(); |
|
||||
ActorRef sessionActor = sessionActors.get(sessionIdStr); |
|
||||
if (sessionActor != null) { |
|
||||
sessionActor.tell(msg, ActorRef.noSender()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void onSessionTermination(SessionTerminationMsg msg) { |
|
||||
String sessionIdStr = msg.getId().toUidStr(); |
|
||||
ActorRef sessionActor = sessionActors.remove(sessionIdStr); |
|
||||
if (sessionActor != null) { |
|
||||
log.debug("[{}] Removed session actor.", sessionIdStr); |
|
||||
//TODO: onSubscriptionUpdate device actor about session close;
|
|
||||
} else { |
|
||||
log.debug("[{}] Session actor was already removed.", sessionIdStr); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void forwardToSessionActor(SessionAwareMsg msg) { |
|
||||
if (msg instanceof ActorSystemToDeviceSessionActorMsg || msg instanceof SessionCloseMsg) { |
|
||||
String sessionIdStr = msg.getSessionId().toUidStr(); |
|
||||
ActorRef sessionActor = sessionActors.get(sessionIdStr); |
|
||||
if (sessionActor != null) { |
|
||||
sessionActor.tell(msg, ActorRef.noSender()); |
|
||||
} else { |
|
||||
log.debug("[{}] Session actor was already removed.", sessionIdStr); |
|
||||
} |
|
||||
} else { |
|
||||
try { |
|
||||
getOrCreateSessionActor(msg.getSessionId()).tell(msg, self()); |
|
||||
} catch (InvalidActorNameException e) { |
|
||||
log.info("Invalid msg : {}", msg); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private ActorRef getOrCreateSessionActor(SessionId sessionId) { |
|
||||
String sessionIdStr = sessionId.toUidStr(); |
|
||||
ActorRef sessionActor = sessionActors.get(sessionIdStr); |
|
||||
if (sessionActor == null) { |
|
||||
log.debug("[{}] Creating session actor.", sessionIdStr); |
|
||||
sessionActor = context().actorOf( |
|
||||
Props.create(new SessionActor.ActorCreator(systemContext, sessionId)).withDispatcher(DefaultActorService.SESSION_DISPATCHER_NAME), |
|
||||
sessionIdStr); |
|
||||
sessionActors.put(sessionIdStr, sessionActor); |
|
||||
log.debug("[{}] Created session actor.", sessionIdStr); |
|
||||
} |
|
||||
return sessionActor; |
|
||||
} |
|
||||
|
|
||||
private void onTermination(Terminated message) { |
|
||||
ActorRef terminated = message.actor(); |
|
||||
if (terminated instanceof LocalActorRef) { |
|
||||
log.info("Removed actor: {}.", terminated); |
|
||||
//TODO: cleanup session actors map
|
|
||||
} else { |
|
||||
throw new IllegalStateException("Remote actors are not supported!"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static class ActorCreator extends ContextBasedCreator<SessionManagerActor> { |
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
public ActorCreator(ActorSystemContext context) { |
|
||||
super(context); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionManagerActor create() throws Exception { |
|
||||
return new SessionManagerActor(context); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() { |
|
||||
@Override |
|
||||
public SupervisorStrategy.Directive apply(Throwable t) { |
|
||||
logger.error(t, "Unknown failure"); |
|
||||
return SupervisorStrategy.stop(); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
@ -1,95 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.actors.session; |
|
||||
|
|
||||
import akka.actor.ActorContext; |
|
||||
import akka.event.LoggingAdapter; |
|
||||
import org.thingsboard.server.actors.ActorSystemContext; |
|
||||
import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.BasicSessionActorToAdaptorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionContext; |
|
||||
import org.thingsboard.server.common.msg.session.SessionType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|
||||
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; |
|
||||
import org.thingsboard.server.common.msg.session.ex.SessionException; |
|
||||
|
|
||||
import java.util.Optional; |
|
||||
|
|
||||
class SyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
|
||||
private DeviceToDeviceActorMsg pendingMsg; |
|
||||
private Optional<ServerAddress> currentTargetServer; |
|
||||
private boolean pendingResponse; |
|
||||
|
|
||||
public SyncMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { |
|
||||
super(ctx, logger, sessionId); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { |
|
||||
updateSessionCtx(msg, SessionType.SYNC); |
|
||||
pendingMsg = toDeviceMsg(msg); |
|
||||
pendingResponse = true; |
|
||||
currentTargetServer = forwardToAppActor(ctx, pendingMsg); |
|
||||
scheduleMsgWithDelay(ctx, new SessionTimeoutMsg(sessionId), getTimeout(systemContext, msg.getSessionMsg().getSessionContext()), ctx.parent()); |
|
||||
} |
|
||||
|
|
||||
public void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg) { |
|
||||
if (pendingResponse) { |
|
||||
try { |
|
||||
sessionCtx.onMsg(SessionCloseMsg.onTimeout(sessionId)); |
|
||||
} catch (SessionException e) { |
|
||||
logger.warning("Failed to push session close msg", e); |
|
||||
} |
|
||||
terminateSession(context, this.sessionId); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { |
|
||||
try { |
|
||||
sessionCtx.onMsg(new BasicSessionActorToAdaptorMsg(this.sessionCtx, msg)); |
|
||||
pendingResponse = false; |
|
||||
} catch (SessionException e) { |
|
||||
logger.warning("Failed to push session response msg", e); |
|
||||
} |
|
||||
terminateSession(context, this.sessionId); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { |
|
||||
if (pendingResponse) { |
|
||||
Optional<ServerAddress> newTargetServer = forwardToAppActorIfAddressChanged(context, pendingMsg, currentTargetServer); |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
if (!newTargetServer.equals(currentTargetServer)) { |
|
||||
if (newTargetServer.isPresent()) { |
|
||||
logger.debug("[{}] Forwarded msg to new server: {}", sessionId, newTargetServer.get()); |
|
||||
} else { |
|
||||
logger.debug("[{}] Forwarded msg to local server.", sessionId); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
currentTargetServer = newTargetServer; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private long getTimeout(ActorSystemContext ctx, SessionContext sessionCtx) { |
|
||||
return sessionCtx.getTimeout() > 0 ? sessionCtx.getTimeout() : ctx.getSyncSessionTimeout(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.actors.shared; |
|
||||
|
|
||||
import lombok.Data; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.MsgType; |
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
|
|
||||
@Data |
|
||||
public class SessionTimeoutMsg implements Serializable, TbActorMsg { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
private final SessionId sessionId; |
|
||||
|
|
||||
@Override |
|
||||
public MsgType getMsgType() { |
|
||||
return MsgType.SESSION_TIMEOUT_MSG; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,173 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.transport; |
||||
|
|
||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import com.google.common.util.concurrent.Futures; |
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.thingsboard.server.common.data.Device; |
||||
|
import org.thingsboard.server.common.data.id.DeviceId; |
||||
|
import org.thingsboard.server.common.data.relation.EntityRelation; |
||||
|
import org.thingsboard.server.common.data.security.DeviceCredentials; |
||||
|
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
||||
|
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
||||
|
import org.thingsboard.server.dao.device.DeviceService; |
||||
|
import org.thingsboard.server.dao.relation.RelationService; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; |
||||
|
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate; |
||||
|
import org.thingsboard.server.kafka.TBKafkaProducerTemplate; |
||||
|
import org.thingsboard.server.kafka.TbKafkaResponseTemplate; |
||||
|
import org.thingsboard.server.kafka.TbKafkaSettings; |
||||
|
import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
||||
|
import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
||||
|
import org.thingsboard.server.service.state.DeviceStateService; |
||||
|
|
||||
|
import javax.annotation.PostConstruct; |
||||
|
import javax.annotation.PreDestroy; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.Executors; |
||||
|
import java.util.concurrent.locks.ReentrantLock; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 05.10.18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class LocalTransportApiService implements TransportApiService { |
||||
|
|
||||
|
private static final ObjectMapper mapper = new ObjectMapper(); |
||||
|
|
||||
|
@Autowired |
||||
|
private DeviceService deviceService; |
||||
|
|
||||
|
@Autowired |
||||
|
private RelationService relationService; |
||||
|
|
||||
|
@Autowired |
||||
|
private DeviceCredentialsService deviceCredentialsService; |
||||
|
|
||||
|
@Autowired |
||||
|
private DeviceStateService deviceStateService; |
||||
|
|
||||
|
@Autowired |
||||
|
private DbCallbackExecutorService dbCallbackExecutorService; |
||||
|
|
||||
|
private ReentrantLock deviceCreationLock = new ReentrantLock(); |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<TransportApiResponseMsg> handle(TransportApiRequestMsg transportApiRequestMsg) { |
||||
|
if (transportApiRequestMsg.hasValidateTokenRequestMsg()) { |
||||
|
ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg(); |
||||
|
return validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN); |
||||
|
} else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) { |
||||
|
ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg(); |
||||
|
return validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE); |
||||
|
} else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { |
||||
|
return handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()); |
||||
|
} |
||||
|
return getEmptyTransportApiResponseFuture(); |
||||
|
} |
||||
|
|
||||
|
private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) { |
||||
|
//TODO: Make async and enable caching
|
||||
|
DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(credentialsId); |
||||
|
if (credentials != null && credentials.getCredentialsType() == credentialsType) { |
||||
|
return getDeviceInfo(credentials.getDeviceId()); |
||||
|
} else { |
||||
|
return getEmptyTransportApiResponseFuture(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private ListenableFuture<TransportApiResponseMsg> handle(GetOrCreateDeviceFromGatewayRequestMsg requestMsg) { |
||||
|
DeviceId gatewayId = new DeviceId(new UUID(requestMsg.getGatewayIdMSB(), requestMsg.getGatewayIdLSB())); |
||||
|
ListenableFuture<Device> gatewayFuture = deviceService.findDeviceByIdAsync(gatewayId); |
||||
|
return Futures.transform(gatewayFuture, gateway -> { |
||||
|
deviceCreationLock.lock(); |
||||
|
try { |
||||
|
Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), requestMsg.getDeviceName()); |
||||
|
if (device == null) { |
||||
|
device = new Device(); |
||||
|
device.setTenantId(gateway.getTenantId()); |
||||
|
device.setName(requestMsg.getDeviceName()); |
||||
|
device.setType(requestMsg.getDeviceType()); |
||||
|
device.setCustomerId(gateway.getCustomerId()); |
||||
|
device = deviceService.saveDevice(device); |
||||
|
relationService.saveRelationAsync(new EntityRelation(gateway.getId(), device.getId(), "Created")); |
||||
|
deviceStateService.onDeviceAdded(device); |
||||
|
} |
||||
|
return TransportApiResponseMsg.newBuilder() |
||||
|
.setGetOrCreateDeviceResponseMsg(GetOrCreateDeviceFromGatewayResponseMsg.newBuilder().setDeviceInfo(getDeviceInfoProto(device)).build()).build(); |
||||
|
} catch (JsonProcessingException e) { |
||||
|
log.warn("[{}] Failed to lookup device by gateway id and name", gatewayId, requestMsg.getDeviceName(), e); |
||||
|
throw new RuntimeException(e); |
||||
|
} finally { |
||||
|
deviceCreationLock.unlock(); |
||||
|
} |
||||
|
}, dbCallbackExecutorService); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId) { |
||||
|
return Futures.transform(deviceService.findDeviceByIdAsync(deviceId), device -> { |
||||
|
if (device == null) { |
||||
|
log.trace("[{}] Failed to lookup device by id", deviceId); |
||||
|
return getEmptyTransportApiResponse(); |
||||
|
} |
||||
|
try { |
||||
|
return TransportApiResponseMsg.newBuilder() |
||||
|
.setValidateTokenResponseMsg(ValidateDeviceCredentialsResponseMsg.newBuilder().setDeviceInfo(getDeviceInfoProto(device)).build()).build(); |
||||
|
} catch (JsonProcessingException e) { |
||||
|
log.warn("[{}] Failed to lookup device by id", deviceId, e); |
||||
|
return getEmptyTransportApiResponse(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private DeviceInfoProto getDeviceInfoProto(Device device) throws JsonProcessingException { |
||||
|
return DeviceInfoProto.newBuilder() |
||||
|
.setTenantIdMSB(device.getTenantId().getId().getMostSignificantBits()) |
||||
|
.setTenantIdLSB(device.getTenantId().getId().getLeastSignificantBits()) |
||||
|
.setDeviceIdMSB(device.getId().getId().getMostSignificantBits()) |
||||
|
.setDeviceIdLSB(device.getId().getId().getLeastSignificantBits()) |
||||
|
.setDeviceName(device.getName()) |
||||
|
.setDeviceType(device.getType()) |
||||
|
.setAdditionalInfo(mapper.writeValueAsString(device.getAdditionalInfo())) |
||||
|
.build(); |
||||
|
} |
||||
|
|
||||
|
private ListenableFuture<TransportApiResponseMsg> getEmptyTransportApiResponseFuture() { |
||||
|
return Futures.immediateFuture(getEmptyTransportApiResponse()); |
||||
|
} |
||||
|
|
||||
|
private TransportApiResponseMsg getEmptyTransportApiResponse() { |
||||
|
return TransportApiResponseMsg.newBuilder() |
||||
|
.setValidateTokenResponseMsg(ValidateDeviceCredentialsResponseMsg.getDefaultInstance()).build(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,209 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.transport; |
||||
|
|
||||
|
import akka.actor.ActorRef; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.thingsboard.rule.engine.api.util.DonAsynchron; |
||||
|
import org.thingsboard.server.actors.ActorSystemContext; |
||||
|
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
||||
|
import org.thingsboard.server.common.transport.SessionMsgListener; |
||||
|
import org.thingsboard.server.common.transport.TransportService; |
||||
|
import org.thingsboard.server.common.transport.TransportServiceCallback; |
||||
|
import org.thingsboard.server.common.transport.service.AbstractTransportService; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; |
||||
|
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; |
||||
|
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
||||
|
import org.thingsboard.server.service.encoding.DataDecodingEncodingService; |
||||
|
import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
||||
|
|
||||
|
import javax.annotation.PostConstruct; |
||||
|
import javax.annotation.PreDestroy; |
||||
|
import java.util.Optional; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
import java.util.concurrent.ConcurrentMap; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.Executors; |
||||
|
import java.util.concurrent.ScheduledExecutorService; |
||||
|
import java.util.concurrent.SynchronousQueue; |
||||
|
import java.util.concurrent.ThreadPoolExecutor; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
import java.util.function.Consumer; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 12.10.18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Service |
||||
|
@ConditionalOnProperty(prefix = "transport", value = "type", havingValue = "local") |
||||
|
public class LocalTransportService extends AbstractTransportService implements RuleEngineTransportService { |
||||
|
|
||||
|
@Autowired |
||||
|
private TransportApiService transportApiService; |
||||
|
|
||||
|
@Autowired |
||||
|
private ActorSystemContext actorContext; |
||||
|
|
||||
|
//TODO: completely replace this routing with the Kafka routing by partition ids.
|
||||
|
@Autowired |
||||
|
private ClusterRoutingService routingService; |
||||
|
@Autowired |
||||
|
private ClusterRpcService rpcService; |
||||
|
@Autowired |
||||
|
private DataDecodingEncodingService encodingService; |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
super.init(); |
||||
|
} |
||||
|
|
||||
|
@PreDestroy |
||||
|
public void destroy() { |
||||
|
super.destroy(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(ValidateDeviceTokenRequestMsg msg, TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> callback) { |
||||
|
DonAsynchron.withCallback( |
||||
|
transportApiService.handle(TransportApiRequestMsg.newBuilder().setValidateTokenRequestMsg(msg).build()), |
||||
|
transportApiResponseMsg -> { |
||||
|
if (callback != null) { |
||||
|
callback.onSuccess(transportApiResponseMsg.getValidateTokenResponseMsg()); |
||||
|
} |
||||
|
}, |
||||
|
getThrowableConsumer(callback), transportCallbackExecutor); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(ValidateDeviceX509CertRequestMsg msg, TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> callback) { |
||||
|
DonAsynchron.withCallback( |
||||
|
transportApiService.handle(TransportApiRequestMsg.newBuilder().setValidateX509CertRequestMsg(msg).build()), |
||||
|
transportApiResponseMsg -> { |
||||
|
if (callback != null) { |
||||
|
callback.onSuccess(transportApiResponseMsg.getValidateTokenResponseMsg()); |
||||
|
} |
||||
|
}, |
||||
|
getThrowableConsumer(callback), transportCallbackExecutor); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(GetOrCreateDeviceFromGatewayRequestMsg msg, TransportServiceCallback<GetOrCreateDeviceFromGatewayResponseMsg> callback) { |
||||
|
DonAsynchron.withCallback( |
||||
|
transportApiService.handle(TransportApiRequestMsg.newBuilder().setGetOrCreateDeviceRequestMsg(msg).build()), |
||||
|
transportApiResponseMsg -> { |
||||
|
if (callback != null) { |
||||
|
callback.onSuccess(transportApiResponseMsg.getGetOrCreateDeviceResponseMsg()); |
||||
|
} |
||||
|
}, |
||||
|
getThrowableConsumer(callback), transportCallbackExecutor); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(SessionInfoProto sessionInfo, SessionEventMsg msg, TransportServiceCallback<Void> callback) { |
||||
|
forwardToDeviceActor(TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setSessionEvent(msg).build(), callback); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(SessionInfoProto sessionInfo, PostTelemetryMsg msg, TransportServiceCallback<Void> callback) { |
||||
|
forwardToDeviceActor(TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setPostTelemetry(msg).build(), callback); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(SessionInfoProto sessionInfo, PostAttributeMsg msg, TransportServiceCallback<Void> callback) { |
||||
|
forwardToDeviceActor(TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setPostAttributes(msg).build(), callback); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(SessionInfoProto sessionInfo, GetAttributeRequestMsg msg, TransportServiceCallback<Void> callback) { |
||||
|
forwardToDeviceActor(TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setGetAttributes(msg).build(), callback); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(SessionInfoProto sessionInfo, SubscribeToAttributeUpdatesMsg msg, TransportServiceCallback<Void> callback) { |
||||
|
forwardToDeviceActor(TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setSubscribeToAttributes(msg).build(), callback); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(SessionInfoProto sessionInfo, SubscribeToRPCMsg msg, TransportServiceCallback<Void> callback) { |
||||
|
forwardToDeviceActor(TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setSubscribeToRPC(msg).build(), callback); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(SessionInfoProto sessionInfo, ToDeviceRpcResponseMsg msg, TransportServiceCallback<Void> callback) { |
||||
|
forwardToDeviceActor(TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setToDeviceRPCCallResponse(msg).build(), callback); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(SessionInfoProto sessionInfo, ToServerRpcRequestMsg msg, TransportServiceCallback<Void> callback) { |
||||
|
forwardToDeviceActor(TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setToServerRPCCallRequest(msg).build(), callback); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(String nodeId, DeviceActorToTransportMsg msg) { |
||||
|
process(nodeId, msg, null, null); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(String nodeId, DeviceActorToTransportMsg msg, Runnable onSuccess, Consumer<Throwable> onFailure) { |
||||
|
processToTransportMsg(msg); |
||||
|
if (onSuccess != null) { |
||||
|
onSuccess.run(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void forwardToDeviceActor(TransportToDeviceActorMsg toDeviceActorMsg, TransportServiceCallback<Void> callback) { |
||||
|
TransportToDeviceActorMsgWrapper wrapper = new TransportToDeviceActorMsgWrapper(toDeviceActorMsg); |
||||
|
Optional<ServerAddress> address = routingService.resolveById(wrapper.getDeviceId()); |
||||
|
if (address.isPresent()) { |
||||
|
rpcService.tell(encodingService.convertToProtoDataMessage(address.get(), wrapper)); |
||||
|
} else { |
||||
|
actorContext.getAppActor().tell(wrapper, ActorRef.noSender()); |
||||
|
} |
||||
|
if (callback != null) { |
||||
|
callback.onSuccess(null); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private <T> Consumer<Throwable> getThrowableConsumer(TransportServiceCallback<T> callback) { |
||||
|
return e -> { |
||||
|
if (callback != null) { |
||||
|
callback.onError(e); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,200 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.transport; |
||||
|
|
||||
|
import akka.actor.ActorRef; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.kafka.clients.consumer.ConsumerRecords; |
||||
|
import org.apache.kafka.clients.producer.Callback; |
||||
|
import org.apache.kafka.clients.producer.RecordMetadata; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.thingsboard.server.actors.ActorSystemContext; |
||||
|
import org.thingsboard.server.actors.service.ActorService; |
||||
|
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
||||
|
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate; |
||||
|
import org.thingsboard.server.kafka.TBKafkaProducerTemplate; |
||||
|
import org.thingsboard.server.kafka.TbKafkaSettings; |
||||
|
import org.thingsboard.server.kafka.TbNodeIdProvider; |
||||
|
import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
||||
|
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; |
||||
|
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
||||
|
import org.thingsboard.server.service.encoding.DataDecodingEncodingService; |
||||
|
import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
||||
|
|
||||
|
import javax.annotation.PostConstruct; |
||||
|
import javax.annotation.PreDestroy; |
||||
|
import java.time.Duration; |
||||
|
import java.util.Optional; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.Executors; |
||||
|
import java.util.function.Consumer; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 09.10.18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Service |
||||
|
@ConditionalOnProperty(prefix = "transport", value = "type", havingValue = "remote") |
||||
|
public class RemoteRuleEngineTransportService implements RuleEngineTransportService { |
||||
|
|
||||
|
@Value("${transport.remote.rule_engine.topic}") |
||||
|
private String ruleEngineTopic; |
||||
|
@Value("${transport.remote.notifications.topic}") |
||||
|
private String notificationsTopic; |
||||
|
@Value("${transport.remote.rule_engine.poll_interval}") |
||||
|
private int pollDuration; |
||||
|
@Value("${transport.remote.rule_engine.auto_commit_interval}") |
||||
|
private int autoCommitInterval; |
||||
|
|
||||
|
@Autowired |
||||
|
private TbKafkaSettings kafkaSettings; |
||||
|
|
||||
|
@Autowired |
||||
|
private TbNodeIdProvider nodeIdProvider; |
||||
|
|
||||
|
@Autowired |
||||
|
private ActorSystemContext actorContext; |
||||
|
|
||||
|
//TODO: completely replace this routing with the Kafka routing by partition ids.
|
||||
|
@Autowired |
||||
|
private ClusterRoutingService routingService; |
||||
|
@Autowired |
||||
|
private ClusterRpcService rpcService; |
||||
|
@Autowired |
||||
|
private DataDecodingEncodingService encodingService; |
||||
|
|
||||
|
private TBKafkaConsumerTemplate<ToRuleEngineMsg> ruleEngineConsumer; |
||||
|
private TBKafkaProducerTemplate<ToTransportMsg> notificationsProducer; |
||||
|
|
||||
|
private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(); |
||||
|
|
||||
|
private volatile boolean stopped = false; |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<ToTransportMsg> notificationsProducerBuilder = TBKafkaProducerTemplate.builder(); |
||||
|
notificationsProducerBuilder.settings(kafkaSettings); |
||||
|
notificationsProducerBuilder.defaultTopic(notificationsTopic); |
||||
|
notificationsProducerBuilder.encoder(new ToTransportMsgEncoder()); |
||||
|
|
||||
|
notificationsProducer = notificationsProducerBuilder.build(); |
||||
|
notificationsProducer.init(); |
||||
|
|
||||
|
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<ToRuleEngineMsg> ruleEngineConsumerBuilder = TBKafkaConsumerTemplate.builder(); |
||||
|
ruleEngineConsumerBuilder.settings(kafkaSettings); |
||||
|
ruleEngineConsumerBuilder.topic(ruleEngineTopic); |
||||
|
ruleEngineConsumerBuilder.clientId("transport-" + nodeIdProvider.getNodeId()); |
||||
|
ruleEngineConsumerBuilder.groupId("tb-node"); |
||||
|
ruleEngineConsumerBuilder.autoCommit(true); |
||||
|
ruleEngineConsumerBuilder.autoCommitIntervalMs(autoCommitInterval); |
||||
|
ruleEngineConsumerBuilder.decoder(new ToRuleEngineMsgDecoder()); |
||||
|
|
||||
|
ruleEngineConsumer = ruleEngineConsumerBuilder.build(); |
||||
|
ruleEngineConsumer.subscribe(); |
||||
|
|
||||
|
mainConsumerExecutor.execute(() -> { |
||||
|
while (!stopped) { |
||||
|
try { |
||||
|
ConsumerRecords<String, byte[]> records = ruleEngineConsumer.poll(Duration.ofMillis(pollDuration)); |
||||
|
records.forEach(record -> { |
||||
|
try { |
||||
|
ToRuleEngineMsg toRuleEngineMsg = ruleEngineConsumer.decode(record); |
||||
|
if (toRuleEngineMsg.hasToDeviceActorMsg()) { |
||||
|
forwardToDeviceActor(toRuleEngineMsg.getToDeviceActorMsg()); |
||||
|
} |
||||
|
} catch (Throwable e) { |
||||
|
log.warn("Failed to process the notification.", e); |
||||
|
} |
||||
|
}); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("Failed to obtain messages from queue.", e); |
||||
|
try { |
||||
|
Thread.sleep(pollDuration); |
||||
|
} catch (InterruptedException e2) { |
||||
|
log.trace("Failed to wait until the server has capacity to handle new requests", e2); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(String nodeId, DeviceActorToTransportMsg msg) { |
||||
|
process(nodeId, msg, null, null); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void process(String nodeId, DeviceActorToTransportMsg msg, Runnable onSuccess, Consumer<Throwable> onFailure) { |
||||
|
notificationsProducer.send(notificationsTopic + "." + nodeId, |
||||
|
new UUID(msg.getSessionIdMSB(), msg.getSessionIdLSB()).toString(), |
||||
|
ToTransportMsg.newBuilder().setToDeviceSessionMsg(msg).build() |
||||
|
, new QueueCallbackAdaptor(onSuccess, onFailure)); |
||||
|
} |
||||
|
|
||||
|
private void forwardToDeviceActor(TransportToDeviceActorMsg toDeviceActorMsg) { |
||||
|
TransportToDeviceActorMsgWrapper wrapper = new TransportToDeviceActorMsgWrapper(toDeviceActorMsg); |
||||
|
Optional<ServerAddress> address = routingService.resolveById(wrapper.getDeviceId()); |
||||
|
if (address.isPresent()) { |
||||
|
rpcService.tell(encodingService.convertToProtoDataMessage(address.get(), wrapper)); |
||||
|
} else { |
||||
|
actorContext.getAppActor().tell(wrapper, ActorRef.noSender()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreDestroy |
||||
|
public void destroy() { |
||||
|
stopped = true; |
||||
|
if (ruleEngineConsumer != null) { |
||||
|
ruleEngineConsumer.unsubscribe(); |
||||
|
} |
||||
|
if (mainConsumerExecutor != null) { |
||||
|
mainConsumerExecutor.shutdownNow(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static class QueueCallbackAdaptor implements Callback { |
||||
|
private final Runnable onSuccess; |
||||
|
private final Consumer<Throwable> onFailure; |
||||
|
|
||||
|
QueueCallbackAdaptor(Runnable onSuccess, Consumer<Throwable> onFailure) { |
||||
|
this.onSuccess = onSuccess; |
||||
|
this.onFailure = onFailure; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onCompletion(RecordMetadata metadata, Exception exception) { |
||||
|
if (exception == null) { |
||||
|
if (onSuccess != null) { |
||||
|
onSuccess.run(); |
||||
|
} |
||||
|
} else { |
||||
|
if (onFailure != null) { |
||||
|
onFailure.accept(exception); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,109 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.transport; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
||||
|
import org.thingsboard.server.kafka.*; |
||||
|
|
||||
|
import javax.annotation.PostConstruct; |
||||
|
import javax.annotation.PreDestroy; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.SynchronousQueue; |
||||
|
import java.util.concurrent.ThreadPoolExecutor; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 05.10.18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
@ConditionalOnProperty(prefix = "transport", value = "type", havingValue = "remote") |
||||
|
public class RemoteTransportApiService { |
||||
|
|
||||
|
@Value("${transport.remote.transport_api.requests_topic}") |
||||
|
private String transportApiRequestsTopic; |
||||
|
@Value("${transport.remote.transport_api.responses_topic}") |
||||
|
private String transportApiResponsesTopic; |
||||
|
@Value("${transport.remote.transport_api.max_pending_requests}") |
||||
|
private int maxPendingRequests; |
||||
|
@Value("${transport.remote.transport_api.request_timeout}") |
||||
|
private long requestTimeout; |
||||
|
@Value("${transport.remote.transport_api.request_poll_interval}") |
||||
|
private int responsePollDuration; |
||||
|
@Value("${transport.remote.transport_api.request_auto_commit_interval}") |
||||
|
private int autoCommitInterval; |
||||
|
|
||||
|
@Autowired |
||||
|
private TbKafkaSettings kafkaSettings; |
||||
|
|
||||
|
@Autowired |
||||
|
private TbNodeIdProvider nodeIdProvider; |
||||
|
|
||||
|
@Autowired |
||||
|
private TransportApiService transportApiService; |
||||
|
|
||||
|
private ExecutorService transportCallbackExecutor; |
||||
|
|
||||
|
private TbKafkaResponseTemplate<TransportApiRequestMsg, TransportApiResponseMsg> transportApiTemplate; |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
this.transportCallbackExecutor = new ThreadPoolExecutor(0, 100, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); |
||||
|
|
||||
|
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TransportApiResponseMsg> responseBuilder = TBKafkaProducerTemplate.builder(); |
||||
|
responseBuilder.settings(kafkaSettings); |
||||
|
responseBuilder.defaultTopic(transportApiResponsesTopic); |
||||
|
responseBuilder.encoder(new TransportApiResponseEncoder()); |
||||
|
|
||||
|
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<TransportApiRequestMsg> requestBuilder = TBKafkaConsumerTemplate.builder(); |
||||
|
requestBuilder.settings(kafkaSettings); |
||||
|
requestBuilder.topic(transportApiRequestsTopic); |
||||
|
requestBuilder.clientId(nodeIdProvider.getNodeId()); |
||||
|
requestBuilder.groupId("tb-node"); |
||||
|
requestBuilder.autoCommit(true); |
||||
|
requestBuilder.autoCommitIntervalMs(autoCommitInterval); |
||||
|
requestBuilder.decoder(new TransportApiRequestDecoder()); |
||||
|
|
||||
|
TbKafkaResponseTemplate.TbKafkaResponseTemplateBuilder |
||||
|
<TransportApiRequestMsg, TransportApiResponseMsg> builder = TbKafkaResponseTemplate.builder(); |
||||
|
builder.requestTemplate(requestBuilder.build()); |
||||
|
builder.responseTemplate(responseBuilder.build()); |
||||
|
builder.maxPendingRequests(maxPendingRequests); |
||||
|
builder.requestTimeout(requestTimeout); |
||||
|
builder.pollInterval(responsePollDuration); |
||||
|
builder.executor(transportCallbackExecutor); |
||||
|
builder.handler(transportApiService); |
||||
|
transportApiTemplate = builder.build(); |
||||
|
transportApiTemplate.init(); |
||||
|
} |
||||
|
|
||||
|
@PreDestroy |
||||
|
public void destroy() { |
||||
|
if (transportApiTemplate != null) { |
||||
|
transportApiTemplate.stop(); |
||||
|
} |
||||
|
if (transportCallbackExecutor != null) { |
||||
|
transportCallbackExecutor.shutdownNow(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.transport; |
||||
|
|
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
||||
|
import org.thingsboard.server.kafka.TbKafkaDecoder; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 05.10.18. |
||||
|
*/ |
||||
|
public class TransportApiRequestDecoder implements TbKafkaDecoder<TransportApiRequestMsg> { |
||||
|
@Override |
||||
|
public TransportApiRequestMsg decode(byte[] data) throws IOException { |
||||
|
return TransportApiRequestMsg.parseFrom(data); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.transport.msg; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.thingsboard.server.common.data.id.DeviceId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.msg.MsgType; |
||||
|
import org.thingsboard.server.common.msg.TbActorMsg; |
||||
|
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; |
||||
|
import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 09.10.18. |
||||
|
*/ |
||||
|
@Data |
||||
|
public class TransportToDeviceActorMsgWrapper implements TbActorMsg, DeviceAwareMsg, TenantAwareMsg, Serializable { |
||||
|
|
||||
|
private final TenantId tenantId; |
||||
|
private final DeviceId deviceId; |
||||
|
private final TransportToDeviceActorMsg msg; |
||||
|
|
||||
|
public TransportToDeviceActorMsgWrapper(TransportToDeviceActorMsg msg) { |
||||
|
this.msg = msg; |
||||
|
this.tenantId = new TenantId(new UUID(msg.getSessionInfo().getTenantIdMSB(), msg.getSessionInfo().getTenantIdLSB())); |
||||
|
this.deviceId = new DeviceId(new UUID(msg.getSessionInfo().getDeviceIdMSB(), msg.getSessionInfo().getDeviceIdLSB())); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public MsgType getMsgType() { |
||||
|
return MsgType.TRANSPORT_TO_DEVICE_ACTOR_MSG; |
||||
|
} |
||||
|
} |
||||
@ -1,24 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.aware; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
|
|
||||
public interface SessionAwareMsg { |
|
||||
|
|
||||
SessionId getSessionId(); |
|
||||
|
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
public interface ActorSystemToDeviceSessionActorMsg extends SessionAwareMsg, Serializable, TbActorMsg { |
|
||||
|
|
||||
ToDeviceMsg getMsg(); |
|
||||
} |
|
||||
@ -1,47 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.ToString; |
|
||||
import org.thingsboard.server.common.msg.kv.AttributesKVMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
|
|
||||
@ToString |
|
||||
public class AttributesUpdateNotification implements ToDeviceMsg { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
private AttributesKVMsg data; |
|
||||
|
|
||||
public AttributesUpdateNotification(AttributesKVMsg data) { |
|
||||
this.data = data; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public boolean isSuccess() { |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
public SessionMsgType getSessionMsgType() { |
|
||||
return SessionMsgType.ATTRIBUTES_UPDATE_NOTIFICATION; |
|
||||
} |
|
||||
|
|
||||
public AttributesKVMsg getData() { |
|
||||
return data; |
|
||||
} |
|
||||
} |
|
||||
@ -1,28 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import java.util.Set; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|
||||
|
|
||||
public interface AttributesUpdateRequest extends FromDeviceRequestMsg { |
|
||||
|
|
||||
Set<AttributeKvEntry> getAttributes(); |
|
||||
|
|
||||
} |
|
||||
@ -1,52 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.MsgType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
|
|
||||
public class BasicActorSystemToDeviceSessionActorMsg implements ActorSystemToDeviceSessionActorMsg { |
|
||||
|
|
||||
private final ToDeviceMsg msg; |
|
||||
private final SessionId sessionId; |
|
||||
|
|
||||
public BasicActorSystemToDeviceSessionActorMsg(ToDeviceMsg msg, SessionId sessionId) { |
|
||||
super(); |
|
||||
this.msg = msg; |
|
||||
this.sessionId = sessionId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionId getSessionId() { |
|
||||
return sessionId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public ToDeviceMsg getMsg() { |
|
||||
return msg; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "BasicActorSystemToDeviceSessionActorMsg [msg=" + msg + ", sessionId=" + sessionId + "]"; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public MsgType getMsgType() { |
|
||||
return MsgType.ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG; |
|
||||
} |
|
||||
} |
|
||||
@ -1,63 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import java.util.Collection; |
|
||||
import java.util.LinkedHashSet; |
|
||||
import java.util.Set; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
public class BasicAttributesUpdateRequest extends BasicRequest implements AttributesUpdateRequest { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
private final Set<AttributeKvEntry> data; |
|
||||
|
|
||||
public BasicAttributesUpdateRequest() { |
|
||||
this(DEFAULT_REQUEST_ID); |
|
||||
} |
|
||||
|
|
||||
public BasicAttributesUpdateRequest(Integer requestId) { |
|
||||
super(requestId); |
|
||||
this.data = new LinkedHashSet<>(); |
|
||||
} |
|
||||
|
|
||||
public void add(AttributeKvEntry entry) { |
|
||||
this.data.add(entry); |
|
||||
} |
|
||||
|
|
||||
public void add(Collection<AttributeKvEntry> entries) { |
|
||||
this.data.addAll(entries); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionMsgType getMsgType() { |
|
||||
return SessionMsgType.POST_ATTRIBUTES_REQUEST; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Set<AttributeKvEntry> getAttributes() { |
|
||||
return data; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "BasicAttributesUpdateRequest [data=" + data + "]"; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,45 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
public class BasicCommandAckResponse extends BasicResponseMsg<Integer> implements StatusCodeResponse { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
public static BasicCommandAckResponse onSuccess(SessionMsgType requestMsgType, Integer requestId) { |
|
||||
return BasicCommandAckResponse.onSuccess(requestMsgType, requestId, 200); |
|
||||
} |
|
||||
|
|
||||
public static BasicCommandAckResponse onSuccess(SessionMsgType requestMsgType, Integer requestId, Integer code) { |
|
||||
return new BasicCommandAckResponse(requestMsgType, requestId, true, null, code); |
|
||||
} |
|
||||
|
|
||||
public static BasicCommandAckResponse onError(SessionMsgType requestMsgType, Integer requestId, Exception error) { |
|
||||
return new BasicCommandAckResponse(requestMsgType, requestId, false, error, null); |
|
||||
} |
|
||||
|
|
||||
private BasicCommandAckResponse(SessionMsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) { |
|
||||
super(requestMsgType, requestId, SessionMsgType.TO_DEVICE_RPC_RESPONSE_ACK, success, error, code); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "BasicStatusCodeResponse []"; |
|
||||
} |
|
||||
} |
|
||||
@ -1,59 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.ToString; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
import java.util.Collections; |
|
||||
import java.util.Optional; |
|
||||
import java.util.Set; |
|
||||
|
|
||||
@ToString |
|
||||
public class BasicGetAttributesRequest extends BasicRequest implements GetAttributesRequest { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
private final Set<String> clientKeys; |
|
||||
private final Set<String> sharedKeys; |
|
||||
|
|
||||
public BasicGetAttributesRequest(Integer requestId) { |
|
||||
this(requestId, Collections.emptySet(), Collections.emptySet()); |
|
||||
} |
|
||||
|
|
||||
public BasicGetAttributesRequest(Integer requestId, Set<String> clientKeys, Set<String> sharedKeys) { |
|
||||
super(requestId); |
|
||||
this.clientKeys = clientKeys; |
|
||||
this.sharedKeys = sharedKeys; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionMsgType getMsgType() { |
|
||||
return SessionMsgType.GET_ATTRIBUTES_REQUEST; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Optional<Set<String>> getClientAttributeNames() { |
|
||||
return Optional.ofNullable(clientKeys); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Optional<Set<String>> getSharedAttributeNames() { |
|
||||
return Optional.ofNullable(sharedKeys); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,40 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.ToString; |
|
||||
import org.thingsboard.server.common.msg.kv.AttributesKVMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
@ToString |
|
||||
public class BasicGetAttributesResponse extends BasicResponseMsg<AttributesKVMsg> implements GetAttributesResponse { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
public static BasicGetAttributesResponse onSuccess(SessionMsgType requestMsgType, int requestId, AttributesKVMsg code) { |
|
||||
return new BasicGetAttributesResponse(requestMsgType, requestId, true, null, code); |
|
||||
} |
|
||||
|
|
||||
public static BasicGetAttributesResponse onError(SessionMsgType requestMsgType, int requestId, Exception error) { |
|
||||
return new BasicGetAttributesResponse(requestMsgType, requestId, false, error, null); |
|
||||
} |
|
||||
|
|
||||
private BasicGetAttributesResponse(SessionMsgType requestMsgType, int requestId, boolean success, Exception error, AttributesKVMsg code) { |
|
||||
super(requestMsgType, requestId, SessionMsgType.GET_ATTRIBUTES_RESPONSE, success, error, code); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,79 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.util.Optional; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
|
|
||||
public class BasicResponseMsg<T extends Serializable> implements ResponseMsg<T> { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
private final SessionMsgType requestMsgType; |
|
||||
private final Integer requestId; |
|
||||
private final SessionMsgType sessionMsgType; |
|
||||
private final boolean success; |
|
||||
private final T data; |
|
||||
private final Exception error; |
|
||||
|
|
||||
protected BasicResponseMsg(SessionMsgType requestMsgType, Integer requestId, SessionMsgType sessionMsgType, boolean success, Exception error, T data) { |
|
||||
super(); |
|
||||
this.requestMsgType = requestMsgType; |
|
||||
this.requestId = requestId; |
|
||||
this.sessionMsgType = sessionMsgType; |
|
||||
this.success = success; |
|
||||
this.error = error; |
|
||||
this.data = data; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionMsgType getRequestMsgType() { |
|
||||
return requestMsgType; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Integer getRequestId() { |
|
||||
return requestId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public boolean isSuccess() { |
|
||||
return success; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Optional<Exception> getError() { |
|
||||
return Optional.ofNullable(error); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Optional<T> getData() { |
|
||||
return Optional.ofNullable(data); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "BasicResponseMsg [success=" + success + ", data=" + data + ", error=" + error + "]"; |
|
||||
} |
|
||||
|
|
||||
public SessionMsgType getSessionMsgType() { |
|
||||
return sessionMsgType; |
|
||||
} |
|
||||
} |
|
||||
@ -1,42 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.ToString; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
@ToString |
|
||||
public class BasicStatusCodeResponse extends BasicResponseMsg<Integer> implements StatusCodeResponse { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
public static BasicStatusCodeResponse onSuccess(SessionMsgType requestMsgType, Integer requestId) { |
|
||||
return BasicStatusCodeResponse.onSuccess(requestMsgType, requestId, 0); |
|
||||
} |
|
||||
|
|
||||
public static BasicStatusCodeResponse onSuccess(SessionMsgType requestMsgType, Integer requestId, Integer code) { |
|
||||
return new BasicStatusCodeResponse(requestMsgType, requestId, true, null, code); |
|
||||
} |
|
||||
|
|
||||
public static BasicStatusCodeResponse onError(SessionMsgType requestMsgType, Integer requestId, Exception error) { |
|
||||
return new BasicStatusCodeResponse(requestMsgType, requestId, false, error, null); |
|
||||
} |
|
||||
|
|
||||
private BasicStatusCodeResponse(SessionMsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) { |
|
||||
super(requestMsgType, requestId, SessionMsgType.STATUS_CODE_RESPONSE, success, error, code); |
|
||||
} |
|
||||
} |
|
||||
@ -1,66 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.HashMap; |
|
||||
import java.util.List; |
|
||||
import java.util.Map; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.kv.KvEntry; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
public class BasicTelemetryUploadRequest extends BasicRequest implements TelemetryUploadRequest { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
private final Map<Long, List<KvEntry>> data; |
|
||||
|
|
||||
public BasicTelemetryUploadRequest() { |
|
||||
this(DEFAULT_REQUEST_ID); |
|
||||
} |
|
||||
|
|
||||
public BasicTelemetryUploadRequest(Integer requestId) { |
|
||||
super(requestId); |
|
||||
this.data = new HashMap<>(); |
|
||||
} |
|
||||
|
|
||||
public void add(long ts, KvEntry entry) { |
|
||||
List<KvEntry> tsEntries = data.get(ts); |
|
||||
if (tsEntries == null) { |
|
||||
tsEntries = new ArrayList<>(); |
|
||||
data.put(ts, tsEntries); |
|
||||
} |
|
||||
tsEntries.add(entry); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionMsgType getMsgType() { |
|
||||
return SessionMsgType.POST_TELEMETRY_REQUEST; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Map<Long, List<KvEntry>> getData() { |
|
||||
return data; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "BasicTelemetryUploadRequest [data=" + data + "]"; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,29 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import java.util.Optional; |
|
||||
import java.util.Set; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|
||||
|
|
||||
public interface GetAttributesRequest extends FromDeviceRequestMsg { |
|
||||
|
|
||||
Optional<Set<String>> getClientAttributeNames(); |
|
||||
Optional<Set<String>> getSharedAttributeNames(); |
|
||||
|
|
||||
} |
|
||||
@ -1,22 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.kv.AttributesKVMsg; |
|
||||
|
|
||||
public interface GetAttributesResponse extends ResponseMsg<AttributesKVMsg> { |
|
||||
|
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.util.Optional; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
|
|
||||
public interface ResponseMsg<T extends Serializable> extends ToDeviceMsg { |
|
||||
|
|
||||
SessionMsgType getRequestMsgType(); |
|
||||
|
|
||||
Integer getRequestId(); |
|
||||
|
|
||||
Optional<Exception> getError(); |
|
||||
|
|
||||
Optional<T> getData(); |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
public class RpcUnsubscribeMsg implements FromDeviceMsg { |
|
||||
@Override |
|
||||
public SessionMsgType getMsgType() { |
|
||||
return SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST; |
|
||||
} |
|
||||
} |
|
||||
@ -1,43 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
|
|
||||
public enum RuleEngineError { |
|
||||
|
|
||||
QUEUE_PUT_TIMEOUT(true), SERVER_ERROR(true), TIMEOUT; |
|
||||
|
|
||||
private final boolean critical; |
|
||||
|
|
||||
RuleEngineError() { |
|
||||
this(false); |
|
||||
} |
|
||||
|
|
||||
RuleEngineError(boolean critical) { |
|
||||
this.critical = critical; |
|
||||
} |
|
||||
|
|
||||
public boolean isCritical() { |
|
||||
return critical; |
|
||||
} |
|
||||
|
|
||||
public int getPriority() { |
|
||||
return ordinal(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,53 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.Data; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
@Data |
|
||||
public class RuleEngineErrorMsg implements ToDeviceMsg { |
|
||||
|
|
||||
private final SessionMsgType inSessionMsgType; |
|
||||
private final RuleEngineError error; |
|
||||
|
|
||||
@Override |
|
||||
public boolean isSuccess() { |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
public SessionMsgType getSessionMsgType() { |
|
||||
return SessionMsgType.RULE_ENGINE_ERROR; |
|
||||
} |
|
||||
|
|
||||
public String getErrorMsg() { |
|
||||
switch (error) { |
|
||||
case QUEUE_PUT_TIMEOUT: |
|
||||
return "Timeout during persistence of the message to the queue!"; |
|
||||
case SERVER_ERROR: |
|
||||
return "Error during processing of message by the server!"; |
|
||||
case TIMEOUT: |
|
||||
return "Timeout during processing of message by the server!"; |
|
||||
default: |
|
||||
throw new RuntimeException("Error " + error + " is not supported!"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,38 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.ToString; |
|
||||
import org.thingsboard.server.common.msg.kv.AttributesKVMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
|
|
||||
@ToString |
|
||||
public class SessionCloseNotification implements ToDeviceMsg { |
|
||||
|
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
@Override |
|
||||
public boolean isSuccess() { |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
public SessionMsgType getSessionMsgType() { |
|
||||
return SessionMsgType.SESSION_CLOSE; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,35 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.Data; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
@Data |
|
||||
public class SessionOpenMsg implements FromDeviceMsg { |
|
||||
|
|
||||
@Override |
|
||||
public SessionMsgType getMsgType() { |
|
||||
return SessionMsgType.SESSION_OPEN; |
|
||||
} |
|
||||
} |
|
||||
@ -1,20 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
public interface StatusCodeResponse extends ResponseMsg<Integer>{ |
|
||||
|
|
||||
} |
|
||||
@ -1,29 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import java.util.List; |
|
||||
import java.util.Map; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.kv.KvEntry; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|
||||
|
|
||||
public interface TelemetryUploadRequest extends FromDeviceRequestMsg { |
|
||||
|
|
||||
Map<Long, List<KvEntry>> getData(); |
|
||||
|
|
||||
} |
|
||||
@ -1,41 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.Data; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
@Data |
|
||||
public class ToDeviceRpcRequestMsg implements ToDeviceMsg { |
|
||||
|
|
||||
private final int requestId; |
|
||||
private final String method; |
|
||||
private final String params; |
|
||||
|
|
||||
public SessionMsgType getSessionMsgType() { |
|
||||
return SessionMsgType.TO_DEVICE_RPC_REQUEST; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public boolean isSuccess() { |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.Data; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
@Data |
|
||||
public class ToDeviceRpcResponseMsg implements FromDeviceMsg { |
|
||||
|
|
||||
private final int requestId; |
|
||||
private final String data; |
|
||||
|
|
||||
@Override |
|
||||
public SessionMsgType getMsgType() { |
|
||||
return SessionMsgType.TO_DEVICE_RPC_RESPONSE; |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.core; |
|
||||
|
|
||||
import lombok.Data; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
@Data |
|
||||
public class ToServerRpcRequestMsg implements FromDeviceRequestMsg { |
|
||||
|
|
||||
private final Integer requestId; |
|
||||
private final String method; |
|
||||
private final String params; |
|
||||
|
|
||||
@Override |
|
||||
public SessionMsgType getMsgType() { |
|
||||
return SessionMsgType.TO_SERVER_RPC_REQUEST; |
|
||||
} |
|
||||
} |
|
||||
@ -1,107 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.device; |
|
||||
|
|
||||
import lombok.ToString; |
|
||||
import org.thingsboard.server.common.data.id.CustomerId; |
|
||||
import org.thingsboard.server.common.data.id.DeviceId; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.data.id.TenantId; |
|
||||
import org.thingsboard.server.common.msg.MsgType; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionType; |
|
||||
import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; |
|
||||
|
|
||||
import java.util.Optional; |
|
||||
|
|
||||
@ToString |
|
||||
public class BasicDeviceToDeviceActorMsg implements DeviceToDeviceActorMsg { |
|
||||
|
|
||||
private static final long serialVersionUID = -1866795134993115408L; |
|
||||
|
|
||||
private final TenantId tenantId; |
|
||||
private final CustomerId customerId; |
|
||||
private final DeviceId deviceId; |
|
||||
private final SessionId sessionId; |
|
||||
private final SessionType sessionType; |
|
||||
private final ServerAddress serverAddress; |
|
||||
private final FromDeviceMsg msg; |
|
||||
|
|
||||
public BasicDeviceToDeviceActorMsg(DeviceToDeviceActorMsg other, FromDeviceMsg msg) { |
|
||||
this(null, other.getTenantId(), other.getCustomerId(), other.getDeviceId(), other.getSessionId(), other.getSessionType(), msg); |
|
||||
} |
|
||||
|
|
||||
public BasicDeviceToDeviceActorMsg(TransportToDeviceSessionActorMsg msg, SessionType sessionType) { |
|
||||
this(null, msg.getTenantId(), msg.getCustomerId(), msg.getDeviceId(), msg.getSessionId(), sessionType, msg.getSessionMsg().getMsg()); |
|
||||
} |
|
||||
|
|
||||
private BasicDeviceToDeviceActorMsg(ServerAddress serverAddress, TenantId tenantId, CustomerId customerId, DeviceId deviceId, SessionId sessionId, SessionType sessionType, |
|
||||
FromDeviceMsg msg) { |
|
||||
super(); |
|
||||
this.serverAddress = serverAddress; |
|
||||
this.tenantId = tenantId; |
|
||||
this.customerId = customerId; |
|
||||
this.deviceId = deviceId; |
|
||||
this.sessionId = sessionId; |
|
||||
this.sessionType = sessionType; |
|
||||
this.msg = msg; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public DeviceId getDeviceId() { |
|
||||
return deviceId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public CustomerId getCustomerId() { |
|
||||
return customerId; |
|
||||
} |
|
||||
|
|
||||
public TenantId getTenantId() { |
|
||||
return tenantId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionId getSessionId() { |
|
||||
return sessionId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionType getSessionType() { |
|
||||
return sessionType; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public Optional<ServerAddress> getServerAddress() { |
|
||||
return Optional.ofNullable(serverAddress); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public FromDeviceMsg getPayload() { |
|
||||
return msg; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public DeviceToDeviceActorMsg toOtherAddress(ServerAddress otherAddress) { |
|
||||
return new BasicDeviceToDeviceActorMsg(otherAddress, tenantId, customerId, deviceId, sessionId, sessionType, msg); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public MsgType getMsgType() { |
|
||||
return MsgType.DEVICE_SESSION_TO_DEVICE_ACTOR_MSG; |
|
||||
} |
|
||||
} |
|
||||
@ -1,41 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.device; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.util.Optional; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.CustomerAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
|
||||
import org.thingsboard.server.common.msg.session.SessionType; |
|
||||
|
|
||||
public interface DeviceToDeviceActorMsg extends TbActorMsg, DeviceAwareMsg, CustomerAwareMsg, TenantAwareMsg, Serializable { |
|
||||
|
|
||||
SessionId getSessionId(); |
|
||||
|
|
||||
SessionType getSessionType(); |
|
||||
|
|
||||
Optional<ServerAddress> getServerAddress(); |
|
||||
|
|
||||
FromDeviceMsg getPayload(); |
|
||||
|
|
||||
DeviceToDeviceActorMsg toOtherAddress(ServerAddress otherAddress); |
|
||||
} |
|
||||
@ -1,22 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
public interface AdaptorToSessionActorMsg extends SessionMsg { |
|
||||
|
|
||||
FromDeviceMsg getMsg(); |
|
||||
|
|
||||
} |
|
||||
@ -1,32 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
public class BasicAdaptorToSessionActorMsg extends BasicSessionMsg implements AdaptorToSessionActorMsg { |
|
||||
|
|
||||
private final FromDeviceMsg msg; |
|
||||
|
|
||||
public BasicAdaptorToSessionActorMsg(SessionContext ctx, FromDeviceMsg msg) { |
|
||||
super(ctx); |
|
||||
this.msg = msg; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public FromDeviceMsg getMsg() { |
|
||||
return msg; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,32 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
public class BasicSessionActorToAdaptorMsg extends BasicSessionMsg implements SessionActorToAdaptorMsg { |
|
||||
|
|
||||
private final ToDeviceMsg msg; |
|
||||
|
|
||||
public BasicSessionActorToAdaptorMsg(SessionContext ctx, ToDeviceMsg msg) { |
|
||||
super(ctx); |
|
||||
this.msg = msg; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public ToDeviceMsg getMsg() { |
|
||||
return msg; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,44 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
|
|
||||
public class BasicSessionMsg implements SessionMsg { |
|
||||
|
|
||||
private final SessionContext ctx; |
|
||||
|
|
||||
public BasicSessionMsg(SessionContext ctx) { |
|
||||
super(); |
|
||||
this.ctx = ctx; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionId getSessionId() { |
|
||||
return ctx.getSessionId(); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionContext getSessionContext() { |
|
||||
return ctx; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "BasicSessionMsg [ctx=" + ctx + "]"; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,74 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.Device; |
|
||||
import org.thingsboard.server.common.data.id.CustomerId; |
|
||||
import org.thingsboard.server.common.data.id.DeviceId; |
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.data.id.TenantId; |
|
||||
import org.thingsboard.server.common.msg.MsgType; |
|
||||
|
|
||||
public class BasicTransportToDeviceSessionActorMsg implements TransportToDeviceSessionActorMsg { |
|
||||
|
|
||||
private final TenantId tenantId; |
|
||||
private final CustomerId customerId; |
|
||||
private final DeviceId deviceId; |
|
||||
private final AdaptorToSessionActorMsg msg; |
|
||||
|
|
||||
public BasicTransportToDeviceSessionActorMsg(Device device, AdaptorToSessionActorMsg msg) { |
|
||||
super(); |
|
||||
this.tenantId = device.getTenantId(); |
|
||||
this.customerId = device.getCustomerId(); |
|
||||
this.deviceId = device.getId(); |
|
||||
this.msg = msg; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public DeviceId getDeviceId() { |
|
||||
return deviceId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public CustomerId getCustomerId() { |
|
||||
return customerId; |
|
||||
} |
|
||||
|
|
||||
public TenantId getTenantId() { |
|
||||
return tenantId; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionId getSessionId() { |
|
||||
return msg.getSessionId(); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public AdaptorToSessionActorMsg getSessionMsg() { |
|
||||
return msg; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "BasicTransportToDeviceSessionActorMsg [tenantId=" + tenantId + ", customerId=" + customerId + ", deviceId=" + deviceId + ", msg=" + msg |
|
||||
+ "]"; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public MsgType getMsgType() { |
|
||||
return MsgType.TRANSPORT_TO_DEVICE_SESSION_ACTOR_MSG; |
|
||||
} |
|
||||
} |
|
||||
@ -1,22 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
public interface SessionActorToAdaptorMsg extends SessionMsg { |
|
||||
|
|
||||
ToDeviceMsg getMsg(); |
|
||||
|
|
||||
} |
|
||||
@ -1,23 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
|
||||
|
|
||||
public interface SessionCtrlMsg extends SessionAwareMsg, TbActorMsg { |
|
||||
|
|
||||
} |
|
||||
@ -1,24 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
|
||||
|
|
||||
public interface SessionMsg extends SessionAwareMsg { |
|
||||
|
|
||||
SessionContext getSessionContext(); |
|
||||
|
|
||||
} |
|
||||
@ -1,22 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
public enum SessionType { |
|
||||
|
|
||||
SYNC, ASYNC; |
|
||||
|
|
||||
} |
|
||||
@ -1,26 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
|
|
||||
public interface ToDeviceMsg extends Serializable { |
|
||||
|
|
||||
boolean isSuccess(); |
|
||||
|
|
||||
SessionMsgType getSessionMsgType(); |
|
||||
|
|
||||
} |
|
||||
@ -1,28 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.CustomerAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
|
||||
import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
|
||||
|
|
||||
public interface TransportToDeviceSessionActorMsg extends DeviceAwareMsg, CustomerAwareMsg, TenantAwareMsg, SessionAwareMsg, TbActorMsg { |
|
||||
|
|
||||
AdaptorToSessionActorMsg getSessionMsg(); |
|
||||
|
|
||||
} |
|
||||
@ -1,68 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.session.ctrl; |
|
||||
|
|
||||
import org.thingsboard.server.common.data.id.SessionId; |
|
||||
import org.thingsboard.server.common.msg.MsgType; |
|
||||
import org.thingsboard.server.common.msg.session.SessionCtrlMsg; |
|
||||
|
|
||||
public class SessionCloseMsg implements SessionCtrlMsg { |
|
||||
|
|
||||
private final SessionId sessionId; |
|
||||
private final boolean revoked; |
|
||||
private final boolean timeout; |
|
||||
|
|
||||
public static SessionCloseMsg onDisconnect(SessionId sessionId) { |
|
||||
return new SessionCloseMsg(sessionId, false, false); |
|
||||
} |
|
||||
|
|
||||
public static SessionCloseMsg onError(SessionId sessionId) { |
|
||||
return new SessionCloseMsg(sessionId, false, false); |
|
||||
} |
|
||||
|
|
||||
public static SessionCloseMsg onTimeout(SessionId sessionId) { |
|
||||
return new SessionCloseMsg(sessionId, false, true); |
|
||||
} |
|
||||
|
|
||||
public static SessionCloseMsg onCredentialsRevoked(SessionId sessionId) { |
|
||||
return new SessionCloseMsg(sessionId, true, false); |
|
||||
} |
|
||||
|
|
||||
private SessionCloseMsg(SessionId sessionId, boolean unauthorized, boolean timeout) { |
|
||||
super(); |
|
||||
this.sessionId = sessionId; |
|
||||
this.revoked = unauthorized; |
|
||||
this.timeout = timeout; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SessionId getSessionId() { |
|
||||
return sessionId; |
|
||||
} |
|
||||
|
|
||||
public boolean isCredentialsRevoked() { |
|
||||
return revoked; |
|
||||
} |
|
||||
|
|
||||
public boolean isTimeout() { |
|
||||
return timeout; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public MsgType getMsgType() { |
|
||||
return MsgType.SESSION_CTRL_MSG; |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2018 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.common.msg.timeout; |
|
||||
|
|
||||
import org.thingsboard.server.common.msg.MsgType; |
|
||||
import org.thingsboard.server.common.msg.timeout.TimeoutMsg; |
|
||||
|
|
||||
import java.util.UUID; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
public final class DeviceActorQueueTimeoutMsg extends TimeoutMsg<UUID> { |
|
||||
|
|
||||
public DeviceActorQueueTimeoutMsg(UUID id, long timeout) { |
|
||||
super(id, timeout); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public MsgType getMsgType() { |
|
||||
return MsgType.DEVICE_ACTOR_QUEUE_TIMEOUT_MSG; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,50 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.kafka; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
import java.nio.ByteBuffer; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 25.09.18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public abstract class AbstractTbKafkaTemplate { |
||||
|
protected byte[] uuidToBytes(UUID uuid) { |
||||
|
ByteBuffer buf = ByteBuffer.allocate(16); |
||||
|
buf.putLong(uuid.getMostSignificantBits()); |
||||
|
buf.putLong(uuid.getLeastSignificantBits()); |
||||
|
return buf.array(); |
||||
|
} |
||||
|
|
||||
|
protected static UUID bytesToUuid(byte[] bytes) { |
||||
|
ByteBuffer bb = ByteBuffer.wrap(bytes); |
||||
|
long firstLong = bb.getLong(); |
||||
|
long secondLong = bb.getLong(); |
||||
|
return new UUID(firstLong, secondLong); |
||||
|
} |
||||
|
|
||||
|
protected byte[] stringToBytes(String string) { |
||||
|
return string.getBytes(StandardCharsets.UTF_8); |
||||
|
} |
||||
|
|
||||
|
protected String bytesToString(byte[] data) { |
||||
|
return new String(data, StandardCharsets.UTF_8); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.kafka; |
||||
|
|
||||
|
import com.google.common.util.concurrent.FutureCallback; |
||||
|
import com.google.common.util.concurrent.Futures; |
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
|
||||
|
import java.util.concurrent.Executor; |
||||
|
import java.util.concurrent.ScheduledExecutorService; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
import java.util.function.Consumer; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 05.10.18. |
||||
|
*/ |
||||
|
public class AsyncCallbackTemplate { |
||||
|
|
||||
|
public static <T> void withCallbackAndTimeout(ListenableFuture<T> future, |
||||
|
Consumer<T> onSuccess, |
||||
|
Consumer<Throwable> onFailure, |
||||
|
long timeoutInMs, |
||||
|
ScheduledExecutorService timeoutExecutor, |
||||
|
Executor callbackExecutor) { |
||||
|
future = Futures.withTimeout(future, timeoutInMs, TimeUnit.MILLISECONDS, timeoutExecutor); |
||||
|
withCallback(future, onSuccess, onFailure, callbackExecutor); |
||||
|
} |
||||
|
|
||||
|
public static <T> void withCallback(ListenableFuture<T> future, Consumer<T> onSuccess, |
||||
|
Consumer<Throwable> onFailure, Executor executor) { |
||||
|
FutureCallback<T> callback = new FutureCallback<T>() { |
||||
|
@Override |
||||
|
public void onSuccess(T result) { |
||||
|
try { |
||||
|
onSuccess.accept(result); |
||||
|
} catch (Throwable th) { |
||||
|
onFailure(th); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(Throwable t) { |
||||
|
onFailure.accept(t); |
||||
|
} |
||||
|
}; |
||||
|
if (executor != null) { |
||||
|
Futures.addCallback(future, callback, executor); |
||||
|
} else { |
||||
|
Futures.addCallback(future, callback); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,156 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.kafka; |
||||
|
|
||||
|
import lombok.Builder; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.kafka.clients.consumer.ConsumerRecords; |
||||
|
import org.apache.kafka.common.header.Header; |
||||
|
import org.apache.kafka.common.header.internals.RecordHeader; |
||||
|
|
||||
|
import java.time.Duration; |
||||
|
import java.util.Collections; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
import java.util.concurrent.ConcurrentMap; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.Executors; |
||||
|
import java.util.concurrent.ScheduledExecutorService; |
||||
|
import java.util.concurrent.TimeoutException; |
||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 25.09.18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class TbKafkaResponseTemplate<Request, Response> extends AbstractTbKafkaTemplate { |
||||
|
|
||||
|
private final TBKafkaConsumerTemplate<Request> requestTemplate; |
||||
|
private final TBKafkaProducerTemplate<Response> responseTemplate; |
||||
|
private final TbKafkaHandler<Request, Response> handler; |
||||
|
private final ConcurrentMap<UUID, String> pendingRequests; |
||||
|
private final ExecutorService loopExecutor; |
||||
|
private final ScheduledExecutorService timeoutExecutor; |
||||
|
private final ExecutorService callbackExecutor; |
||||
|
private final int maxPendingRequests; |
||||
|
private final long requestTimeout; |
||||
|
|
||||
|
private final long pollInterval; |
||||
|
private volatile boolean stopped = false; |
||||
|
private final AtomicInteger pendingRequestCount = new AtomicInteger(); |
||||
|
|
||||
|
@Builder |
||||
|
public TbKafkaResponseTemplate(TBKafkaConsumerTemplate<Request> requestTemplate, |
||||
|
TBKafkaProducerTemplate<Response> responseTemplate, |
||||
|
TbKafkaHandler<Request, Response> handler, |
||||
|
long pollInterval, |
||||
|
long requestTimeout, |
||||
|
int maxPendingRequests, |
||||
|
ExecutorService executor) { |
||||
|
this.requestTemplate = requestTemplate; |
||||
|
this.responseTemplate = responseTemplate; |
||||
|
this.handler = handler; |
||||
|
this.pendingRequests = new ConcurrentHashMap<>(); |
||||
|
this.maxPendingRequests = maxPendingRequests; |
||||
|
this.pollInterval = pollInterval; |
||||
|
this.requestTimeout = requestTimeout; |
||||
|
this.callbackExecutor = executor; |
||||
|
this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(); |
||||
|
this.loopExecutor = Executors.newSingleThreadExecutor(); |
||||
|
} |
||||
|
|
||||
|
public void init() { |
||||
|
this.responseTemplate.init(); |
||||
|
requestTemplate.subscribe(); |
||||
|
loopExecutor.submit(() -> { |
||||
|
while (!stopped) { |
||||
|
try { |
||||
|
while (pendingRequestCount.get() >= maxPendingRequests) { |
||||
|
try { |
||||
|
Thread.sleep(pollInterval); |
||||
|
} catch (InterruptedException e) { |
||||
|
log.trace("Failed to wait until the server has capacity to handle new requests", e); |
||||
|
} |
||||
|
} |
||||
|
ConsumerRecords<String, byte[]> requests = requestTemplate.poll(Duration.ofMillis(pollInterval)); |
||||
|
requests.forEach(request -> { |
||||
|
Header requestIdHeader = request.headers().lastHeader(TbKafkaSettings.REQUEST_ID_HEADER); |
||||
|
if (requestIdHeader == null) { |
||||
|
log.error("[{}] Missing requestId in header", request); |
||||
|
return; |
||||
|
} |
||||
|
UUID requestId = bytesToUuid(requestIdHeader.value()); |
||||
|
if (requestId == null) { |
||||
|
log.error("[{}] Missing requestId in header and body", request); |
||||
|
return; |
||||
|
} |
||||
|
Header responseTopicHeader = request.headers().lastHeader(TbKafkaSettings.RESPONSE_TOPIC_HEADER); |
||||
|
if (responseTopicHeader == null) { |
||||
|
log.error("[{}] Missing response topic in header", request); |
||||
|
return; |
||||
|
} |
||||
|
String responseTopic = bytesToString(responseTopicHeader.value()); |
||||
|
try { |
||||
|
pendingRequestCount.getAndIncrement(); |
||||
|
Request decodedRequest = requestTemplate.decode(request); |
||||
|
AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(decodedRequest), |
||||
|
response -> { |
||||
|
pendingRequestCount.decrementAndGet(); |
||||
|
reply(requestId, responseTopic, response); |
||||
|
}, |
||||
|
e -> { |
||||
|
pendingRequestCount.decrementAndGet(); |
||||
|
if (e.getCause() != null && e.getCause() instanceof TimeoutException) { |
||||
|
log.warn("[{}] Timedout to process the request: {}", requestId, request, e); |
||||
|
} else { |
||||
|
log.trace("[{}] Failed to process the request: {}", requestId, request, e); |
||||
|
} |
||||
|
}, |
||||
|
requestTimeout, |
||||
|
timeoutExecutor, |
||||
|
callbackExecutor); |
||||
|
} catch (Throwable e) { |
||||
|
pendingRequestCount.decrementAndGet(); |
||||
|
log.warn("[{}] Failed to process the request: {}", requestId, request, e); |
||||
|
} |
||||
|
}); |
||||
|
} catch (Throwable e) { |
||||
|
log.warn("Failed to obtain messages from queue.", e); |
||||
|
try { |
||||
|
Thread.sleep(pollInterval); |
||||
|
} catch (InterruptedException e2) { |
||||
|
log.trace("Failed to wait until the server has capacity to handle new requests", e2); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void stop() { |
||||
|
stopped = true; |
||||
|
if (timeoutExecutor != null) { |
||||
|
timeoutExecutor.shutdownNow(); |
||||
|
} |
||||
|
if (loopExecutor != null) { |
||||
|
loopExecutor.shutdownNow(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void reply(UUID requestId, String topic, Response response) { |
||||
|
responseTemplate.send(topic, requestId.toString(), response, Collections.singletonList(new RecordHeader(TbKafkaSettings.REQUEST_ID_HEADER, uuidToBytes(requestId))), null); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.kafka; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import javax.annotation.PostConstruct; |
||||
|
import java.net.InetAddress; |
||||
|
import java.net.UnknownHostException; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 12.10.18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
public class TbNodeIdProvider { |
||||
|
|
||||
|
@Getter |
||||
|
@Value("${cluster.node_id:#{null}}") |
||||
|
private String nodeId; |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
if (StringUtils.isEmpty(nodeId)) { |
||||
|
try { |
||||
|
nodeId = InetAddress.getLocalHost().getHostName(); |
||||
|
} catch (UnknownHostException e) { |
||||
|
nodeId = org.apache.commons.lang3.RandomStringUtils.randomAlphabetic(10); |
||||
|
} |
||||
|
} |
||||
|
log.info("Current NodeId: {}", nodeId); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,88 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2018 The Thingsboard Authors |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
|
||||
|
--> |
||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<parent> |
||||
|
<groupId>org.thingsboard.common</groupId> |
||||
|
<version>2.2.0-SNAPSHOT</version> |
||||
|
<artifactId>transport</artifactId> |
||||
|
</parent> |
||||
|
<groupId>org.thingsboard.common.transport</groupId> |
||||
|
<artifactId>coap</artifactId> |
||||
|
<packaging>jar</packaging> |
||||
|
|
||||
|
<name>Thingsboard CoAP Transport Common</name> |
||||
|
<url>https://thingsboard.io</url> |
||||
|
|
||||
|
<properties> |
||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
|
<main.dir>${basedir}/../../..</main.dir> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.thingsboard.common.transport</groupId> |
||||
|
<artifactId>transport-api</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.eclipse.californium</groupId> |
||||
|
<artifactId>californium-core</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework</groupId> |
||||
|
<artifactId>spring-context-support</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework</groupId> |
||||
|
<artifactId>spring-context</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.slf4j</groupId> |
||||
|
<artifactId>slf4j-api</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.slf4j</groupId> |
||||
|
<artifactId>log4j-over-slf4j</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>ch.qos.logback</groupId> |
||||
|
<artifactId>logback-core</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>ch.qos.logback</groupId> |
||||
|
<artifactId>logback-classic</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-test</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>junit</groupId> |
||||
|
<artifactId>junit</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.mockito</groupId> |
||||
|
<artifactId>mockito-all</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
|
||||
|
</project> |
||||
@ -0,0 +1,51 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.coap; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.transport.TransportContext; |
||||
|
import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 18.10.18. |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@ConditionalOnExpression("'${transport.type:null}'=='null' || ('${transport.type}'=='local' && '${transport.coap.enabled}'=='true')") |
||||
|
@Component |
||||
|
public class CoapTransportContext extends TransportContext { |
||||
|
|
||||
|
@Getter |
||||
|
@Value("${transport.coap.bind_address}") |
||||
|
private String host; |
||||
|
|
||||
|
@Getter |
||||
|
@Value("${transport.coap.bind_port}") |
||||
|
private Integer port; |
||||
|
|
||||
|
@Getter |
||||
|
@Value("${transport.coap.timeout}") |
||||
|
private Long timeout; |
||||
|
|
||||
|
@Getter |
||||
|
@Autowired |
||||
|
private CoapTransportAdaptor adaptor; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,445 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.coap; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.eclipse.californium.core.CoapResource; |
||||
|
import org.eclipse.californium.core.coap.CoAP.ResponseCode; |
||||
|
import org.eclipse.californium.core.coap.Request; |
||||
|
import org.eclipse.californium.core.coap.Response; |
||||
|
import org.eclipse.californium.core.network.Exchange; |
||||
|
import org.eclipse.californium.core.network.ExchangeObserver; |
||||
|
import org.eclipse.californium.core.server.resources.CoapExchange; |
||||
|
import org.eclipse.californium.core.server.resources.Resource; |
||||
|
import org.springframework.util.ReflectionUtils; |
||||
|
import org.thingsboard.server.common.data.security.DeviceTokenCredentials; |
||||
|
import org.thingsboard.server.common.msg.session.FeatureType; |
||||
|
import org.thingsboard.server.common.msg.session.SessionMsgType; |
||||
|
import org.thingsboard.server.common.transport.SessionMsgListener; |
||||
|
import org.thingsboard.server.common.transport.TransportContext; |
||||
|
import org.thingsboard.server.common.transport.TransportService; |
||||
|
import org.thingsboard.server.common.transport.TransportServiceCallback; |
||||
|
import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos; |
||||
|
|
||||
|
import java.lang.reflect.Field; |
||||
|
import java.util.List; |
||||
|
import java.util.Optional; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
import java.util.concurrent.ConcurrentMap; |
||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
import java.util.function.Consumer; |
||||
|
|
||||
|
@Slf4j |
||||
|
public class CoapTransportResource extends CoapResource { |
||||
|
// coap://localhost:port/api/v1/DEVICE_TOKEN/[attributes|telemetry|rpc[/requestId]]
|
||||
|
private static final int ACCESS_TOKEN_POSITION = 3; |
||||
|
private static final int FEATURE_TYPE_POSITION = 4; |
||||
|
private static final int REQUEST_ID_POSITION = 5; |
||||
|
|
||||
|
private final CoapTransportContext transportContext; |
||||
|
private final TransportService transportService; |
||||
|
private final Field observerField; |
||||
|
private final long timeout; |
||||
|
private final ConcurrentMap<String, TransportProtos.SessionInfoProto> tokenToSessionIdMap = new ConcurrentHashMap<>(); |
||||
|
|
||||
|
public CoapTransportResource(CoapTransportContext context, String name) { |
||||
|
super(name); |
||||
|
this.transportContext = context; |
||||
|
this.transportService = context.getTransportService(); |
||||
|
this.timeout = context.getTimeout(); |
||||
|
// This is important to turn off existing observable logic in
|
||||
|
// CoapResource. We will have our own observe monitoring due to 1:1
|
||||
|
// observe relationship.
|
||||
|
this.setObservable(false); |
||||
|
observerField = ReflectionUtils.findField(Exchange.class, "observer"); |
||||
|
observerField.setAccessible(true); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void handleGET(CoapExchange exchange) { |
||||
|
if (transportContext.getQuotaService().isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) { |
||||
|
log.warn("CoAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort()); |
||||
|
exchange.respond(ResponseCode.BAD_REQUEST); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest()); |
||||
|
if (!featureType.isPresent()) { |
||||
|
log.trace("Missing feature type parameter"); |
||||
|
exchange.respond(ResponseCode.BAD_REQUEST); |
||||
|
} else if (featureType.get() == FeatureType.TELEMETRY) { |
||||
|
log.trace("Can't fetch/subscribe to timeseries updates"); |
||||
|
exchange.respond(ResponseCode.BAD_REQUEST); |
||||
|
} else if (exchange.getRequestOptions().hasObserve()) { |
||||
|
processExchangeGetRequest(exchange, featureType.get()); |
||||
|
} else if (featureType.get() == FeatureType.ATTRIBUTES) { |
||||
|
processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST); |
||||
|
} else { |
||||
|
log.trace("Invalid feature type parameter"); |
||||
|
exchange.respond(ResponseCode.BAD_REQUEST); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void processExchangeGetRequest(CoapExchange exchange, FeatureType featureType) { |
||||
|
boolean unsubscribe = exchange.getRequestOptions().getObserve() == 1; |
||||
|
SessionMsgType sessionMsgType; |
||||
|
if (featureType == FeatureType.RPC) { |
||||
|
sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST : SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST; |
||||
|
} else { |
||||
|
sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST : SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST; |
||||
|
} |
||||
|
processRequest(exchange, sessionMsgType); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void handlePOST(CoapExchange exchange) { |
||||
|
if (transportContext.getQuotaService().isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) { |
||||
|
log.warn("CoAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort()); |
||||
|
exchange.respond(ResponseCode.BAD_REQUEST); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest()); |
||||
|
if (!featureType.isPresent()) { |
||||
|
log.trace("Missing feature type parameter"); |
||||
|
exchange.respond(ResponseCode.BAD_REQUEST); |
||||
|
} else { |
||||
|
switch (featureType.get()) { |
||||
|
case ATTRIBUTES: |
||||
|
processRequest(exchange, SessionMsgType.POST_ATTRIBUTES_REQUEST); |
||||
|
break; |
||||
|
case TELEMETRY: |
||||
|
processRequest(exchange, SessionMsgType.POST_TELEMETRY_REQUEST); |
||||
|
break; |
||||
|
case RPC: |
||||
|
Optional<Integer> requestId = getRequestId(exchange.advanced().getRequest()); |
||||
|
if (requestId.isPresent()) { |
||||
|
processRequest(exchange, SessionMsgType.TO_DEVICE_RPC_RESPONSE); |
||||
|
} else { |
||||
|
processRequest(exchange, SessionMsgType.TO_SERVER_RPC_REQUEST); |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void processRequest(CoapExchange exchange, SessionMsgType type) { |
||||
|
log.trace("Processing {}", exchange.advanced().getRequest()); |
||||
|
exchange.accept(); |
||||
|
Exchange advanced = exchange.advanced(); |
||||
|
Request request = advanced.getRequest(); |
||||
|
|
||||
|
Optional<DeviceTokenCredentials> credentials = decodeCredentials(request); |
||||
|
if (!credentials.isPresent()) { |
||||
|
exchange.respond(ResponseCode.BAD_REQUEST); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
transportService.process(TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(credentials.get().getCredentialsId()).build(), |
||||
|
new DeviceAuthCallback(transportContext, exchange, sessionInfo -> { |
||||
|
UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); |
||||
|
try { |
||||
|
switch (type) { |
||||
|
case POST_ATTRIBUTES_REQUEST: |
||||
|
transportService.process(sessionInfo, |
||||
|
transportContext.getAdaptor().convertToPostAttributes(sessionId, request), |
||||
|
new CoapOkCallback(exchange)); |
||||
|
break; |
||||
|
case POST_TELEMETRY_REQUEST: |
||||
|
transportService.process(sessionInfo, |
||||
|
transportContext.getAdaptor().convertToPostTelemetry(sessionId, request), |
||||
|
new CoapOkCallback(exchange)); |
||||
|
break; |
||||
|
case SUBSCRIBE_ATTRIBUTES_REQUEST: |
||||
|
advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced), |
||||
|
registerAsyncCoapSession(exchange, request, sessionInfo, sessionId))); |
||||
|
transportService.process(sessionInfo, |
||||
|
TransportProtos.SubscribeToAttributeUpdatesMsg.getDefaultInstance(), |
||||
|
new CoapNoOpCallback(exchange)); |
||||
|
break; |
||||
|
case UNSUBSCRIBE_ATTRIBUTES_REQUEST: |
||||
|
TransportProtos.SessionInfoProto attrSession = lookupAsyncSessionInfo(request); |
||||
|
if (attrSession != null) { |
||||
|
transportService.process(attrSession, |
||||
|
TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setUnsubscribe(true).build(), |
||||
|
new CoapOkCallback(exchange)); |
||||
|
closeAndDeregister(sessionInfo); |
||||
|
} |
||||
|
break; |
||||
|
case SUBSCRIBE_RPC_COMMANDS_REQUEST: |
||||
|
advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced), |
||||
|
registerAsyncCoapSession(exchange, request, sessionInfo, sessionId))); |
||||
|
transportService.process(sessionInfo, |
||||
|
TransportProtos.SubscribeToRPCMsg.getDefaultInstance(), |
||||
|
new CoapNoOpCallback(exchange)); |
||||
|
break; |
||||
|
case UNSUBSCRIBE_RPC_COMMANDS_REQUEST: |
||||
|
TransportProtos.SessionInfoProto rpcSession = lookupAsyncSessionInfo(request); |
||||
|
if (rpcSession != null) { |
||||
|
transportService.process(rpcSession, |
||||
|
TransportProtos.SubscribeToRPCMsg.newBuilder().setUnsubscribe(true).build(), |
||||
|
new CoapOkCallback(exchange)); |
||||
|
transportService.process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null); |
||||
|
transportService.deregisterSession(rpcSession); |
||||
|
} |
||||
|
break; |
||||
|
case TO_DEVICE_RPC_RESPONSE: |
||||
|
transportService.process(sessionInfo, |
||||
|
transportContext.getAdaptor().convertToDeviceRpcResponse(sessionId, request), |
||||
|
new CoapOkCallback(exchange)); |
||||
|
break; |
||||
|
case TO_SERVER_RPC_REQUEST: |
||||
|
transportService.process(sessionInfo, |
||||
|
transportContext.getAdaptor().convertToServerRpcRequest(sessionId, request), |
||||
|
new CoapNoOpCallback(exchange)); |
||||
|
break; |
||||
|
case GET_ATTRIBUTES_REQUEST: |
||||
|
transportService.registerSyncSession(sessionInfo, new CoapSessionListener(sessionId, exchange), transportContext.getTimeout()); |
||||
|
transportService.process(sessionInfo, |
||||
|
transportContext.getAdaptor().convertToGetAttributes(sessionId, request), |
||||
|
new CoapNoOpCallback(exchange)); |
||||
|
break; |
||||
|
} |
||||
|
} catch (AdaptorException e) { |
||||
|
log.trace("[{}] Failed to decode message: ", sessionId, e); |
||||
|
exchange.respond(ResponseCode.BAD_REQUEST); |
||||
|
} catch (IllegalAccessException e) { |
||||
|
log.trace("[{}] Failed to process message: ", sessionId, e); |
||||
|
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
})); |
||||
|
} |
||||
|
|
||||
|
private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(Request request) { |
||||
|
String token = request.getSource().getHostAddress() + ":" + request.getSourcePort() + ":" + request.getTokenString(); |
||||
|
return tokenToSessionIdMap.remove(token); |
||||
|
} |
||||
|
|
||||
|
private String registerAsyncCoapSession(CoapExchange exchange, Request request, TransportProtos.SessionInfoProto sessionInfo, UUID sessionId) { |
||||
|
String token = request.getSource().getHostAddress() + ":" + request.getSourcePort() + ":" + request.getTokenString(); |
||||
|
tokenToSessionIdMap.putIfAbsent(token, sessionInfo); |
||||
|
CoapSessionListener attrListener = new CoapSessionListener(sessionId, exchange); |
||||
|
transportService.registerAsyncSession(sessionInfo, attrListener); |
||||
|
transportService.process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.OPEN), null); |
||||
|
return token; |
||||
|
} |
||||
|
|
||||
|
private static TransportProtos.SessionEventMsg getSessionEventMsg(TransportProtos.SessionEvent event) { |
||||
|
return TransportProtos.SessionEventMsg.newBuilder() |
||||
|
.setSessionType(TransportProtos.SessionType.ASYNC) |
||||
|
.setEvent(event).build(); |
||||
|
} |
||||
|
|
||||
|
private Optional<DeviceTokenCredentials> decodeCredentials(Request request) { |
||||
|
List<String> uriPath = request.getOptions().getUriPath(); |
||||
|
if (uriPath.size() >= ACCESS_TOKEN_POSITION) { |
||||
|
return Optional.of(new DeviceTokenCredentials(uriPath.get(ACCESS_TOKEN_POSITION - 1))); |
||||
|
} else { |
||||
|
return Optional.empty(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private Optional<FeatureType> getFeatureType(Request request) { |
||||
|
List<String> uriPath = request.getOptions().getUriPath(); |
||||
|
try { |
||||
|
if (uriPath.size() >= FEATURE_TYPE_POSITION) { |
||||
|
return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase())); |
||||
|
} |
||||
|
} catch (RuntimeException e) { |
||||
|
log.warn("Failed to decode feature type: {}", uriPath); |
||||
|
} |
||||
|
return Optional.empty(); |
||||
|
} |
||||
|
|
||||
|
public static Optional<Integer> getRequestId(Request request) { |
||||
|
List<String> uriPath = request.getOptions().getUriPath(); |
||||
|
try { |
||||
|
if (uriPath.size() >= REQUEST_ID_POSITION) { |
||||
|
return Optional.of(Integer.valueOf(uriPath.get(REQUEST_ID_POSITION - 1))); |
||||
|
} |
||||
|
} catch (RuntimeException e) { |
||||
|
log.warn("Failed to decode feature type: {}", uriPath); |
||||
|
} |
||||
|
return Optional.empty(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Resource getChild(String name) { |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
private static class DeviceAuthCallback implements TransportServiceCallback<TransportProtos.ValidateDeviceCredentialsResponseMsg> { |
||||
|
private final TransportContext transportContext; |
||||
|
private final CoapExchange exchange; |
||||
|
private final Consumer<TransportProtos.SessionInfoProto> onSuccess; |
||||
|
|
||||
|
DeviceAuthCallback(TransportContext transportContext, CoapExchange exchange, Consumer<TransportProtos.SessionInfoProto> onSuccess) { |
||||
|
this.transportContext = transportContext; |
||||
|
this.exchange = exchange; |
||||
|
this.onSuccess = onSuccess; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onSuccess(TransportProtos.ValidateDeviceCredentialsResponseMsg msg) { |
||||
|
if (msg.hasDeviceInfo()) { |
||||
|
UUID sessionId = UUID.randomUUID(); |
||||
|
TransportProtos.DeviceInfoProto deviceInfoProto = msg.getDeviceInfo(); |
||||
|
TransportProtos.SessionInfoProto sessionInfo = TransportProtos.SessionInfoProto.newBuilder() |
||||
|
.setNodeId(transportContext.getNodeId()) |
||||
|
.setTenantIdMSB(deviceInfoProto.getTenantIdMSB()) |
||||
|
.setTenantIdLSB(deviceInfoProto.getTenantIdLSB()) |
||||
|
.setDeviceIdMSB(deviceInfoProto.getDeviceIdMSB()) |
||||
|
.setDeviceIdLSB(deviceInfoProto.getDeviceIdLSB()) |
||||
|
.setSessionIdMSB(sessionId.getMostSignificantBits()) |
||||
|
.setSessionIdLSB(sessionId.getLeastSignificantBits()) |
||||
|
.build(); |
||||
|
onSuccess.accept(sessionInfo); |
||||
|
} else { |
||||
|
exchange.respond(ResponseCode.UNAUTHORIZED); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onError(Throwable e) { |
||||
|
log.warn("Failed to process request", e); |
||||
|
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static class CoapOkCallback implements TransportServiceCallback<Void> { |
||||
|
private final CoapExchange exchange; |
||||
|
|
||||
|
CoapOkCallback(CoapExchange exchange) { |
||||
|
this.exchange = exchange; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onSuccess(Void msg) { |
||||
|
exchange.respond(ResponseCode.VALID); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onError(Throwable e) { |
||||
|
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static class CoapNoOpCallback implements TransportServiceCallback<Void> { |
||||
|
private final CoapExchange exchange; |
||||
|
|
||||
|
CoapNoOpCallback(CoapExchange exchange) { |
||||
|
this.exchange = exchange; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onSuccess(Void msg) { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onError(Throwable e) { |
||||
|
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class CoapSessionListener implements SessionMsgListener { |
||||
|
|
||||
|
private final CoapExchange exchange; |
||||
|
private final AtomicInteger seqNumber = new AtomicInteger(2); |
||||
|
|
||||
|
CoapSessionListener(UUID sessionId, CoapExchange exchange) { |
||||
|
this.exchange = exchange; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg msg) { |
||||
|
try { |
||||
|
exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg)); |
||||
|
} catch (AdaptorException e) { |
||||
|
log.trace("Failed to reply due to error", e); |
||||
|
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg) { |
||||
|
try { |
||||
|
exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg)); |
||||
|
} catch (AdaptorException e) { |
||||
|
log.trace("Failed to reply due to error", e); |
||||
|
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onRemoteSessionCloseCommand(TransportProtos.SessionCloseNotificationProto sessionCloseNotification) { |
||||
|
exchange.respond(ResponseCode.SERVICE_UNAVAILABLE); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg msg) { |
||||
|
try { |
||||
|
exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg)); |
||||
|
} catch (AdaptorException e) { |
||||
|
log.trace("Failed to reply due to error", e); |
||||
|
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg msg) { |
||||
|
try { |
||||
|
exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg)); |
||||
|
} catch (AdaptorException e) { |
||||
|
log.trace("Failed to reply due to error", e); |
||||
|
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public int getNextSeqNumber() { |
||||
|
return seqNumber.getAndIncrement(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class CoapExchangeObserverProxy implements ExchangeObserver { |
||||
|
|
||||
|
private final ExchangeObserver proxy; |
||||
|
private final String token; |
||||
|
|
||||
|
CoapExchangeObserverProxy(ExchangeObserver proxy, String token) { |
||||
|
super(); |
||||
|
this.proxy = proxy; |
||||
|
this.token = token; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void completed(Exchange exchange) { |
||||
|
proxy.completed(exchange); |
||||
|
TransportProtos.SessionInfoProto session = tokenToSessionIdMap.remove(token); |
||||
|
if (session != null) { |
||||
|
closeAndDeregister(session); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void closeAndDeregister(TransportProtos.SessionInfoProto session) { |
||||
|
transportService.process(session, getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null); |
||||
|
transportService.deregisterSession(session); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.coap.adaptors; |
||||
|
|
||||
|
import org.eclipse.californium.core.coap.Request; |
||||
|
import org.eclipse.californium.core.coap.Response; |
||||
|
import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos; |
||||
|
import org.thingsboard.server.transport.coap.CoapTransportResource; |
||||
|
|
||||
|
import java.util.UUID; |
||||
|
import java.util.Optional; |
||||
|
|
||||
|
public interface CoapTransportAdaptor { |
||||
|
|
||||
|
TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound) throws AdaptorException; |
||||
|
|
||||
|
TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound) throws AdaptorException; |
||||
|
|
||||
|
TransportProtos.GetAttributeRequestMsg convertToGetAttributes(UUID sessionId, Request inbound) throws AdaptorException; |
||||
|
|
||||
|
TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound) throws AdaptorException; |
||||
|
|
||||
|
TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(UUID sessionId, Request inbound) throws AdaptorException; |
||||
|
|
||||
|
Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException; |
||||
|
|
||||
|
Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; |
||||
|
|
||||
|
Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; |
||||
|
|
||||
|
Response convertToPublish(CoapTransportResource.CoapSessionListener coapSessionListener, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,155 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.coap.adaptors; |
||||
|
|
||||
|
import java.util.*; |
||||
|
|
||||
|
import com.google.gson.JsonElement; |
||||
|
import com.google.gson.JsonObject; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.eclipse.californium.core.coap.CoAP; |
||||
|
import org.eclipse.californium.core.coap.Request; |
||||
|
import org.eclipse.californium.core.coap.Response; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
import org.thingsboard.server.common.msg.kv.AttributesKVMsg; |
||||
|
import org.thingsboard.server.common.msg.session.SessionContext; |
||||
|
import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
||||
|
import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import com.google.gson.JsonParser; |
||||
|
import com.google.gson.JsonSyntaxException; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos; |
||||
|
import org.thingsboard.server.transport.coap.CoapTransportResource; |
||||
|
|
||||
|
@Component("JsonCoapAdaptor") |
||||
|
@Slf4j |
||||
|
public class JsonCoapAdaptor implements CoapTransportAdaptor { |
||||
|
|
||||
|
@Override |
||||
|
public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound) throws AdaptorException { |
||||
|
String payload = validatePayload(sessionId, inbound); |
||||
|
try { |
||||
|
return JsonConverter.convertToTelemetryProto(new JsonParser().parse(payload)); |
||||
|
} catch (IllegalStateException | JsonSyntaxException ex) { |
||||
|
throw new AdaptorException(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound) throws AdaptorException { |
||||
|
String payload = validatePayload(sessionId, inbound); |
||||
|
try { |
||||
|
return JsonConverter.convertToAttributesProto(new JsonParser().parse(payload)); |
||||
|
} catch (IllegalStateException | JsonSyntaxException ex) { |
||||
|
throw new AdaptorException(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(UUID sessionId, Request inbound) throws AdaptorException { |
||||
|
List<String> queryElements = inbound.getOptions().getUriQuery(); |
||||
|
TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder(); |
||||
|
if (queryElements != null && queryElements.size() > 0) { |
||||
|
Set<String> clientKeys = toKeys(queryElements, "clientKeys"); |
||||
|
Set<String> sharedKeys = toKeys(queryElements, "sharedKeys"); |
||||
|
if (clientKeys != null) { |
||||
|
result.addAllClientAttributeNames(clientKeys); |
||||
|
} |
||||
|
if (sharedKeys != null) { |
||||
|
result.addAllSharedAttributeNames(sharedKeys); |
||||
|
} |
||||
|
} |
||||
|
return result.build(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound) throws AdaptorException { |
||||
|
Optional<Integer> requestId = CoapTransportResource.getRequestId(inbound); |
||||
|
String payload = validatePayload(sessionId, inbound); |
||||
|
JsonObject response = new JsonParser().parse(payload).getAsJsonObject(); |
||||
|
return TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId.orElseThrow(() -> new AdaptorException("Request id is missing!"))) |
||||
|
.setPayload(response.toString()).build(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(UUID sessionId, Request inbound) throws AdaptorException { |
||||
|
String payload = validatePayload(sessionId, inbound); |
||||
|
return JsonConverter.convertToServerRpcRequest(new JsonParser().parse(payload), 0); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException { |
||||
|
return getObserveNotification(session.getNextSeqNumber(), JsonConverter.toJson(msg)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.ToDeviceRpcRequestMsg msg) throws AdaptorException { |
||||
|
return getObserveNotification(session.getNextSeqNumber(), JsonConverter.toJson(msg, true)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Response convertToPublish(CoapTransportResource.CoapSessionListener coapSessionListener, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException { |
||||
|
Response response = new Response(CoAP.ResponseCode.CONTENT); |
||||
|
JsonElement result = JsonConverter.toJson(msg); |
||||
|
response.setPayload(result.toString()); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { |
||||
|
if (msg.getClientAttributeListCount() == 0 && msg.getSharedAttributeListCount() == 0 && msg.getDeletedAttributeKeysCount() == 0) { |
||||
|
return new Response(CoAP.ResponseCode.NOT_FOUND); |
||||
|
} else { |
||||
|
Response response = new Response(CoAP.ResponseCode.CONTENT); |
||||
|
JsonObject result = JsonConverter.toJson(msg); |
||||
|
response.setPayload(result.toString()); |
||||
|
return response; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private Response getObserveNotification(int seqNumber, JsonElement json) { |
||||
|
Response response = new Response(CoAP.ResponseCode.CONTENT); |
||||
|
response.getOptions().setObserve(seqNumber); |
||||
|
response.setPayload(json.toString()); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
private String validatePayload(UUID sessionId, Request inbound) throws AdaptorException { |
||||
|
String payload = inbound.getPayloadString(); |
||||
|
if (payload == null) { |
||||
|
log.warn("[{}] Payload is empty!", sessionId); |
||||
|
throw new AdaptorException(new IllegalArgumentException("Payload is empty!")); |
||||
|
} |
||||
|
return payload; |
||||
|
} |
||||
|
|
||||
|
private Set<String> toKeys(List<String> queryElements, String attributeName) throws AdaptorException { |
||||
|
String keys = null; |
||||
|
for (String queryElement : queryElements) { |
||||
|
String[] queryItem = queryElement.split("="); |
||||
|
if (queryItem.length == 2 && queryItem[0].equals(attributeName)) { |
||||
|
keys = queryItem[1]; |
||||
|
} |
||||
|
} |
||||
|
if (keys != null && !StringUtils.isEmpty(keys)) { |
||||
|
return new HashSet<>(Arrays.asList(keys.split(","))); |
||||
|
} else { |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2018 The Thingsboard Authors |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
|
||||
|
--> |
||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<parent> |
||||
|
<groupId>org.thingsboard.common</groupId> |
||||
|
<version>2.2.0-SNAPSHOT</version> |
||||
|
<artifactId>transport</artifactId> |
||||
|
</parent> |
||||
|
<groupId>org.thingsboard.common.transport</groupId> |
||||
|
<artifactId>http</artifactId> |
||||
|
<packaging>jar</packaging> |
||||
|
|
||||
|
<name>Thingsboard HTTP Transport Common</name> |
||||
|
<url>https://thingsboard.io</url> |
||||
|
|
||||
|
<properties> |
||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
|
<main.dir>${basedir}/../../..</main.dir> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.thingsboard.common.transport</groupId> |
||||
|
<artifactId>transport-api</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.slf4j</groupId> |
||||
|
<artifactId>slf4j-api</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.slf4j</groupId> |
||||
|
<artifactId>log4j-over-slf4j</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>ch.qos.logback</groupId> |
||||
|
<artifactId>logback-core</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>ch.qos.logback</groupId> |
||||
|
<artifactId>logback-classic</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-test</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>junit</groupId> |
||||
|
<artifactId>junit</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.mockito</groupId> |
||||
|
<artifactId>mockito-all</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
|
||||
|
</project> |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue