/*
* 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.io;
import akka.actor.ActorRef;
import akka.actor.UntypedActor;
import akka.japi.Creator;
import org.kaaproject.kaa.server.common.thrift.gen.operations.RedirectionRule;
import org.kaaproject.kaa.server.operations.service.akka.AkkaContext;
import org.kaaproject.kaa.server.operations.service.akka.messages.io.RuleTimeoutMessage;
import org.kaaproject.kaa.server.operations.service.akka.messages.io.response.SessionResponse;
import org.kaaproject.kaa.server.transport.message.SessionAwareMessage;
import org.kaaproject.kaa.server.transport.message.SessionInitMessage;
import org.kaaproject.kaa.server.transport.session.SessionAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.concurrent.duration.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class EncDecActor extends UntypedActor {
private static final Logger LOG = LoggerFactory.getLogger(EncDecActor.class);
private final EncDecActorMessageProcessor messageProcessor;
/**
* Current redirection rules.
*/
private final HashMap<Long, RedirectionRule> redirectionRules; // NOSONAR
private final Random random;
/**
* Instantiates a new enc dec actor.
*
* @param epsActor the eps actor
* @param context the akka context
* @param platformProtocols the platform protocols
*/
public EncDecActor(ActorRef epsActor, AkkaContext context, Set<String> platformProtocols) {
super();
this.messageProcessor = new EncDecActorMessageProcessor(epsActor, context, platformProtocols);
this.redirectionRules = new HashMap<>();
this.random = new Random();
}
public static RedirectionRule checkInitRedirection(
HashMap<Long, RedirectionRule> redirectionRules, double random) {
return checkRedirection(redirectionRules, random, true);
}
public static RedirectionRule checkSessionRedirection(
HashMap<Long, RedirectionRule> redirectionRules, double random) {
return checkRedirection(redirectionRules, random, false);
}
/**
* Check redirection redirection rule.
*
* @param redirectionRules the redirection rules
* @param random the random
* @param initSession determines if the session is initial
* @return the redirection rule
*/
public static RedirectionRule checkRedirection(HashMap<Long, RedirectionRule> redirectionRules,
double random, boolean initSession) { // NOSONAR
RedirectionRule result = null;
for (RedirectionRule rule : redirectionRules.values()) {
double redirectionProbability = initSession
? rule.initRedirectProbability : rule.sessionRedirectProbability;
if (random <= redirectionProbability) {
result = rule;
break;
} else {
random -= redirectionProbability;
}
}
return result;
}
/*
* (non-Javadoc)
*
* @see akka.actor.UntypedActor#preStart()
*/
@Override
public void preStart() {
LOG.info("Starting " + this);
}
/*
* (non-Javadoc)
*
* @see akka.actor.UntypedActor#postStop()
*/
@Override
public void postStop() {
LOG.info("Stoped " + this);
}
/*
* (non-Javadoc)
*
* @see akka.actor.UntypedActor#onReceive(java.lang.Object)
*/
@Override
public void onReceive(Object message) throws Exception {
LOG.debug("Received: {}", message.getClass().getName());
if (message instanceof SessionInitMessage) {
RedirectionRule redirection = checkInitRedirection(redirectionRules, random.nextDouble());
if (redirection == null) {
messageProcessor.decodeAndForward(context(), (SessionInitMessage) message);
} else {
messageProcessor.redirect(redirection, (SessionInitMessage) message);
}
} else if (message instanceof SessionAware) {
if (message instanceof SessionAwareMessage) {
RedirectionRule redirection = checkSessionRedirection(
redirectionRules, random.nextDouble());
if (redirection == null) {
messageProcessor.decodeAndForward(context(), (SessionAwareMessage) message);
} else {
messageProcessor.redirect(redirection, (SessionAwareMessage) message);
}
} else {
messageProcessor.forward(context(), (SessionAware) message);
}
} else if (message instanceof SessionResponse) {
messageProcessor.encodeAndReply((SessionResponse) message);
} else if (message instanceof RedirectionRule) {
applyRedirectionRule((RedirectionRule) message);
} else if (message instanceof RuleTimeoutMessage) {
removeRedirectionRule((RuleTimeoutMessage) message);
}
}
private void applyRedirectionRule(RedirectionRule body) {
context()
.system()
.scheduler()
.scheduleOnce(Duration.create(body.ruleTTL, TimeUnit.MILLISECONDS), self(),
new RuleTimeoutMessage(body.getRuleId()),
context().dispatcher(), self());
redirectionRules.put(body.getRuleId(), body);
}
private void removeRedirectionRule(RuleTimeoutMessage message) {
if (redirectionRules.remove(message.getRuleId()) != null) {
LOG.info("Redirection rule {} removed", message.getRuleId());
}
}
public static class ActorCreator implements Creator<EncDecActor> {
private static final long serialVersionUID = 1L;
private final ActorRef epsActor;
private final AkkaContext context;
private final Set<String> platformProtocols;
/**
* Instantiates a new actor creator.
*
* @param epsActor the eps actor
* @param context the context
* @param platformProtocols the platform protocols
*/
public ActorCreator(ActorRef epsActor, AkkaContext context, Set<String> platformProtocols) {
super();
this.epsActor = epsActor;
this.context = context;
this.platformProtocols = new HashSet<>(platformProtocols);
}
/*
* (non-Javadoc)
*
* @see akka.japi.Creator#create()
*/
@Override
public EncDecActor create() throws Exception {
return new EncDecActor(epsActor, context, platformProtocols);
}
public Set<String> getPlatformProtocols() {
return platformProtocols;
}
}
}