/**
* 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.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.jumpmind.db.sql.ISqlRowMapper;
import org.jumpmind.db.sql.ISqlTransaction;
import org.jumpmind.db.sql.Row;
import org.jumpmind.db.sql.SqlException;
import org.jumpmind.db.sql.UniqueKeyException;
import org.jumpmind.db.sql.mapper.StringMapper;
import org.jumpmind.security.ISecurityService;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.config.INodeIdCreator;
import org.jumpmind.symmetric.db.ISymmetricDialect;
import org.jumpmind.symmetric.ext.IOfflineServerListener;
import org.jumpmind.symmetric.model.NetworkedNode;
import org.jumpmind.symmetric.model.Node;
import org.jumpmind.symmetric.model.NodeGroupLinkAction;
import org.jumpmind.symmetric.model.NodeHost;
import org.jumpmind.symmetric.model.NodeSecurity;
import org.jumpmind.symmetric.model.NodeStatus;
import org.jumpmind.symmetric.security.INodePasswordFilter;
import org.jumpmind.symmetric.service.IExtensionService;
import org.jumpmind.symmetric.service.INodeService;
import org.jumpmind.symmetric.service.IParameterService;
import org.jumpmind.symmetric.util.DefaultNodeIdCreator;
import org.jumpmind.util.AppUtils;
/**
* @see INodeService
*/
public class NodeService extends AbstractService implements INodeService {
private IExtensionService extensionService;
private Node cachedNodeIdentity;
private Map<String, NodeSecurity> securityCache;
private long securityCacheTime;
private INodePasswordFilter nodePasswordFilter;
private NodeHost nodeHostForCurrentNode = null;
public NodeService(IParameterService parameterService, ISymmetricDialect dialect, ISecurityService securityService,
IExtensionService extensionService) {
super(parameterService, dialect);
this.extensionService = extensionService;
extensionService.addExtensionPoint(new DefaultNodeIdCreator(parameterService, this, securityService));
setSqlMap(new NodeServiceSqlMap(symmetricDialect.getPlatform(),
createSqlReplacementTokens()));
}
public String findSymmetricVersion() {
return (String) sqlTemplate.queryForObject(getSql("findSymmetricVersionSql"), String.class);
}
public String findIdentityNodeId() {
Node node = findIdentity();
return node != null ? node.getNodeId() : null;
}
public Collection<Node> findEnabledNodesFromNodeGroup(String nodeGroupId) {
return sqlTemplate.query(getSql("selectNodePrefixSql", "findEnabledNodesFromNodeGroupSql"),
new NodeRowMapper(), new Object[] { nodeGroupId });
}
public Set<Node> findNodesThatOriginatedFromNodeId(String originalNodeId) {
return findNodesThatOriginatedFromNodeId(originalNodeId, true);
}
public Collection<Node> findNodesWithOpenRegistration() {
return sqlTemplate.query(getSql("selectNodePrefixSql", "findNodesWithOpenRegistrationSql"),
new NodeRowMapper());
}
public Set<Node> findNodesThatOriginatedFromNodeId(String originalNodeId, boolean recursive) {
Set<Node> all = new HashSet<Node>();
List<Node> list = sqlTemplate.query(
getSql("selectNodePrefixSql", "findNodesCreatedByMeSql"), new NodeRowMapper(),
originalNodeId);
if (list.size() > 0) {
all.addAll(list);
if (recursive) {
for (Node node : list) {
all.addAll(findNodesThatOriginatedFromNodeId(node.getNodeId()));
}
}
}
return all;
}
/**
* Lookup a node in the database, which contains information for syncing
* with it.
*/
public Node findNode(String id) {
List<Node> list = sqlTemplate.query(getSql("selectNodePrefixSql", "findNodeSql"),
new NodeRowMapper(), id);
return (Node) getFirstEntry(list);
}
public Node findNodeByExternalId(String nodeGroupId, String externalId) {
List<Node> list = sqlTemplate.query(
getSql("selectNodePrefixSql", "findNodeByExternalIdSql"), new NodeRowMapper(),
nodeGroupId, externalId);
return (Node) getFirstEntry(list);
}
public void ignoreNodeChannelForExternalId(boolean enabled, String channelId,
String nodeGroupId, String externalId) {
Node node = findNodeByExternalId(nodeGroupId, externalId);
if (sqlTemplate.update(getSql("nodeChannelControlIgnoreSql"), new Object[] {
enabled ? 1 : 0, node.getNodeId(), channelId }) == 0) {
sqlTemplate.update(getSql("insertNodeChannelControlSql"),
new Object[] { node.getNodeId(), channelId, enabled ? 1 : 0, 0 });
}
}
public boolean isRegistrationEnabled(String nodeId) {
NodeSecurity nodeSecurity = findNodeSecurity(nodeId);
if (nodeSecurity != null) {
return nodeSecurity.isRegistrationEnabled();
}
return false;
}
/**
* Lookup a node_security in the database, which contains private
* information used to authenticate.
*/
public NodeSecurity findNodeSecurity(String id) {
return findNodeSecurity(id, false);
}
public List<NodeHost> findNodeHosts(String nodeId) {
return sqlTemplate.query(getSql("selectNodeHostPrefixSql", "selectNodeHostByNodeIdSql"),
new NodeHostRowMapper(), nodeId);
}
public void deleteNodeHost(String nodeId) {
platform.getSqlTemplate().update(getSql("deleteNodeHostSql"), new Object[] { nodeId });
}
public void updateNodeHost(NodeHost nodeHost) {
Object[] params = new Object[] {
nodeHost.getIpAddress(),
nodeHost.getOsUser(), nodeHost.getOsName(),
nodeHost.getOsArch(), nodeHost.getOsVersion(),
nodeHost.getAvailableProcessors(),
nodeHost.getFreeMemoryBytes(),
nodeHost.getTotalMemoryBytes(),
nodeHost.getMaxMemoryBytes(),
nodeHost.getJavaVersion(), nodeHost.getJavaVendor(),
nodeHost.getJdbcVersion(),
nodeHost.getSymmetricVersion(),
nodeHost.getTimezoneOffset(),
nodeHost.getHeartbeatTime(),
nodeHost.getLastRestartTime(), nodeHost.getNodeId(),
nodeHost.getHostName() };
if (sqlTemplate.update(getSql("updateNodeHostSql"), params) == 0) {
sqlTemplate.update(getSql("insertNodeHostSql"), params);
}
}
public void updateNodeHostForCurrentNode() {
if (nodeHostForCurrentNode == null) {
nodeHostForCurrentNode = new NodeHost(findIdentityNodeId());
}
nodeHostForCurrentNode.refresh(platform);
updateNodeHost(nodeHostForCurrentNode);
}
public NodeSecurity findNodeSecurity(String nodeId, boolean createIfNotFound) {
try {
if (nodeId != null) {
List<NodeSecurity> list = sqlTemplate.query(getSql("findNodeSecuritySql"),
new NodeSecurityRowMapper(), new Object[] { nodeId },
new int[] { Types.VARCHAR });
NodeSecurity security = (NodeSecurity) getFirstEntry(list);
if (security == null && createIfNotFound) {
insertNodeSecurity(nodeId);
security = findNodeSecurity(nodeId, false);
}
return security;
} else {
log.debug("A 'null' node id was passed into findNodeSecurity");
return null;
}
} catch (UniqueKeyException ex) {
log.error(
"Could not find a node security row for '{}'",
nodeId);
throw ex;
}
}
public void deleteNodeSecurity(String nodeId) {
sqlTemplate.update(getSql("deleteNodeSecuritySql"), new Object[] { nodeId });
}
public void deleteNode(String nodeId, boolean syncChange) {
ISqlTransaction transaction = null;
try {
transaction = sqlTemplate.startSqlTransaction();
if (!syncChange) {
symmetricDialect.disableSyncTriggers(transaction, nodeId);
}
if (StringUtils.isNotBlank(nodeId)) {
if (nodeId.equals(findIdentityNodeId())) {
transaction.prepareAndExecute(getSql("deleteNodeIdentitySql"));
}
transaction.prepareAndExecute(getSql("deleteNodeSecuritySql"), new Object[] { nodeId });
transaction.prepareAndExecute(getSql("deleteNodeHostSql"), new Object[] { nodeId });
transaction.prepareAndExecute(getSql("deleteNodeSql"), new Object[] { nodeId });
transaction.prepareAndExecute(getSql("deleteNodeChannelCtlSql"), new Object[] { nodeId });
transaction.prepareAndExecute(getSql("deleteIncomingErrorSql"), new Object[] { nodeId });
transaction.prepareAndExecute(getSql("deleteExtractRequestSql"), new Object[] { nodeId });
transaction.prepareAndExecute(getSql("deleteNodeCommunicationSql"), new Object[] { nodeId });
transaction.prepareAndExecute(getSql("deleteTableReloadRequestSql"), new Object[] { nodeId, nodeId });
transaction.prepareAndExecute(getSql("setOutgoingBatchOkSql"), new Object[] { nodeId });
transaction.prepareAndExecute(getSql("deleteIncomingBatchSql"), new Object[] { nodeId });
}
} catch (Error ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} catch (RuntimeException ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} finally {
if (!syncChange) {
symmetricDialect.enableSyncTriggers(transaction);
}
close(transaction);
}
}
public void insertNodeSecurity(String id) {
flushNodeAuthorizedCache();
String password = extensionService.getExtensionPoint(INodeIdCreator.class).generatePassword(new Node(id, null, null));
password = filterPasswordOnSaveIfNeeded(password);
sqlTemplate.update(getSql("insertNodeSecuritySql"), new Object[] { id, password,
null });
}
public void insertNodeIdentity(String nodeId) {
sqlTemplate.update(getSql("insertNodeIdentitySql"), nodeId);
}
public boolean deleteIdentity() {
boolean successful = false;
try {
sqlTemplate.update(getSql("deleteNodeIdentitySql"));
successful = true;
} catch (SqlException ex) {
log.debug(ex.getMessage());
} finally {
cachedNodeIdentity = null;
}
return successful;
}
public void insertNodeGroup(String groupId, String description) {
if (sqlTemplate.queryForInt(getSql("doesNodeGroupExistSql"), groupId) == 0) {
sqlTemplate.update(getSql("insertNodeGroupSql"), description, groupId);
}
}
public void save(Node node) {
if (!updateNode(node)) {
sqlTemplate.update(
getSql("insertNodeSql"),
new Object[] { node.getNodeGroupId(), node.getExternalId(), node.getDatabaseType(),
node.getDatabaseVersion(), node.getSchemaVersion(),
node.getSymmetricVersion(), node.getSyncUrl(), new Date(),
node.isSyncEnabled() ? 1 : 0, AppUtils.getTimezoneOffset(),
node.getBatchToSendCount(), node.getBatchInErrorCount(),
node.getCreatedAtNodeId(), node.getDeploymentType(), node.getNodeId() },
new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP,
Types.INTEGER, Types.VARCHAR, Types.INTEGER, Types.INTEGER, Types.VARCHAR,
Types.VARCHAR, Types.VARCHAR });
}
}
public boolean updateNode(Node node) {
boolean updated = sqlTemplate.update(
getSql("updateNodeSql"),
new Object[] { node.getNodeGroupId(), node.getExternalId(), node.getDatabaseType(),
node.getDatabaseVersion(), node.getSchemaVersion(),
node.getSymmetricVersion(), node.getSyncUrl(), new Date(),
node.isSyncEnabled() ? 1 : 0, AppUtils.getTimezoneOffset(),
node.getBatchToSendCount(), node.getBatchInErrorCount(),
node.getCreatedAtNodeId(), node.getDeploymentType(), node.getNodeId() },
new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP,
Types.INTEGER, Types.VARCHAR, Types.INTEGER, Types.INTEGER, Types.VARCHAR,
Types.VARCHAR, Types.VARCHAR }) == 1;
return updated;
}
protected <T> T getFirstEntry(List<T> list) {
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
public List<NodeSecurity> findNodeSecurityWithLoadEnabled() {
return sqlTemplate.query(
getSql("findNodeSecurityWithLoadEnabledSql"), new NodeSecurityRowMapper());
}
public Map<String, NodeSecurity> findAllNodeSecurity(boolean useCache) {
long maxSecurityCacheTime = parameterService
.getLong(ParameterConstants.CACHE_TIMEOUT_NODE_SECURITY_IN_MS);
Map<String, NodeSecurity> all = securityCache;
if (all == null || System.currentTimeMillis() - securityCacheTime >= maxSecurityCacheTime
|| securityCacheTime == 0 || !useCache) {
all = (Map<String, NodeSecurity>) sqlTemplate.queryForMap(
getSql("findAllNodeSecuritySql"), new NodeSecurityRowMapper(), "node_id");
securityCache = all;
securityCacheTime = System.currentTimeMillis();
}
return all;
}
/**
* Check that the given node and password match in the node_security table.
* A node must authenticate before it's allowed to sync data.
*/
public boolean isNodeAuthorized(String nodeId, String password) {
Map<String, NodeSecurity> nodeSecurities = findAllNodeSecurity(true);
NodeSecurity nodeSecurity = nodeSecurities.get(nodeId);
if (nodeSecurity != null
&& !nodeId.equals(findIdentityNodeId()) && ((nodeSecurity.getNodePassword() != null
&& !nodeSecurity.getNodePassword().equals("") && nodeSecurity
.getNodePassword().equals(password)) || nodeSecurity
.isRegistrationEnabled())) {
return true;
}
return false;
}
public void flushNodeAuthorizedCache() {
securityCacheTime = 0;
}
public Node getCachedIdentity() {
return cachedNodeIdentity;
}
public Node findIdentity() {
return findIdentity(true);
}
public Node findIdentity(boolean useCache) {
return findIdentity(useCache, true);
}
public Node findIdentity(boolean useCache, boolean logSqlError) {
if (cachedNodeIdentity == null || useCache == false) {
try {
List<Node> list = sqlTemplate.query(
getSql("selectNodePrefixSql", "findNodeIdentitySql"), new NodeRowMapper());
cachedNodeIdentity = (Node) getFirstEntry(list);
} catch (SqlException ex) {
if (logSqlError) {
log.info("Failed to load the node identity because: {}. Returning {}",
ex.getMessage(), cachedNodeIdentity);
}
}
}
return cachedNodeIdentity;
}
public List<Node> findNodesToPull() {
return findSourceNodesFor(NodeGroupLinkAction.W);
}
public List<Node> findNodesToPushTo() {
return findTargetNodesFor(NodeGroupLinkAction.P);
}
public List<Node> findSourceNodesFor(NodeGroupLinkAction eventAction) {
Node node = findIdentity();
if (node != null) {
return sqlTemplate.query(getSql("selectNodePrefixSql", "findNodesWhoTargetMeSql"),
new NodeRowMapper(), node.getNodeGroupId(), eventAction.name());
} else {
return Collections.emptyList();
}
}
public List<Node> findTargetNodesFor(NodeGroupLinkAction eventAction) {
Node node = findIdentity();
if (node != null) {
return sqlTemplate.query(getSql("selectNodePrefixSql", "findNodesWhoITargetSql"),
new NodeRowMapper(), node.getNodeGroupId(), eventAction.name());
} else {
return Collections.emptyList();
}
}
public List<String> findAllExternalIds() {
return sqlTemplate.query(getSql("selectExternalIdsSql"), new StringMapper());
}
public List<Node> findAllNodes() {
return sqlTemplate.query(getSql("selectNodePrefixSql"), new NodeRowMapper());
}
public Map<String, Node> findAllNodesAsMap() {
List<Node> nodes = findAllNodes();
Map<String, Node> nodeMap = new HashMap<String, Node>(nodes.size());
for (Node node : nodes) {
nodeMap.put(node.getNodeId(), node);
}
return nodeMap;
}
public NetworkedNode getRootNetworkedNode() {
Map<String, Node> nodes = findAllNodesAsMap();
Map<String, NetworkedNode> leaves = new HashMap<String, NetworkedNode>(nodes.size());
NetworkedNode nodeLeaf = null;
for (Node node : nodes.values()) {
nodeLeaf = leaves.get(node.getNodeId());
if (nodeLeaf == null) {
nodeLeaf = new NetworkedNode(node);
nodeLeaf.addParents(nodes, leaves);
leaves.put(node.getNodeId(), nodeLeaf);
}
}
nodeLeaf = leaves.get(findIdentityNodeId());
if (nodeLeaf != null) {
NetworkedNode root = nodeLeaf.getRoot();
root.setAllNetworkedNodes(leaves);
return root;
} else {
return null;
}
}
public boolean updateNodeSecurity(NodeSecurity security) {
ISqlTransaction transaction = null;
try {
transaction = sqlTemplate.startSqlTransaction();
boolean updated = updateNodeSecurity(transaction, security);
transaction.commit();
return updated;
} catch (Error ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} catch (RuntimeException ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} finally {
close(transaction);
}
}
public boolean updateNodeSecurity(ISqlTransaction transaction, NodeSecurity security) {
security.setNodePassword(filterPasswordOnSaveIfNeeded(security.getNodePassword()));
boolean updated = transaction.prepareAndExecute(
getSql("updateNodeSecuritySql"),
new Object[] { security.getNodePassword(),
security.isRegistrationEnabled() ? 1 : 0, security.getRegistrationTime(),
security.isInitialLoadEnabled() ? 1 : 0, security.getInitialLoadTime(),
security.getCreatedAtNodeId(),
security.isRevInitialLoadEnabled() ? 1 : 0,
security.getRevInitialLoadTime(),
security.getInitialLoadId(),
security.getInitialLoadCreateBy(),
security.getRevInitialLoadId(),
security.getRevInitialLoadCreateBy(),
security.getNodeId() }, new int[] {
Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP, Types.INTEGER,
Types.TIMESTAMP, Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP,
Types.BIGINT, Types.VARCHAR, Types.BIGINT, Types.VARCHAR,
Types.VARCHAR }) == 1;
flushNodeAuthorizedCache();
return updated;
}
public boolean setInitialLoadEnabled(ISqlTransaction transaction, String nodeId,
boolean initialLoadEnabled, boolean syncChange, long loadId, String createBy) {
try {
if (!syncChange) {
symmetricDialect.disableSyncTriggers(transaction, nodeId);
}
NodeSecurity nodeSecurity = findNodeSecurity(nodeId, true);
if (nodeSecurity != null) {
nodeSecurity.setInitialLoadEnabled(initialLoadEnabled);
nodeSecurity.setInitialLoadId(loadId);
if (initialLoadEnabled) {
nodeSecurity.setInitialLoadTime(null);
nodeSecurity.setInitialLoadCreateBy(createBy);
} else {
nodeSecurity.setInitialLoadTime(new Date());
}
return updateNodeSecurity(transaction, nodeSecurity);
}
return false;
} finally {
if (!syncChange) {
symmetricDialect.enableSyncTriggers(transaction);
}
}
}
public boolean setInitialLoadEnabled(String nodeId, boolean initialLoadEnabled, boolean syncChange, long loadId, String createBy) {
ISqlTransaction transaction = null;
try {
transaction = sqlTemplate.startSqlTransaction();
boolean updated = setInitialLoadEnabled(transaction, nodeId, initialLoadEnabled, syncChange, loadId, createBy);
transaction.commit();
return updated;
} catch (Error ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} catch (RuntimeException ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} finally {
close(transaction);
}
}
public boolean setReverseInitialLoadEnabled(ISqlTransaction transaction, String nodeId,
boolean initialLoadEnabled, boolean syncChange, long loadId, String createBy) {
try {
if (!syncChange) {
symmetricDialect.disableSyncTriggers(transaction, nodeId);
}
NodeSecurity nodeSecurity = findNodeSecurity(nodeId, true);
if (nodeSecurity != null) {
nodeSecurity.setRevInitialLoadEnabled(initialLoadEnabled);
nodeSecurity.setRevInitialLoadId(loadId);
if (initialLoadEnabled) {
nodeSecurity.setRevInitialLoadTime(null);
nodeSecurity.setRevInitialLoadCreateBy(createBy);
} else {
nodeSecurity.setRevInitialLoadTime(new Date());
}
return updateNodeSecurity(transaction, nodeSecurity);
}
return false;
} finally {
if (!syncChange) {
symmetricDialect.enableSyncTriggers(transaction);
}
}
}
public boolean setReverseInitialLoadEnabled(String nodeId, boolean initialLoadEnabled, boolean syncChange, long loadId, String createBy) {
ISqlTransaction transaction = null;
try {
transaction = sqlTemplate.startSqlTransaction();
boolean updated = setReverseInitialLoadEnabled(transaction, nodeId, initialLoadEnabled, syncChange, loadId, createBy);
transaction.commit();
return updated;
} catch (Error ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} catch (RuntimeException ex) {
if (transaction != null) {
transaction.rollback();
}
throw ex;
} finally {
close(transaction);
}
}
public boolean isExternalIdRegistered(String nodeGroupId, String externalId) {
return sqlTemplate.queryForInt(getSql("isNodeRegisteredSql"), new Object[] { nodeGroupId,
externalId }) > 0;
}
public boolean isDataLoadCompleted() {
return getNodeStatus() == NodeStatus.DATA_LOAD_COMPLETED;
}
public boolean isDataLoadStarted() {
return getNodeStatus() == NodeStatus.DATA_LOAD_STARTED;
}
public boolean isRegistrationServer() {
return parameterService.isRegistrationServer();
}
public NodeStatus getNodeStatus() {
long ts = System.currentTimeMillis();
try {
class DataLoadStatus {
int initialLoadEnabled;
Date initialLoadTime;
}
List<DataLoadStatus> results = sqlTemplate.query(getSql("getDataLoadStatusSql"),
new ISqlRowMapper<DataLoadStatus>() {
public DataLoadStatus mapRow(Row rs) {
DataLoadStatus status = new DataLoadStatus();
status.initialLoadEnabled = rs.getInt("initial_load_enabled");
status.initialLoadTime = rs.getDateTime("initial_load_time");
return status;
}
});
if (results.size() > 0) {
DataLoadStatus status = results.get(0);
if (status.initialLoadEnabled == 1) {
return NodeStatus.DATA_LOAD_STARTED;
} else if (status.initialLoadTime != null) {
return NodeStatus.DATA_LOAD_COMPLETED;
}
}
return NodeStatus.DATA_LOAD_NOT_STARTED;
} catch (SqlException ex) {
log.error("Could not query table after {} ms. The status is unknown.",
(System.currentTimeMillis() - ts), ex);
return NodeStatus.STATUS_UNKNOWN;
}
}
public void setNodePasswordFilter(INodePasswordFilter nodePasswordFilter) {
this.nodePasswordFilter = nodePasswordFilter;
}
private String filterPasswordOnSaveIfNeeded(String password) {
String s = password;
if (nodePasswordFilter != null) {
s = nodePasswordFilter.onNodeSecuritySave(password);
}
return s;
}
private String filterPasswordOnRenderIfNeeded(String password) {
String s = password;
if (nodePasswordFilter != null) {
s = nodePasswordFilter.onNodeSecurityRender(password);
}
return s;
}
public void checkForOfflineNodes() {
long offlineNodeDetectionMinutes = parameterService
.getLong(ParameterConstants.OFFLINE_NODE_DETECTION_PERIOD_MINUTES);
List<IOfflineServerListener> offlineServerListeners = extensionService.getExtensionPointList(IOfflineServerListener.class);
// Only check for offline nodes if there is a listener and the
// offline detection period is a positive value. The default value
// of -1 disables the feature.
if (offlineServerListeners != null && offlineNodeDetectionMinutes > 0) {
List<Node> list = findOfflineNodes();
if (list.size() > 0) {
fireOffline(list);
}
}
}
public List<Node> findOfflineNodes() {
return findOfflineNodes(parameterService
.getLong(ParameterConstants.OFFLINE_NODE_DETECTION_PERIOD_MINUTES));
}
public List<Node> findOfflineNodes(long minutesOffline) {
List<Node> offlineNodeList = new ArrayList<Node>();
Node myNode = findIdentity();
if (myNode != null) {
long offlineNodeDetectionMillis = minutesOffline * 60 * 1000;
List<Row> list = sqlTemplate.query(getSql("findNodeHeartbeatsSql"));
for (Row node : list) {
String nodeId = node.getString("node_id");
Date time = node.getDateTime("heartbeat_time");
String offset = node.getString("timezone_offset");
// Take the timezone of the client node into account when
// checking the hearbeat time.
Date clientNodeCurrentTime = null;
if (offset != null) {
clientNodeCurrentTime = AppUtils
.getLocalDateForOffset(offset);
} else {
clientNodeCurrentTime = new Date();
}
long cutOffTimeMillis = clientNodeCurrentTime.getTime()
- offlineNodeDetectionMillis;
if (time == null
|| time.getTime() < cutOffTimeMillis) {
offlineNodeList.add(findNode(nodeId));
}
}
}
return offlineNodeList;
}
public Map<String, Date> findLastHeartbeats() {
Map<String, Date> dates = new HashMap<String, Date>();
Node myNode = findIdentity();
if (myNode != null) {
List<Row> list = sqlTemplate.query(getSql("findNodeHeartbeatsSql"));
for (Row node : list) {
String nodeId = node.getString("node_id");
Date time = node.getDateTime("heartbeat_time");
dates.put(nodeId, time);
}
}
return dates;
}
public List<String> findOfflineNodeIds(long minutesOffline) {
List<String> offlineNodeList = new ArrayList<String>();
Node myNode = findIdentity();
if (myNode != null) {
long offlineNodeDetectionMillis = minutesOffline * 60 * 1000;
List<Row> list = sqlTemplate.query(getSql("findNodeHeartbeatsSql"));
for (Row node : list) {
String nodeId = node.getString("node_id");
Date time = node.getDateTime("heartbeat_time");
String offset = node.getString("timezone_offset");
// Take the timezone of the client node into account when
// checking the hearbeat time.
Date clientNodeCurrentTime = null;
if (offset != null) {
clientNodeCurrentTime = AppUtils
.getLocalDateForOffset(offset);
} else {
clientNodeCurrentTime = new Date();
}
long cutOffTimeMillis = clientNodeCurrentTime.getTime()
- offlineNodeDetectionMillis;
if (time == null
|| time.getTime() < cutOffTimeMillis) {
offlineNodeList.add(nodeId);
}
}
}
return offlineNodeList;
}
protected void fireOffline(List<Node> offlineClientNodeList) {
for (IOfflineServerListener listener : extensionService.getExtensionPointList(IOfflineServerListener.class)) {
for (Node node : offlineClientNodeList) {
listener.clientNodeOffline(node);
}
}
}
class NodeRowMapper implements ISqlRowMapper<Node> {
public Node mapRow(Row rs) {
Node node = new Node();
node.setNodeId(rs.getString("node_id"));
node.setNodeGroupId(rs.getString("node_group_id"));
node.setExternalId(rs.getString("external_id"));
node.setSyncEnabled(rs.getBoolean("sync_enabled"));
node.setSyncUrl(rs.getString("sync_url"));
node.setSchemaVersion(rs.getString("schema_version"));
node.setDatabaseType(rs.getString("database_type"));
node.setDatabaseVersion(rs.getString("database_version"));
node.setSymmetricVersion(rs.getString("symmetric_version"));
node.setCreatedAtNodeId(rs.getString("created_at_node_id"));
node.setBatchToSendCount(rs.getInt("batch_to_send_count"));
node.setBatchInErrorCount(rs.getInt("batch_in_error_count"));
node.setDeploymentType(rs.getString("deployment_type"));
return node;
}
}
class NodeSecurityRowMapper implements ISqlRowMapper<NodeSecurity> {
public NodeSecurity mapRow(Row rs) {
NodeSecurity nodeSecurity = new NodeSecurity();
nodeSecurity.setNodeId(rs.getString("node_id"));
nodeSecurity.setNodePassword(filterPasswordOnRenderIfNeeded(rs
.getString("node_password")));
nodeSecurity.setRegistrationEnabled(rs.getBoolean("registration_enabled"));
nodeSecurity.setRegistrationTime(rs.getDateTime("registration_time"));
nodeSecurity.setInitialLoadEnabled(rs.getBoolean("initial_load_enabled"));
nodeSecurity.setInitialLoadTime(rs.getDateTime("initial_load_time"));
nodeSecurity.setCreatedAtNodeId(rs.getString("created_at_node_id"));
nodeSecurity.setRevInitialLoadEnabled(rs.getBoolean("rev_initial_load_enabled"));
nodeSecurity.setRevInitialLoadTime(rs.getDateTime("rev_initial_load_time"));
nodeSecurity.setInitialLoadId(rs.getLong("initial_load_id"));
nodeSecurity.setInitialLoadCreateBy(rs.getString("initial_load_create_by"));
nodeSecurity.setRevInitialLoadId(rs.getLong("rev_initial_load_id"));
nodeSecurity.setRevInitialLoadCreateBy(rs.getString("rev_initial_load_create_by"));
return nodeSecurity;
}
}
class NodeHostRowMapper implements ISqlRowMapper<NodeHost> {
public NodeHost mapRow(Row rs) {
NodeHost nodeHost = new NodeHost();
nodeHost.setNodeId(rs.getString("node_id"));
nodeHost.setHostName(rs.getString("host_name"));
nodeHost.setIpAddress(rs.getString("ip_address"));
nodeHost.setOsUser(rs.getString("os_user"));
nodeHost.setOsName(rs.getString("os_name"));
nodeHost.setOsArch(rs.getString("os_arch"));
nodeHost.setOsVersion(rs.getString("os_version"));
nodeHost.setAvailableProcessors(rs.getInt("available_processors"));
nodeHost.setFreeMemoryBytes(rs.getLong("free_memory_bytes"));
nodeHost.setTotalMemoryBytes(rs.getLong("total_memory_bytes"));
nodeHost.setMaxMemoryBytes(rs.getLong("max_memory_bytes"));
nodeHost.setJavaVersion(rs.getString("java_version"));
nodeHost.setJavaVendor(rs.getString("java_vendor"));
nodeHost.setJdbcVersion(rs.getString("jdbc_version"));
nodeHost.setSymmetricVersion(rs.getString("symmetric_version"));
nodeHost.setTimezoneOffset(rs.getString("timezone_offset"));
nodeHost.setHeartbeatTime(rs.getDateTime("heartbeat_time"));
nodeHost.setLastRestartTime(rs.getDateTime("last_restart_time"));
nodeHost.setCreateTime(rs.getDateTime("create_time"));
return nodeHost;
}
}
}