/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.voltdb.probe;
import static com.google_voltpatches.common.base.Preconditions.checkArgument;
import java.util.List;
import java.util.UUID;
import javax.annotation.Generated;
import org.json_voltpatches.JSONException;
import org.json_voltpatches.JSONObject;
import org.voltdb.StartAction;
import org.voltdb.common.NodeState;
import com.google_voltpatches.common.base.Throwables;
import com.google_voltpatches.common.collect.ImmutableList;
/**
* It is a data transfer object (DTO) that snapshots a subset of {@link MeshProber}
* fields, and is passed around in initial mesh requests.
*/
public class HostCriteria {
public final static String IS_PAUSED = "paused";
public final static String CONFIG_HASH = "configHash";
public final static String MESH_HASH = "meshHash";
public final static String IS_BARE = "isBare";
public final static String START_ACTION = "startAction";
public final static String IS_ENTERPRISE = "isEnterprise";
public final static String HOST_COUNT = "hostCount";
public final static String NODE_STATE = "nodeState";
public final static String ADD_ALLOWED = "addAllowed";
public final static String SAFE_MODE = "safeMode";
public final static String TERMINUS_NONCE = "terminusNonce";
public final static UUID UNDEFINED = new UUID(0L,0L);
/**
* It checks whether the given {@link JSONObject} contains the
* fields necessary to create an instance of {@link HostCriteria}.
* The get[type] variant of {@link JSONObject} throws a {@link JSONException}
* when it does not parse to the expected types
*/
public static boolean hasCriteria(JSONObject jo) {
try {
return jo != null
&& jo.has(IS_PAUSED) && (jo.getBoolean(IS_PAUSED) ? true : true)
&& jo.has(IS_BARE) && (jo.getBoolean(IS_BARE) ? true : true)
&& jo.has(IS_ENTERPRISE) && (jo.getBoolean(IS_ENTERPRISE) ? true : true)
&& jo.has(ADD_ALLOWED) && (jo.getBoolean(ADD_ALLOWED) ? true : true)
&& jo.has(SAFE_MODE) && (jo.getBoolean(SAFE_MODE) ? true : true)
&& jo.has(CONFIG_HASH) && jo.getString(CONFIG_HASH) != null && !jo.getString(CONFIG_HASH).trim().isEmpty()
&& jo.has(MESH_HASH) && jo.getString(MESH_HASH) != null && !jo.getString(MESH_HASH).trim().isEmpty()
&& jo.has(START_ACTION) && jo.getString(START_ACTION) != null && !jo.getString(START_ACTION).trim().isEmpty()
&& jo.has(NODE_STATE) && jo.getString(NODE_STATE) != null && !jo.getString(NODE_STATE).trim().isEmpty()
&& jo.has(HOST_COUNT) && jo.getInt(HOST_COUNT) > 0
&& (jo.optString(TERMINUS_NONCE, null) == null || !jo.optString(TERMINUS_NONCE).trim().isEmpty());
} catch (JSONException e) {
return false;
}
}
protected final boolean m_paused;
protected final UUID m_configHash;
/** coordinators and host count digest */
protected final UUID m_meshHash;
protected final boolean m_enterprise;
protected final StartAction m_startAction;
/**
* {@code true} if there are no recoverable artifacts (Command Logs, Snapshots)
*/
protected final boolean m_bare;
protected final int m_hostCount;
protected final NodeState m_nodeState;
protected final boolean m_addAllowed;
protected final boolean m_safeMode;
protected final String m_terminusNonce;
public HostCriteria(JSONObject jo) {
checkArgument(jo != null, "json object is null");
m_paused = jo.optBoolean(IS_PAUSED, false);
m_bare = jo.optBoolean(IS_BARE, false);
m_enterprise = jo.optBoolean(IS_ENTERPRISE, false);
m_configHash = UUID.fromString(jo.optString(CONFIG_HASH,UNDEFINED.toString()));
m_meshHash = UUID.fromString(jo.optString(MESH_HASH,UNDEFINED.toString()));
m_startAction = StartAction.valueOf(jo.optString(START_ACTION, StartAction.CREATE.name()));
m_hostCount = jo.optInt(HOST_COUNT,1);
m_nodeState = NodeState.valueOf(jo.optString(NODE_STATE, NodeState.INITIALIZING.name()));
m_addAllowed = jo.optBoolean(ADD_ALLOWED, false);
m_safeMode = jo.optBoolean(SAFE_MODE, false);
m_terminusNonce = jo.optString(TERMINUS_NONCE, null);
}
public HostCriteria(boolean paused, UUID configHash, UUID meshHash,
boolean enterprise, StartAction startAction, boolean bare,
int hostCount, NodeState nodeState, boolean addAllowed,
boolean safeMode, String terminusNonce) {
checkArgument(configHash != null, "config hash is null");
checkArgument(meshHash != null, "mesh hash is null");
checkArgument(startAction != null, "start action is null");
checkArgument(hostCount > 0, "host count %s is less then one", hostCount);
checkArgument(terminusNonce == null || !terminusNonce.trim().isEmpty(),
"terminus should not be blank");
m_paused = paused;
m_configHash = configHash;
m_meshHash = meshHash;
m_enterprise = enterprise;
m_startAction = startAction;
m_bare = bare;
m_hostCount = hostCount;
m_nodeState = nodeState;
m_addAllowed = addAllowed;
m_safeMode = safeMode;
m_terminusNonce = terminusNonce;
}
public boolean isPaused() {
return m_paused;
}
public UUID getConfigHash() {
return m_configHash;
}
public UUID getMeshHash() {
return m_meshHash;
}
public boolean isEnterprise() {
return m_enterprise;
}
public StartAction getStartAction() {
return m_startAction;
}
/**
* @return {@code true} if there are no recoverable artifacts (Command Logs, Snapshots)
*/
public boolean isBare() {
return m_bare;
}
public int getHostCount() {
return m_hostCount;
}
public NodeState getNodeState() {
return m_nodeState;
}
public boolean isAddAllowed() {
return m_addAllowed;
}
public boolean isSafeMode() {
return m_safeMode;
}
public String getTerminusNonce() {
return m_terminusNonce;
}
public JSONObject appendTo(JSONObject jo) {
checkArgument(jo != null, "json object is null");
try {
jo.put(IS_BARE, m_bare);
jo.put(IS_ENTERPRISE, m_enterprise);
jo.put(IS_PAUSED, m_paused);
jo.put(CONFIG_HASH, m_configHash.toString());
jo.put(MESH_HASH, m_meshHash.toString());
jo.put(START_ACTION, m_startAction.name());
jo.put(HOST_COUNT, m_hostCount);
jo.put(NODE_STATE, m_nodeState.name());
jo.put(ADD_ALLOWED, m_addAllowed);
jo.put(SAFE_MODE, m_safeMode);
jo.put(TERMINUS_NONCE, m_terminusNonce);
} catch (JSONException e) {
Throwables.propagate(e);
}
return jo;
}
public boolean isUndefined() {
return UNDEFINED.equals(m_configHash) && UNDEFINED.equals(m_meshHash);
}
public List<String> listIncompatibilities(HostCriteria o) {
checkArgument(o != null, "cant check compatibility against a null host criteria");
ImmutableList.Builder<String> ilb = ImmutableList.builder();
if (o.isUndefined()) {
ilb.add("Joining node has incompatible version");
return ilb.build();
}
if (m_startAction != o.m_startAction) {
ilb.add(String.format("Start action %s does not match %s", o.m_startAction, m_startAction));
}
if (m_startAction != StartAction.PROBE) {
return ilb.build();
}
if (m_enterprise != o.m_enterprise) {
ilb.add("Cluster cannot contain both enterprise and community editions");
}
if (m_hostCount != o.m_hostCount) {
ilb.add(String.format("Mismatched host count: %d, and %d", m_hostCount, o.m_hostCount));
}
if (!m_meshHash.equals(o.m_meshHash)) {
ilb.add("Mismatched list of hosts given at database startup");
}
if (!m_configHash.equals(o.m_configHash)) {
ilb.add("Servers are initialized with deployment options that do not match");
}
if ( m_terminusNonce != null
&& o.m_terminusNonce != null
&& !m_terminusNonce.equals(o.m_terminusNonce))
{
ilb.add("Servers have different startup snapshots nonces: "
+ m_terminusNonce + " vs. " + o.m_terminusNonce);
}
return ilb.build();
}
@Override @Generated("by eclipse's equals and hashCode source generators")
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (m_bare ? 1231 : 1237);
result = prime * result
+ ((m_configHash == null) ? 0 : m_configHash.hashCode());
result = prime * result + (m_enterprise ? 1231 : 1237);
result = prime * result + (m_addAllowed ? 1231 : 1237);
result = prime * result + (m_safeMode ? 1231 : 1237);
result = prime * result + m_hostCount;
result = prime * result
+ ((m_meshHash == null) ? 0 : m_meshHash.hashCode());
result = prime * result
+ ((m_terminusNonce == null) ? 0 : m_terminusNonce.hashCode());
result = prime * result + (m_paused ? 1231 : 1237);
result = prime * result
+ ((m_startAction == null) ? 0 : m_startAction.hashCode());
result = prime * result
+ ((m_nodeState == null) ? 0 : m_nodeState.hashCode());
return result;
}
@Override @Generated("by eclipse's equals and hashCode source generators")
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
HostCriteria other = (HostCriteria) obj;
if (m_bare != other.m_bare)
return false;
if (m_configHash == null) {
if (other.m_configHash != null)
return false;
} else if (!m_configHash.equals(other.m_configHash))
return false;
if (m_enterprise != other.m_enterprise)
return false;
if (m_addAllowed != other.m_addAllowed)
return false;
if (m_safeMode != other.m_safeMode)
return false;
if (m_hostCount != other.m_hostCount)
return false;
if (m_meshHash == null) {
if (other.m_meshHash != null)
return false;
} else if (!m_meshHash.equals(other.m_meshHash))
return false;
if (m_terminusNonce == null) {
if (other.m_terminusNonce != null)
return false;
} else if (!m_terminusNonce.equals(other.m_terminusNonce))
return false;
if (m_paused != other.m_paused)
return false;
if (m_startAction != other.m_startAction)
return false;
if (m_nodeState != other.m_nodeState)
return false;
return true;
}
@Override
public String toString() {
return "HostCriteria [paused=" + m_paused + ", configHash=" + m_configHash
+ ", meshHash=" + m_meshHash + ", enterprise=" + m_enterprise
+ ", startAction=" + m_startAction + ", bare=" + m_bare
+ ", hostCount=" + m_hostCount + ", nodeState=" + m_nodeState
+ ", addAllowed=" + m_addAllowed + ", safeMode=" + m_safeMode
+ ", terminusNonce=" + m_terminusNonce + "]";
}
}