/**
* Licensed to JumpMind Inc under one or more contributor
* license agreements. See the NOTICE file distributed
* with this work for additional information regarding
* copyright ownership. JumpMind Inc licenses this file
* to you under the GNU General Public License, version 3.0 (GPLv3)
* (the "License"); you may not use this file except in compliance
* with the License.
*
* You should have received a copy of the GNU General Public License,
* version 3.0 (GPLv3) along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*
* 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.jumpmind.symmetric.service.impl;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.UnknownHostException;
import java.sql.Types;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.jumpmind.db.sql.ISqlRowMapper;
import org.jumpmind.db.sql.ISqlTransaction;
import org.jumpmind.db.sql.Row;
import org.jumpmind.db.sql.mapper.StringMapper;
import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.common.Constants;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.config.INodeIdCreator;
import org.jumpmind.symmetric.model.Node;
import org.jumpmind.symmetric.model.NodeGroupLink;
import org.jumpmind.symmetric.model.NodeSecurity;
import org.jumpmind.symmetric.model.RegistrationRequest;
import org.jumpmind.symmetric.model.RegistrationRequest.RegistrationStatus;
import org.jumpmind.symmetric.model.RemoteNodeStatus.Status;
import org.jumpmind.symmetric.security.INodePasswordFilter;
import org.jumpmind.symmetric.service.IConfigurationService;
import org.jumpmind.symmetric.service.IDataExtractorService;
import org.jumpmind.symmetric.service.IDataLoaderService;
import org.jumpmind.symmetric.service.IDataService;
import org.jumpmind.symmetric.service.IExtensionService;
import org.jumpmind.symmetric.service.INodeService;
import org.jumpmind.symmetric.service.IOutgoingBatchService;
import org.jumpmind.symmetric.service.IRegistrationService;
import org.jumpmind.symmetric.service.RegistrationFailedException;
import org.jumpmind.symmetric.service.RegistrationNotOpenException;
import org.jumpmind.symmetric.service.RegistrationRedirectException;
import org.jumpmind.symmetric.statistic.IStatisticManager;
import org.jumpmind.symmetric.transport.ConnectionRejectedException;
import org.jumpmind.symmetric.transport.ITransportManager;
import org.jumpmind.util.AppUtils;
import org.jumpmind.util.RandomTimeSlot;
/**
* @see IRegistrationService
*/
public class RegistrationService extends AbstractService implements IRegistrationService {
private INodeService nodeService;
private IDataExtractorService dataExtractorService;
private IDataService dataService;
private IDataLoaderService dataLoaderService;
private ITransportManager transportManager;
private IOutgoingBatchService outgoingBatchService;
private RandomTimeSlot randomTimeSlot;
private IStatisticManager statisticManager;
private IConfigurationService configurationService;
private IExtensionService extensionService;
private ISymmetricEngine engine;
public RegistrationService(ISymmetricEngine engine) {
super(engine.getParameterService(), engine.getSymmetricDialect());
this.engine = engine;
this.nodeService = engine.getNodeService();
this.dataExtractorService = engine.getDataExtractorService();
this.dataService = engine.getDataService();
this.dataLoaderService = engine.getDataLoaderService();
this.transportManager = engine.getTransportManager();
this.statisticManager = engine.getStatisticManager();
this.configurationService = engine.getConfigurationService();
this.outgoingBatchService = engine.getOutgoingBatchService();
this.extensionService = engine.getExtensionService();
this.randomTimeSlot = new RandomTimeSlot(parameterService.getExternalId(), 30);
setSqlMap(new RegistrationServiceSqlMap(symmetricDialect.getPlatform(),
createSqlReplacementTokens()));
}
public Node registerPullOnlyNode(String externalId, String nodeGroupId,
String databaseType, String databaseVersion)
throws IOException {
Node node = new Node();
node.setExternalId(externalId);
node.setNodeGroupId(nodeGroupId);
node.setDatabaseType(databaseType);
node.setDatabaseVersion(databaseVersion);
node = processRegistration(node, null, null, true, Constants.DEPLOYMENT_TYPE_REST);
if (node.isSyncEnabled()) {
//set the node as registered as we have no
//virtual batch for registration to be ok'd
markNodeAsRegistered(node.getNodeId());
}
return node;
}
public boolean registerNode(Node preRegisteredNode, OutputStream out, boolean isRequestedRegistration)
throws IOException {
return registerNode(preRegisteredNode, null, null, out, isRequestedRegistration);
}
protected void extractConfiguration(OutputStream out, Node registeredNode) {
dataExtractorService.extractConfigurationStandalone(registeredNode, out);
}
protected Node processRegistration(Node nodePriorToRegistration, String remoteHost,
String remoteAddress, boolean isRequestedRegistration, String deploymentType)
throws IOException {
Node processedNode = new Node();
processedNode.setSyncEnabled(false);
Node identity = nodeService.findIdentity();
if (identity == null) {
RegistrationRequest req = new RegistrationRequest(nodePriorToRegistration,
RegistrationStatus.ER, remoteHost, remoteAddress);
req.setErrorMessage("Cannot register a client node until this node is registered");
saveRegistrationRequest(req);
log.warn(req.getErrorMessage());
return processedNode;
}
try {
if (!nodeService.isRegistrationServer()) {
/*
* registration is not allowed until this node has an identity
* and an initial load
*/
NodeSecurity security = nodeService.findNodeSecurity(identity.getNodeId());
if (security == null || security.getInitialLoadTime() == null) {
RegistrationRequest req = new RegistrationRequest(nodePriorToRegistration,
RegistrationStatus.ER, remoteHost, remoteAddress);
req.setErrorMessage("Cannot register a client node until this node has an initial load (ie. node_security.initial_load_time is a non null value)");
saveRegistrationRequest(req);
log.warn(req.getErrorMessage());
return processedNode;
}
}
String redirectUrl = getRedirectionUrlFor(nodePriorToRegistration.getExternalId());
if (redirectUrl != null) {
log.info("Redirecting {} to {} for registration.",
nodePriorToRegistration.getExternalId(), redirectUrl);
saveRegistrationRequest(new RegistrationRequest(nodePriorToRegistration,
RegistrationStatus.RR, remoteHost, remoteAddress));
throw new RegistrationRedirectException(redirectUrl);
}
/*
* Check to see if there is a link that exists to service the node
* that is requesting registration
*/
NodeGroupLink link = configurationService.getNodeGroupLinkFor(
identity.getNodeGroupId(), nodePriorToRegistration.getNodeGroupId(), false);
if (link == null
&& parameterService.is(ParameterConstants.REGISTRATION_REQUIRE_NODE_GROUP_LINK,
true)) {
RegistrationRequest req = new RegistrationRequest(nodePriorToRegistration,
RegistrationStatus.ER, remoteHost, remoteAddress);
req.setErrorMessage(String.format("Cannot register a client node unless a node group link exists so the registering node can receive configuration updates. Please add a group link where the source group id is %s and the target group id is %s",
identity.getNodeGroupId(), nodePriorToRegistration.getNodeGroupId()));
saveRegistrationRequest(req);
log.warn(req.getErrorMessage());
return processedNode;
}
String nodeId = StringUtils.isBlank(nodePriorToRegistration.getNodeId()) ? extensionService.
getExtensionPoint(INodeIdCreator.class).selectNodeId(nodePriorToRegistration, remoteHost,
remoteAddress) : nodePriorToRegistration.getNodeId();
Node foundNode = nodeService.findNode(nodeId);
NodeSecurity security = nodeService.findNodeSecurity(nodeId);
if ((foundNode == null || security == null || !security.isRegistrationEnabled())
&& parameterService.is(ParameterConstants.AUTO_REGISTER_ENABLED)) {
openRegistration(nodePriorToRegistration, remoteHost, remoteAddress);
nodeId = StringUtils.isBlank(nodePriorToRegistration.getNodeId()) ? extensionService.
getExtensionPoint(INodeIdCreator.class).selectNodeId(nodePriorToRegistration, remoteHost,
remoteAddress) : nodePriorToRegistration.getNodeId();
security = nodeService.findNodeSecurity(nodeId);
foundNode = nodeService.findNode(nodeId);
} else if (foundNode == null || security == null
|| !security.isRegistrationEnabled()) {
saveRegistrationRequest(new RegistrationRequest(nodePriorToRegistration,
RegistrationStatus.RQ, remoteHost, remoteAddress));
return processedNode;
}
foundNode.setSyncEnabled(true);
if (Constants.DEPLOYMENT_TYPE_REST.equalsIgnoreCase(deploymentType)) {
foundNode.setSymmetricVersion(null);
foundNode.setDeploymentType(deploymentType);
}
foundNode.setSyncUrl(nodePriorToRegistration.getSyncUrl());
foundNode.setDatabaseType(nodePriorToRegistration.getDatabaseType());
foundNode.setDatabaseVersion(nodePriorToRegistration.getDatabaseVersion());
foundNode.setSymmetricVersion(nodePriorToRegistration.getSymmetricVersion());
nodeService.save(foundNode);
/**
* Only send automatic initial load once or if the client is really
* re-registering
*/
if ((security != null && security.getInitialLoadTime() == null)
|| isRequestedRegistration) {
if (parameterService.is(ParameterConstants.AUTO_RELOAD_ENABLED)) {
nodeService.setInitialLoadEnabled(nodeId, true, false, -1, "registration");
}
if (parameterService.is(ParameterConstants.AUTO_RELOAD_REVERSE_ENABLED)) {
nodeService.setReverseInitialLoadEnabled(nodeId, true, false, -1,
"registration");
}
}
saveRegistrationRequest(new RegistrationRequest(foundNode, RegistrationStatus.OK,
remoteHost, remoteAddress));
statisticManager.incrementNodesRegistered(1);
return foundNode;
} catch (RegistrationNotOpenException ex) {
if (StringUtils.isNotBlank(ex.getMessage())) {
log.warn("Registration not allowed for {} because {}",
nodePriorToRegistration.toString(), ex.getMessage());
}
return processedNode;
}
}
/**
* @see IRegistrationService#registerNode(Node, OutputStream, boolean)
*/
public boolean registerNode(Node nodePriorToRegistration, String remoteHost,
String remoteAddress, OutputStream out, boolean isRequestedRegistration)
throws IOException {
Node processedNode = processRegistration(nodePriorToRegistration, remoteHost,
remoteAddress, isRequestedRegistration, null);
if (processedNode.isSyncEnabled()) {
/*
* Mark all configuration batches as processed because we are about to reload
* the configuration for the node
*/
outgoingBatchService.markAllConfigAsSentForNode(processedNode.getNodeId());
extractConfiguration(out, processedNode);
}
return processedNode.isSyncEnabled();
}
public List<RegistrationRequest> getRegistrationRequests(
boolean includeNodesWithOpenRegistrations) {
List<RegistrationRequest> requests = sqlTemplate.query(
getSql("selectRegistrationRequestSql"), new RegistrationRequestMapper());
if (!includeNodesWithOpenRegistrations) {
Collection<Node> nodes = nodeService.findNodesWithOpenRegistration();
Iterator<RegistrationRequest> i = requests.iterator();
while (i.hasNext()) {
RegistrationRequest registrationRequest = (RegistrationRequest) i.next();
for (Node node : nodes) {
if (node.getNodeGroupId().equals(registrationRequest.getNodeGroupId())
&& node.getExternalId().equals(registrationRequest.getExternalId())) {
i.remove();
}
}
}
}
return requests;
}
public boolean deleteRegistrationRequest(RegistrationRequest request) {
String externalId = request.getExternalId() == null ? "" : request.getExternalId();
String nodeGroupId = request.getNodeGroupId() == null ? "" : request.getNodeGroupId();
return 0 < sqlTemplate.update(getSql("deleteRegistrationRequestSql"), new Object[] {
nodeGroupId, externalId, request.getIpAddress(), request.getHostName(),
request.getStatus().name() });
}
public void saveRegistrationRequest(RegistrationRequest request) {
/**
* Lookup existing registration requests to update the attempt count. We previously
* did this in SQL on the update, but as400 v5 didn't like that
*/
boolean foundOne = false;
List<RegistrationRequest> requests = getRegistrationRequests(true);
for (RegistrationRequest registrationRequest : requests) {
if (registrationRequest.getNodeGroupId().equals(request.getNodeGroupId()) && registrationRequest.getExternalId().equals(request.getExternalId())) {
request.setAttemptCount(registrationRequest.getAttemptCount()+1);
foundOne = true;
break;
}
}
String externalId = request.getExternalId() == null ? "" : request.getExternalId();
String nodeGroupId = request.getNodeGroupId() == null ? "" : request.getNodeGroupId();
int count = 0;
if (foundOne) {
count = sqlTemplate.update(
getSql("updateRegistrationRequestSql"),
new Object[] { request.getAttemptCount(), request.getLastUpdateBy(),
request.getLastUpdateTime(), request.getRegisteredNodeId(),
request.getStatus().name(), request.getErrorMessage(), nodeGroupId,
externalId, request.getIpAddress(), request.getHostName() }, new int[] {
Types.NUMERIC, Types.VARCHAR, Types.DATE, Types.VARCHAR, Types.VARCHAR,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.VARCHAR });
}
if (count == 0) {
sqlTemplate.update(
getSql("insertRegistrationRequestSql"),
new Object[] { request.getLastUpdateBy(), request.getLastUpdateTime(),
request.getRegisteredNodeId(), request.getStatus().name(), nodeGroupId,
externalId, request.getIpAddress(), request.getHostName(),
request.getErrorMessage() }, new int[] { Types.VARCHAR, Types.DATE,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR });
}
}
public String getRedirectionUrlFor(String externalId) {
List<String> list = sqlTemplate.query(getSql("getRegistrationRedirectUrlSql"),
new StringMapper(), new Object[] { externalId }, new int[] { Types.VARCHAR });
if (list.size() > 0) {
return transportManager.resolveURL(list.get(0), parameterService.getRegistrationUrl());
} else {
return null;
}
}
public void saveRegistrationRedirect(String externalIdToRedirect, String nodeIdToRedirectTo) {
int count = sqlTemplate.update(getSql("updateRegistrationRedirectUrlSql"), new Object[] {
nodeIdToRedirectTo, externalIdToRedirect }, new int[] { Types.VARCHAR,
Types.VARCHAR });
if (count == 0) {
sqlTemplate.update(getSql("insertRegistrationRedirectUrlSql"), new Object[] {
nodeIdToRedirectTo, externalIdToRedirect }, new int[] { Types.VARCHAR,
Types.VARCHAR });
}
}
/**
* @see IRegistrationService#markNodeAsRegistered(Node)
*/
public void markNodeAsRegistered(String nodeId) {
ISqlTransaction transaction = null;
try {
transaction = sqlTemplate.startSqlTransaction();
symmetricDialect.disableSyncTriggers(transaction, nodeId);
transaction.prepareAndExecute(getSql("registerNodeSecuritySql"), nodeId);
transaction.commit();
} catch (Error ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} catch (RuntimeException ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} finally {
symmetricDialect.enableSyncTriggers(transaction);
close(transaction);
}
}
private void sleepBeforeRegistrationRetry() {
long sleepTimeInMs = DateUtils.MILLIS_PER_SECOND
* randomTimeSlot.getRandomValueSeededByExternalId();
log.info("Could not register. Sleeping before attempting again.", sleepTimeInMs);
log.info("Sleeping for {}ms", sleepTimeInMs);
AppUtils.sleep(sleepTimeInMs);
}
public boolean isRegisteredWithServer() {
return nodeService.findIdentity() != null;
}
/**
* @see IRegistrationService#registerWithServer()
*/
public void registerWithServer() {
boolean registered = isRegisteredWithServer();
int maxNumberOfAttempts = parameterService
.getInt(ParameterConstants.REGISTRATION_NUMBER_OF_ATTEMPTS);
while (!registered && (maxNumberOfAttempts < 0 || maxNumberOfAttempts > 0) && engine.isStarted()) {
try {
log.info("This node is unregistered. It will attempt to register using the registration.url");
registered = dataLoaderService.loadDataFromPull(null).getStatus() == Status.DATA_PROCESSED;
} catch (ConnectException e) {
log.warn("The request to register failed because the client failed to connect to the server");
} catch (UnknownHostException e) {
log.warn("The request to register failed because the host was unknown");
} catch (ConnectionRejectedException ex) {
log.warn("The request to register was rejected by the server. Either the server node is not started, the server is not configured properly or the registration url is incorrect");
} catch (Exception e) {
log.error("", e);
}
maxNumberOfAttempts--;
if (!registered && (maxNumberOfAttempts < 0 || maxNumberOfAttempts > 0)) {
registered = isRegisteredWithServer();
if (registered) {
log.info("We registered, but were not able to acknowledge our registration. Sending a sql event to the node where we registered to indicate that we are alive and registered");
Node identity = nodeService.findIdentity();
Node parentNode = nodeService.findNode(identity.getCreatedAtNodeId());
dataService
.insertSqlEvent(
parentNode,
"update "
+ tablePrefix
+ "_node_security set registration_enabled=1, registration_time=current_timestamp where node_id='"
+ identity.getNodeId() + "'", false, -1, null);
}
}
if (registered) {
Node node = nodeService.findIdentity();
if (node != null) {
log.info("Successfully registered node [id={}]", node.getNodeId());
dataService.heartbeat(true);
} else {
log.error("Node identity is missing after registration. The registration server may be misconfigured or have an error");
registered = false;
}
}
if (!registered && maxNumberOfAttempts != 0) {
sleepBeforeRegistrationRetry();
}
}
if (!registered) {
throw new RegistrationFailedException(String.format(
"Failed after trying to register %s times.",
parameterService.getString(ParameterConstants.REGISTRATION_NUMBER_OF_ATTEMPTS)));
}
}
/**
* @see IRegistrationService#reOpenRegistration(String)
*/
public synchronized void reOpenRegistration(String nodeId) {
Node node = nodeService.findNode(nodeId);
NodeSecurity security = nodeService.findNodeSecurity(nodeId);
String password = null;
if (security != null && parameterService.is(ParameterConstants.REGISTRATION_REOPEN_USE_SAME_PASSWORD, true)) {
password = security.getNodePassword();
} else {
password = extensionService.getExtensionPoint(INodeIdCreator.class).generatePassword(node);
password = filterPasswordOnSaveIfNeeded(password);
}
if (node != null) {
int updateCount = sqlTemplate.update(getSql("reopenRegistrationSql"), new Object[] {
password, nodeId });
if (updateCount == 0 && nodeService.findNodeSecurity(nodeId) == null) {
// if the update count was 0, then we probably have a row in the
// node table, but not in node security.
// lets go ahead and try to insert into node security.
sqlTemplate.update(getSql("openRegistrationNodeSecuritySql"), new Object[] {
nodeId, password, nodeService.findNode(nodeId).getNodeId() });
log.info("Registration was opened for {}", nodeId);
} else if (updateCount == 0) {
log.warn("Registration was already enabled for {}. No need to reenable it", nodeId);
} else {
log.info("Registration was reopened for {}", nodeId);
}
} else {
log.warn("There was no row with a node id of {} to 'reopen' registration for", nodeId);
}
}
/**
* @see IRegistrationService#openRegistration(String, String)
* @return The nodeId of the registered node
*/
public synchronized String openRegistration(String nodeGroup, String externalId) {
Node node = new Node();
node.setExternalId(externalId);
node.setNodeGroupId(nodeGroup);
return openRegistration(node);
}
public synchronized String openRegistration(String nodeGroup, String externalId, String remoteHost, String remoteAddress) {
Node node = new Node();
node.setExternalId(externalId);
node.setNodeGroupId(nodeGroup);
return openRegistration(node, remoteHost, remoteAddress);
}
public synchronized String openRegistration(Node node) {
return openRegistration(node, null, null);
}
protected String openRegistration(Node node, String remoteHost, String remoteAddress) {
Node me = nodeService.findIdentity();
if (me != null) {
String nodeId = extensionService.getExtensionPoint(INodeIdCreator.class).generateNodeId(node, remoteHost, remoteAddress);
Node existingNode = nodeService.findNode(nodeId);
if (existingNode == null) {
node.setNodeId(nodeId);
node.setSyncEnabled(false);
boolean masterToMaster = configurationService.isMasterToMaster();
node.setCreatedAtNodeId(masterToMaster ? null: me.getNodeId());
nodeService.save(node);
// make sure there isn't a node security row lying around w/out
// a node row
nodeService.deleteNodeSecurity(nodeId);
String password = extensionService.getExtensionPoint(INodeIdCreator.class).generatePassword(node);
password = filterPasswordOnSaveIfNeeded(password);
sqlTemplate.update(getSql("openRegistrationNodeSecuritySql"), new Object[] {
nodeId, password, masterToMaster ? null : me.getNodeId() });
nodeService.insertNodeGroup(node.getNodeGroupId(), null);
log.info(
"Just opened registration for external id of {} and a node group of {} and a node id of {}",
new Object[] { node.getExternalId(), node.getNodeGroupId(), nodeId });
} else {
reOpenRegistration(nodeId);
}
return nodeId;
} else {
throw new IllegalStateException(
"This node has not been configured. Could not find a row in the identity table");
}
}
public boolean isAutoRegistration() {
return parameterService.is(ParameterConstants.AUTO_REGISTER_ENABLED);
}
private String filterPasswordOnSaveIfNeeded(String password) {
String s = password;
INodePasswordFilter nodePasswordFilter = extensionService.getExtensionPoint(INodePasswordFilter.class);
if (nodePasswordFilter != null) {
s = nodePasswordFilter.onNodeSecuritySave(password);
}
return s;
}
public boolean isRegistrationOpen(String nodeGroupId, String externalId) {
Node node = nodeService.findNodeByExternalId(nodeGroupId, externalId);
if (node != null) {
NodeSecurity security = nodeService.findNodeSecurity(node.getNodeId());
return security != null && security.isRegistrationEnabled();
}
return false;
}
public void requestNodeCopy() {
Node copyFrom = nodeService.findIdentity();
if (copyFrom == null) {
throw new IllegalStateException("No identity found. Can only copy if the node has an identity");
}
boolean copied = false;
int maxNumberOfAttempts = parameterService
.getInt(ParameterConstants.REGISTRATION_NUMBER_OF_ATTEMPTS);
while (!copied && (maxNumberOfAttempts < 0 || maxNumberOfAttempts > 0)) {
try {
log.info("Detected that node '{}' should be copied to a new node id. Attempting to contact server to accomplish this", copyFrom.getNodeId());
copied = transportManager.sendCopyRequest(copyFrom) == HttpURLConnection.HTTP_OK;
if (copied) {
nodeService.deleteIdentity();
}
} catch (ConnectException e) {
log.warn("The request to copy failed because the client failed to connect to the server");
} catch (UnknownHostException e) {
log.warn("The request to copy failed because the host was unknown");
} catch (ConnectionRejectedException ex) {
log.warn("The request to copy was rejected by the server. Either the server node is not started, the server is not configured properly or the registration url is incorrect");
} catch (Exception e) {
log.error("", e);
}
maxNumberOfAttempts--;
if (!copied) {
long sleepTimeInMs = DateUtils.MILLIS_PER_SECOND
* randomTimeSlot.getRandomValueSeededByExternalId();
log.warn("Copy failed. Sleeping before attempting again.", sleepTimeInMs);
log.info("Sleeping for {}ms", sleepTimeInMs);
AppUtils.sleep(sleepTimeInMs);
}
}
if (!copied) {
throw new RegistrationFailedException(String.format(
"Failed after trying to copy %s times.",
parameterService.getString(ParameterConstants.REGISTRATION_NUMBER_OF_ATTEMPTS)));
}
}
class RegistrationRequestMapper implements ISqlRowMapper<RegistrationRequest> {
public RegistrationRequest mapRow(Row rs) {
RegistrationRequest request = new RegistrationRequest();
request.setNodeGroupId(rs.getString("node_group_id"));
request.setExternalId(rs.getString("external_id"));
request.setStatus(RegistrationStatus.valueOf(RegistrationStatus.class,
rs.getString("status")));
request.setHostName(rs.getString("host_name"));
request.setIpAddress(rs.getString("ip_address"));
request.setAttemptCount(rs.getLong("attempt_count"));
request.setRegisteredNodeId(rs.getString("registered_node_id"));
request.setCreateTime(rs.getDateTime("create_time"));
request.setLastUpdateBy(rs.getString("last_update_by"));
request.setLastUpdateTime(rs.getDateTime("last_update_time"));
request.setErrorMessage(rs.getString("error_message"));
return request;
}
}
}