package edu.uw.zookeeper.server;
import java.util.Arrays;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.zookeeper.KeeperException;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import edu.uw.zookeeper.protocol.ConnectMessage;
import edu.uw.zookeeper.protocol.Session;
import edu.uw.zookeeper.protocol.ZxidReference;
public class ConnectMessageProcessor
implements Function<ConnectMessage.Request, ConnectMessage.Response> {
public static ConnectMessageProcessor defaults(
SessionManager sessions,
ZxidReference lastZxid) {
return new ConnectMessageProcessor(
ImmutableList.<Function<ConnectMessage.Request, KeeperException.Code>>of(
new ZxidValidator(lastZxid),
new ReadOnlyValidator(false),
new ExistingSessionValidator(sessions)),
sessions);
}
protected final Logger logger;
protected final ImmutableList<Function<ConnectMessage.Request, KeeperException.Code>> validators;
protected final SessionManager sessions;
protected ConnectMessageProcessor(
ImmutableList<Function<ConnectMessage.Request, KeeperException.Code>> validators,
SessionManager sessions) {
this.logger = LogManager.getLogger(this);
this.validators = validators;
this.sessions = sessions;
}
@Override
public ConnectMessage.Response apply(ConnectMessage.Request input) {
for (Function<ConnectMessage.Request, KeeperException.Code> validator: validators) {
KeeperException.Code code = validator.apply(input);
if (code != KeeperException.Code.OK) {
throw new IllegalArgumentException(KeeperException.create(code));
}
}
Session.Parameters parameters = input.toParameters();
final Session session;
if (input instanceof ConnectMessage.Request.NewRequest) {
session = sessions.create(parameters.timeOut());
logger.info("Created session {}", Session.toString(session.id()));
} else {
session = sessions.get(input.getSessionId());
if (session == null) {
throw new IllegalArgumentException(new KeeperException.UnknownSessionException());
}
logger.info("Renewed session {}", Session.toString(input.getSessionId()));
}
return ConnectMessage.Response.Valid.newInstance(session, input.getReadOnly(), input.legacy());
}
public static final class ZxidValidator implements Function<ConnectMessage.Request, KeeperException.Code> {
private final ZxidReference lastZxid;
public ZxidValidator(
ZxidReference lastZxid) {
this.lastZxid = lastZxid;
}
public ZxidReference lastZxid() {
return lastZxid;
}
@Override
public KeeperException.Code apply(ConnectMessage.Request input) {
// note that the behavior of ZooKeeperServer
// is to just close the connection
// without replying when the zxid is out of sync
long zxid = lastZxid.get();
if (input.getLastZxidSeen() > zxid) {
return KeeperException.Code.BADARGUMENTS;
}
return KeeperException.Code.OK;
}
}
public static final class ReadOnlyValidator implements Function<ConnectMessage.Request, KeeperException.Code> {
private final boolean readOnly;
public ReadOnlyValidator(
boolean readOnly) {
this.readOnly = readOnly;
}
public boolean readOnly() {
return readOnly;
}
@Override
public KeeperException.Code apply(ConnectMessage.Request input) {
if (readOnly() && !input.getReadOnly()) {
return KeeperException.Code.NOTREADONLY;
}
return KeeperException.Code.OK;
}
}
public static final class ExistingSessionValidator implements Function<ConnectMessage.Request, KeeperException.Code> {
private final SessionManager sessions;
public ExistingSessionValidator(SessionManager sessions) {
this.sessions = sessions;
}
public SessionManager sessions() {
return sessions;
}
@Override
public KeeperException.Code apply(ConnectMessage.Request input) {
if (input instanceof ConnectMessage.Request.RenewRequest) {
Session session = sessions.get(input.getSessionId());
if (session != null) {
if (! Arrays.equals(session.parameters().password(), input.getPasswd())) {
return KeeperException.Code.BADARGUMENTS;
}
} else {
return KeeperException.Code.UNKNOWNSESSION;
}
}
return KeeperException.Code.OK;
}
}
}