/* * Copyright 2014-2016 CyberVision, Inc. * * 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.kaaproject.kaa.server.operations.service.akka.actors.core.endpoint.global; import akka.actor.ActorContext; import org.kaaproject.kaa.common.hash.EndpointObjectHash; import org.kaaproject.kaa.server.common.Base64Util; import org.kaaproject.kaa.server.common.thrift.gen.operations.ThriftActorClassifier; import org.kaaproject.kaa.server.common.thrift.gen.operations.ThriftEndpointConfigurationRefreshMessage; import org.kaaproject.kaa.server.common.thrift.gen.operations.ThriftServerProfileUpdateMessage; import org.kaaproject.kaa.server.common.thrift.gen.operations.ThriftUnicastNotificationMessage; import org.kaaproject.kaa.server.operations.service.OperationsService; import org.kaaproject.kaa.server.operations.service.akka.AkkaContext; import org.kaaproject.kaa.server.operations.service.akka.actors.core.endpoint.AbstractEndpointActorMessageProcessor; import org.kaaproject.kaa.server.operations.service.akka.messages.core.route.ActorClassifier; import org.kaaproject.kaa.server.operations.service.akka.messages.core.route.EndpointClusterAddress; import org.kaaproject.kaa.server.operations.service.akka.messages.core.route.EndpointRouteMessage; import org.kaaproject.kaa.server.operations.service.akka.messages.core.route.RouteTable; import org.kaaproject.kaa.server.operations.service.akka.messages.core.route.ThriftEndpointActorMsg; import org.kaaproject.kaa.server.operations.service.cluster.ClusterService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.function.BiConsumer; public class GlobalEndpointActorMessageProcessor extends AbstractEndpointActorMessageProcessor<GlobalEndpointActorState> { private static final Logger LOG = LoggerFactory .getLogger(GlobalEndpointActorMessageProcessor.class); private final String nodeId; private final RouteTable<EndpointClusterAddress> routes; private final ClusterService clusterService; private final OperationsService operationsService; /** * All-args constructor. */ public GlobalEndpointActorMessageProcessor(AkkaContext context, String appToken, EndpointObjectHash key, String actorKey) { super(new GlobalEndpointActorState(Base64Util.encode(key.getData()), actorKey), context.getOperationsService(), appToken, key, actorKey, Base64Util.encode(key.getData()), context.getGlobalEndpointTimeout() ); clusterService = context.getClusterService(); operationsService = context.getOperationsService(); nodeId = context.getClusterService().getNodeId(); routes = new RouteTable<>(nodeId); } /** * Process an endpoint route message. * * @param message endpoint route message */ public void processRouteMessage(EndpointRouteMessage message) { LOG.debug("[{}] Processing {} operation for address {}", endpointKey, message.getOperation(), message.getAddress()); switch (message.getOperation()) { case ADD: case UPDATE: routes.add(message.getAddress()); break; case DELETE: routes.remove(message.getAddress()); break; default: break; } } /** * Process a cluster update. * * @param context actor context */ public void processClusterUpdate(ActorContext context) { if (!clusterService.isMainEntityNode(key)) { LOG.debug("[{}] No longer a global endpoint node for {}", endpointKey); routes.clear(); context.stop(context.self()); } } @Override protected void processThriftMsg(ActorContext context, ThriftEndpointActorMsg<?> msg) { Object thriftMsg = msg.getMsg(); if (thriftMsg instanceof ThriftServerProfileUpdateMessage) { processServerProfileUpdateMsg(context, (ThriftServerProfileUpdateMessage) thriftMsg); } else if (thriftMsg instanceof ThriftUnicastNotificationMessage) { processUnicastNotificationMsg(context, (ThriftUnicastNotificationMessage) thriftMsg); } else if (thriftMsg instanceof ThriftEndpointConfigurationRefreshMessage) { processEndpointConfigurationRefreshMsg(context, (ThriftEndpointConfigurationRefreshMessage) thriftMsg); } } private void processServerProfileUpdateMsg(ActorContext context, ThriftServerProfileUpdateMessage thriftMsg) { operationsService.syncServerProfile(appToken, endpointKey, key); ThriftServerProfileUpdateMessage localMsg = new ThriftServerProfileUpdateMessage(thriftMsg); localMsg.setActorClassifier(ThriftActorClassifier.LOCAL); dispatchMsg(context, localMsg, clusterService::sendServerProfileUpdateMessage); } private void processUnicastNotificationMsg(ActorContext context, ThriftUnicastNotificationMessage thriftMsg) { ThriftUnicastNotificationMessage localMsg = new ThriftUnicastNotificationMessage(thriftMsg); localMsg.setActorClassifier(ThriftActorClassifier.LOCAL); dispatchMsg(context, localMsg, clusterService::sendUnicastNotificationMessage); } private void processEndpointConfigurationRefreshMsg(ActorContext context, ThriftEndpointConfigurationRefreshMessage thriftMsg) { ThriftEndpointConfigurationRefreshMessage localMsg = new ThriftEndpointConfigurationRefreshMessage(thriftMsg); localMsg.setActorClassifier(ThriftActorClassifier.LOCAL); dispatchMsg(context, localMsg, clusterService::sendEndpointConfigurationRefreshMessage); } private <T> void dispatchMsg(ActorContext context, T localMsg, BiConsumer<String, T> biConsumer) { for (EndpointClusterAddress address : routes.getLocalRoutes()) { LOG.info("Forwarding {} to local endpoint actor {}", localMsg, address); ThriftEndpointActorMsg<T> msg = new ThriftEndpointActorMsg<>( address.toEndpointAddress(), ActorClassifier.LOCAL, localMsg); context.parent().tell(msg, context.self()); } for (EndpointClusterAddress address : routes.getRemoteRoutes()) { LOG.info("Forwarding {} to remote endpoint actor {}", localMsg, address); biConsumer.accept(address.getNodeId(), localMsg); } } }