| /* |
| * Copyright 2011 Google 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 com.google.ipc.invalidation.common; |
| |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ApplicationClientIdPAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ClientConfigPAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ClientHeaderAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ClientToServerMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ClientVersionAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ConfigChangeMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ErrorMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.InfoMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.InfoRequestMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.InitializeMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.InvalidationMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.InvalidationPAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ObjectIdPAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ProtocolHandlerConfigPAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.RateLimitPAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationPAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationStatusAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationStatusMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationSubtreeAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationSummaryAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.RegistrationSyncMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ServerHeaderAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.ServerToClientMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.StatusPAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.TokenControlMessageAccessor; |
| import com.google.ipc.invalidation.common.ClientProtocolAccessor.VersionAccessor; |
| import com.google.ipc.invalidation.util.BaseLogger; |
| import com.google.protobuf.MessageLite; |
| import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP; |
| import com.google.protos.ipc.invalidation.ClientProtocol.ClientHeader; |
| import com.google.protos.ipc.invalidation.ClientProtocol.ClientToServerMessage; |
| import com.google.protos.ipc.invalidation.ClientProtocol.ConfigChangeMessage; |
| import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage; |
| import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP; |
| import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP; |
| import com.google.protos.ipc.invalidation.ClientProtocol.RateLimitP; |
| import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary; |
| import com.google.protos.ipc.invalidation.ClientProtocol.ServerHeader; |
| import com.google.protos.ipc.invalidation.ClientProtocol.ServerToClientMessage; |
| import com.google.protos.ipc.invalidation.ClientProtocol.Version; |
| |
| /** |
| * Validator for v2 protocol messages. |
| * <p> |
| * The basic idea is to declare information about each field in each message, i.e., whether it is |
| * optional or it is required. {@code FieldInfo} is a class that keeps track of information |
| * about each field and {@code MessageInfo} is a class that keeps track of information about each |
| * message. Given a message, we recursively descend a MessageInfo and determine if the fields |
| * are as expected. Then once we are done with a message, we perform a post validation step |
| * which checks constraints across fields. |
| * |
| */ |
| public class TiclMessageValidator2 extends ProtoValidator { |
| public TiclMessageValidator2(BaseLogger logger) { |
| super(logger); |
| } |
| |
| /** Describes how to validate common messages. */ |
| |
| public class CommonMsgInfos { |
| |
| /** Validation for composite (major/minor) versions. */ |
| final MessageInfo VERSION = new MessageInfo(ClientProtocolAccessor.VERSION_ACCESSOR, |
| FieldInfo.newRequired(VersionAccessor.MAJOR_VERSION), |
| FieldInfo.newRequired(VersionAccessor.MINOR_VERSION)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| // Versions must be non-negative. |
| Version version = (Version) message; |
| if ((version.getMajorVersion() < 0) || (version.getMinorVersion() < 0)) { |
| logger.info("Invalid versions: %s", version); |
| return false; |
| } |
| return true; |
| } |
| }; |
| |
| /** Validation for the protocol version. */ |
| final MessageInfo PROTOCOL_VERSION = new MessageInfo( |
| ClientProtocolAccessor.PROTOCOL_VERSION_ACCESSOR, |
| FieldInfo.newRequired(ClientProtocolAccessor.ProtocolVersionAccessor.VERSION, VERSION)); |
| |
| /** Validation for object ids. */ |
| final MessageInfo OID = new MessageInfo(ClientProtocolAccessor.OBJECT_ID_P_ACCESSOR, |
| FieldInfo.newRequired(ObjectIdPAccessor.NAME), |
| FieldInfo.newRequired(ObjectIdPAccessor.SOURCE)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| // Must have non-negative source code. |
| ObjectIdP oid = (ObjectIdP) message; |
| if (oid.getSource() < 0) { |
| logger.info("Source was negative: %s", oid); |
| return false; |
| } |
| return true; |
| } |
| }; |
| |
| /** Validation for invalidations. */ |
| final MessageInfo INVALIDATION = new MessageInfo( |
| ClientProtocolAccessor.INVALIDATION_P_ACCESSOR, |
| FieldInfo.newRequired(InvalidationPAccessor.OBJECT_ID, OID), |
| FieldInfo.newRequired(InvalidationPAccessor.IS_KNOWN_VERSION), |
| FieldInfo.newRequired(InvalidationPAccessor.VERSION), |
| FieldInfo.newOptional(InvalidationPAccessor.PAYLOAD), |
| FieldInfo.newOptional(InvalidationPAccessor.IS_TRICKLE_RESTART), |
| FieldInfo.newOptional(InvalidationPAccessor.BRIDGE_ARRIVAL_TIME_MS_DEPRECATED)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| // Must have non-negative version. |
| InvalidationP invalidation = (InvalidationP) message; |
| if (invalidation.getVersion() < 0) { |
| logger.info("Version was negative: %s", invalidation); |
| return false; |
| } |
| boolean isUnknownVersion = !invalidation.getIsKnownVersion(); |
| // Note that a missing value for is_trickle_restart is treated like a true value, |
| // becomes it comes from a downlevel client that uses invalidation semantics. |
| boolean isTrickleRestart = !invalidation.hasIsTrickleRestart() || |
| invalidation.getIsTrickleRestart(); |
| if (isUnknownVersion && !isTrickleRestart) { |
| logger.info( |
| "if is_known_version is false, is_trickle_restart must be true or missing: %s", |
| invalidation); |
| return false; |
| } |
| return true; |
| } |
| }; |
| |
| /** Validation for a message containing many invalidations. */ |
| final MessageInfo INVALIDATION_MSG; |
| |
| /** Validation for a single registration description. */ |
| final MessageInfo REGISTRATIONP = new MessageInfo( |
| ClientProtocolAccessor.REGISTRATION_P_ACCESSOR, |
| FieldInfo.newRequired(RegistrationPAccessor.OBJECT_ID, OID), |
| FieldInfo.newRequired(RegistrationPAccessor.OP_TYPE)); |
| |
| /** Validation for a summary of registration state. */ |
| final MessageInfo REGISTRATION_SUMMARY = new MessageInfo( |
| ClientProtocolAccessor.REGISTRATION_SUMMARY_ACCESSOR, |
| FieldInfo.newRequired(RegistrationSummaryAccessor.NUM_REGISTRATIONS), |
| FieldInfo.newRequired(RegistrationSummaryAccessor.REGISTRATION_DIGEST)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| RegistrationSummary summary = (RegistrationSummary) message; |
| return (summary.getNumRegistrations() >= 0) |
| && (!summary.getRegistrationDigest().isEmpty()); |
| } |
| }; |
| |
| final MessageInfo RATE_LIMIT = new MessageInfo( |
| ClientProtocolAccessor.RATE_LIMIT_P_ACCESSOR, |
| FieldInfo.newRequired(RateLimitPAccessor.WINDOW_MS), |
| FieldInfo.newRequired(RateLimitPAccessor.COUNT)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| RateLimitP rateLimit = (RateLimitP) message; |
| return (rateLimit.getWindowMs() >= 1000) && |
| (rateLimit.getWindowMs() > rateLimit.getCount()); |
| } |
| }; |
| |
| final MessageInfo PROTOCOL_HANDLER_CONFIG = new MessageInfo( |
| ClientProtocolAccessor.PROTOCOL_HANDLER_CONFIG_P_ACCESSOR, |
| FieldInfo.newOptional(ProtocolHandlerConfigPAccessor.BATCHING_DELAY_MS), |
| FieldInfo.newOptional(ProtocolHandlerConfigPAccessor.RATE_LIMIT, RATE_LIMIT) |
| ); |
| |
| // Validation for Client Config. */ |
| final MessageInfo CLIENT_CONFIG = new MessageInfo( |
| ClientProtocolAccessor.CLIENT_CONFIG_P_ACCESSOR, |
| FieldInfo.newRequired(ClientConfigPAccessor.VERSION, VERSION), |
| FieldInfo.newOptional(ClientConfigPAccessor.NETWORK_TIMEOUT_DELAY_MS), |
| FieldInfo.newOptional(ClientConfigPAccessor.WRITE_RETRY_DELAY_MS), |
| FieldInfo.newOptional(ClientConfigPAccessor.HEARTBEAT_INTERVAL_MS), |
| FieldInfo.newOptional(ClientConfigPAccessor.PERF_COUNTER_DELAY_MS), |
| FieldInfo.newOptional(ClientConfigPAccessor.MAX_EXPONENTIAL_BACKOFF_FACTOR), |
| FieldInfo.newOptional(ClientConfigPAccessor.SMEAR_PERCENT), |
| FieldInfo.newOptional(ClientConfigPAccessor.IS_TRANSIENT), |
| FieldInfo.newOptional(ClientConfigPAccessor.INITIAL_PERSISTENT_HEARTBEAT_DELAY_MS), |
| FieldInfo.newOptional(ClientConfigPAccessor.CHANNEL_SUPPORTS_OFFLINE_DELIVERY), |
| FieldInfo.newRequired(ClientConfigPAccessor.PROTOCOL_HANDLER_CONFIG, |
| PROTOCOL_HANDLER_CONFIG), |
| FieldInfo.newOptional(ClientConfigPAccessor.OFFLINE_HEARTBEAT_THRESHOLD_MS), |
| FieldInfo.newOptional(ClientConfigPAccessor.ALLOW_SUPPRESSION) |
| ); |
| |
| private CommonMsgInfos() { |
| // Initialize in constructor since other instance fields are referenced |
| INVALIDATION_MSG = new MessageInfo( |
| ClientProtocolAccessor.INVALIDATION_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(InvalidationMessageAccessor.INVALIDATION, |
| this.INVALIDATION)); |
| } |
| } |
| |
| /** Describes how to validate client messages. */ |
| private class ClientMsgInfos { |
| /** Validation for client headers. */ |
| final MessageInfo HEADER = new MessageInfo( |
| ClientProtocolAccessor.CLIENT_HEADER_ACCESSOR, |
| FieldInfo.newRequired(ClientHeaderAccessor.PROTOCOL_VERSION, |
| commonMsgInfos.PROTOCOL_VERSION), |
| FieldInfo.newOptional(ClientHeaderAccessor.CLIENT_TOKEN), |
| FieldInfo.newOptional(ClientHeaderAccessor.REGISTRATION_SUMMARY, |
| commonMsgInfos.REGISTRATION_SUMMARY), |
| FieldInfo.newRequired(ClientHeaderAccessor.CLIENT_TIME_MS), |
| FieldInfo.newRequired(ClientHeaderAccessor.MAX_KNOWN_SERVER_TIME_MS), |
| FieldInfo.newOptional(ClientHeaderAccessor.MESSAGE_ID), |
| FieldInfo.newOptional(ClientHeaderAccessor.CLIENT_TYPE)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| ClientHeader header = (ClientHeader) message; |
| |
| // If set, token must not be empty. |
| if (header.hasClientToken() && header.getClientToken().isEmpty()) { |
| logger.info("Client token was set but empty: %s", header); |
| return false; |
| } |
| |
| // If set, message id must not be empty. |
| // Do not use String.isEmpty() here for Froyo (JDK5) compatibility. |
| if (header.hasMessageId() && (header.getMessageId().length() == 0)) { |
| logger.info("Message id was set but empty: %s", header); |
| return false; |
| } |
| |
| if (header.getClientTimeMs() < 0) { |
| logger.info("Client time was negative: %s", header); |
| return false; |
| } |
| |
| if (header.getMaxKnownServerTimeMs() < 0) { |
| logger.info("Max known server time was negative: %s", header); |
| return false; |
| } |
| return true; |
| } |
| }; |
| |
| /** Validation for application client ids. */ |
| final MessageInfo APPLICATION_CLIENT_ID = new MessageInfo( |
| // Client type is optional here since the registrar needs to accept messages from |
| // the ticls that do not set the client type. |
| ClientProtocolAccessor.APPLICATION_CLIENT_ID_P_ACCESSOR, |
| FieldInfo.newOptional(ApplicationClientIdPAccessor.CLIENT_TYPE), |
| FieldInfo.newRequired(ApplicationClientIdPAccessor.CLIENT_NAME)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| ApplicationClientIdP applicationClientId = (ApplicationClientIdP) message; |
| return !applicationClientId.getClientName().isEmpty(); |
| } |
| }; |
| |
| /** Validation for client initialization messages. */ |
| final MessageInfo INITIALIZE_MESSAGE = new MessageInfo( |
| ClientProtocolAccessor.INITIALIZE_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(InitializeMessageAccessor.CLIENT_TYPE), |
| FieldInfo.newRequired(InitializeMessageAccessor.NONCE), |
| FieldInfo.newRequired(InitializeMessageAccessor.DIGEST_SERIALIZATION_TYPE), |
| FieldInfo.newRequired(InitializeMessageAccessor.APPLICATION_CLIENT_ID, |
| APPLICATION_CLIENT_ID)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| return ((InitializeMessage) message).getClientType() >= 0; |
| } |
| }; |
| |
| /** Validation for registration requests. */ |
| final MessageInfo REGISTRATION = new MessageInfo( |
| ClientProtocolAccessor.REGISTRATION_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(RegistrationMessageAccessor.REGISTRATION, |
| commonMsgInfos.REGISTRATIONP)); |
| |
| /** Validation for client versions. */ |
| final MessageInfo CLIENT_VERSION = new MessageInfo( |
| ClientProtocolAccessor.CLIENT_VERSION_ACCESSOR, |
| FieldInfo.newRequired(ClientVersionAccessor.VERSION, commonMsgInfos.VERSION), |
| FieldInfo.newRequired(ClientVersionAccessor.PLATFORM), |
| FieldInfo.newRequired(ClientVersionAccessor.LANGUAGE), |
| FieldInfo.newRequired(ClientVersionAccessor.APPLICATION_INFO)); |
| |
| /** Validation for client information messages. */ |
| final MessageInfo INFO = new MessageInfo( |
| ClientProtocolAccessor.INFO_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(InfoMessageAccessor.CLIENT_VERSION, CLIENT_VERSION), |
| FieldInfo.newOptional(InfoMessageAccessor.CONFIG_PARAMETER), |
| FieldInfo.newOptional(InfoMessageAccessor.PERFORMANCE_COUNTER), |
| FieldInfo.newOptional(InfoMessageAccessor.CLIENT_CONFIG, commonMsgInfos.CLIENT_CONFIG), |
| FieldInfo.newOptional(InfoMessageAccessor.SERVER_REGISTRATION_SUMMARY_REQUESTED)); |
| |
| /** Validation for registration subtrees. */ |
| final MessageInfo SUBTREE = new MessageInfo( |
| ClientProtocolAccessor.REGISTRATION_SUBTREE_ACCESSOR, |
| FieldInfo.newOptional(RegistrationSubtreeAccessor.REGISTERED_OBJECT)); |
| |
| /** Validation for registration sync messages. */ |
| final MessageInfo REGISTRATION_SYNC = new MessageInfo( |
| ClientProtocolAccessor.REGISTRATION_SYNC_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(RegistrationSyncMessageAccessor.SUBTREE, SUBTREE)); |
| |
| /** Validation for a ClientToServerMessage. */ |
| final MessageInfo CLIENT_MSG = new MessageInfo( |
| ClientProtocolAccessor.CLIENT_TO_SERVER_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(ClientToServerMessageAccessor.HEADER, HEADER), |
| FieldInfo.newOptional(ClientToServerMessageAccessor.INFO_MESSAGE, INFO), |
| FieldInfo.newOptional(ClientToServerMessageAccessor.INITIALIZE_MESSAGE, INITIALIZE_MESSAGE), |
| FieldInfo.newOptional(ClientToServerMessageAccessor.INVALIDATION_ACK_MESSAGE, |
| commonMsgInfos.INVALIDATION_MSG), |
| FieldInfo.newOptional(ClientToServerMessageAccessor.REGISTRATION_MESSAGE, REGISTRATION), |
| FieldInfo.newOptional(ClientToServerMessageAccessor.REGISTRATION_SYNC_MESSAGE, |
| REGISTRATION_SYNC)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| ClientToServerMessage parsedMessage = (ClientToServerMessage) message; |
| // The message either has an initialize request from the client or it has the client token. |
| return (parsedMessage.hasInitializeMessage() ^ parsedMessage.getHeader().hasClientToken()); |
| } |
| }; |
| } |
| |
| /** Describes how to validate server messages. */ |
| |
| class ServerMsgInfos { |
| /** Validation for server headers. */ |
| final MessageInfo HEADER = new MessageInfo( |
| ClientProtocolAccessor.SERVER_HEADER_ACCESSOR, |
| FieldInfo.newRequired(ServerHeaderAccessor.PROTOCOL_VERSION, |
| commonMsgInfos.PROTOCOL_VERSION), |
| FieldInfo.newRequired(ServerHeaderAccessor.CLIENT_TOKEN), |
| FieldInfo.newOptional(ServerHeaderAccessor.REGISTRATION_SUMMARY, |
| commonMsgInfos.REGISTRATION_SUMMARY), |
| FieldInfo.newRequired(ServerHeaderAccessor.SERVER_TIME_MS), |
| FieldInfo.newOptional(ServerHeaderAccessor.MESSAGE_ID)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| ServerHeader header = (ServerHeader) message; |
| if (header.getClientToken().isEmpty()) { |
| logger.info("Client token was empty: %s", header); |
| return false; |
| } |
| if (header.getServerTimeMs() < 0) { |
| logger.info("Server time was negative: %s", header); |
| return false; |
| } |
| // If set, message id must not be empty. |
| // Do not use String.isEmpty() here for Froyo (JDK5) compatibility. |
| if (header.hasMessageId() && (header.getMessageId().length() == 0)) { |
| logger.info("Message id was set but empty: %s", header); |
| return false; |
| } |
| return true; |
| } |
| }; |
| |
| /** Validation for server response codes. */ |
| final MessageInfo STATUSP = new MessageInfo( |
| ClientProtocolAccessor.STATUS_P_ACCESSOR, |
| FieldInfo.newRequired(StatusPAccessor.CODE), |
| FieldInfo.newOptional(StatusPAccessor.DESCRIPTION)); |
| |
| /** Validation for token control messages. */ |
| final MessageInfo TOKEN_CONTROL = new MessageInfo( |
| ClientProtocolAccessor.TOKEN_CONTROL_MESSAGE_ACCESSOR, |
| FieldInfo.newOptional(TokenControlMessageAccessor.NEW_TOKEN)); |
| |
| /** Validation for error messages. */ |
| final MessageInfo ERROR = new MessageInfo( |
| ClientProtocolAccessor.ERROR_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(ErrorMessageAccessor.CODE), |
| FieldInfo.newRequired(ErrorMessageAccessor.DESCRIPTION)); |
| |
| /** Validation for registration results. */ |
| final MessageInfo REGISTRATION_RESULT = new MessageInfo( |
| ClientProtocolAccessor.REGISTRATION_STATUS_ACCESSOR, |
| FieldInfo.newRequired(RegistrationStatusAccessor.REGISTRATION, |
| commonMsgInfos.REGISTRATIONP), |
| FieldInfo.newRequired(RegistrationStatusAccessor.STATUS, STATUSP)); |
| |
| /** Validation for registration status messages. */ |
| final MessageInfo REGISTRATION_STATUS_MSG = new MessageInfo( |
| ClientProtocolAccessor.REGISTRATION_STATUS_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(RegistrationStatusMessageAccessor.REGISTRATION_STATUS, |
| REGISTRATION_RESULT)); |
| |
| /** Validation for registration sync requests. */ |
| final MessageInfo REGISTRATION_SYNC_REQUEST = new MessageInfo( |
| ClientProtocolAccessor.REGISTRATION_SYNC_REQUEST_MESSAGE_ACCESSOR); |
| |
| /** Validation for info requests. */ |
| final MessageInfo INFO_REQUEST = new MessageInfo( |
| ClientProtocolAccessor.INFO_REQUEST_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(InfoRequestMessageAccessor.INFO_TYPE)); |
| |
| /** Validation for config change message. */ |
| final MessageInfo CONFIG_CHANGE = new MessageInfo( |
| ClientProtocolAccessor.CONFIG_CHANGE_MESSAGE_ACCESSOR, |
| FieldInfo.newOptional(ConfigChangeMessageAccessor.NEXT_MESSAGE_DELAY_MS)) { |
| @Override |
| public boolean postValidate(MessageLite message) { |
| ConfigChangeMessage parsedMessage = (ConfigChangeMessage) message; |
| // If the message has a next_message_delay_ms value, it must be positive. |
| return !parsedMessage.hasNextMessageDelayMs() || |
| (parsedMessage.getNextMessageDelayMs() > 0); |
| } |
| }; |
| |
| /** Validation for the top-level server messages. */ |
| final MessageInfo SERVER_MSG = new MessageInfo( |
| ClientProtocolAccessor.SERVER_TO_CLIENT_MESSAGE_ACCESSOR, |
| FieldInfo.newRequired(ServerToClientMessageAccessor.HEADER, HEADER), |
| FieldInfo.newOptional(ServerToClientMessageAccessor.TOKEN_CONTROL_MESSAGE, TOKEN_CONTROL), |
| FieldInfo.newOptional(ServerToClientMessageAccessor.INVALIDATION_MESSAGE, |
| commonMsgInfos.INVALIDATION_MSG), |
| FieldInfo.newOptional(ServerToClientMessageAccessor.REGISTRATION_STATUS_MESSAGE, |
| REGISTRATION_STATUS_MSG), |
| FieldInfo.newOptional(ServerToClientMessageAccessor.REGISTRATION_SYNC_REQUEST_MESSAGE, |
| REGISTRATION_SYNC_REQUEST), |
| FieldInfo.newOptional(ServerToClientMessageAccessor.CONFIG_CHANGE_MESSAGE, CONFIG_CHANGE), |
| FieldInfo.newOptional(ServerToClientMessageAccessor.INFO_REQUEST_MESSAGE, INFO_REQUEST), |
| FieldInfo.newOptional(ServerToClientMessageAccessor.ERROR_MESSAGE, ERROR)); |
| } |
| |
| /** Common validation information */ |
| |
| final CommonMsgInfos commonMsgInfos = new CommonMsgInfos(); |
| |
| /** Client validation information */ |
| private final ClientMsgInfos clientMsgInfos = new ClientMsgInfos(); |
| |
| /** Server validation information */ |
| |
| final ServerMsgInfos serverMsgInfos = new ServerMsgInfos(); |
| |
| /** Returns whether {@code clientMessage} is valid. */ |
| public boolean isValid(ClientToServerMessage clientMessage) { |
| return checkMessage(clientMessage, clientMsgInfos.CLIENT_MSG); |
| } |
| |
| /** Returns whether {@code serverMessage} is valid. */ |
| public boolean isValid(ServerToClientMessage serverMessage) { |
| return checkMessage(serverMessage, serverMsgInfos.SERVER_MSG); |
| } |
| |
| /** Returns whether {@code invalidation} is valid. */ |
| public boolean isValid(InvalidationP invalidation) { |
| return checkMessage(invalidation, commonMsgInfos.INVALIDATION); |
| } |
| |
| /** Returns whether {@code version} is valid. */ |
| public boolean isValid(Version version) { |
| return checkMessage(version, commonMsgInfos.VERSION); |
| } |
| |
| /** Returns the {@code MessageInfo} for a {@link ServerToClientMessage}. */ |
| public MessageInfo getServerToClientMessageInfo() { |
| return serverMsgInfos.SERVER_MSG; |
| } |
| } |