1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.jumpmind.symmetric.service.impl;
23
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.net.ConnectException;
27 import java.sql.Types;
28
29 import org.apache.commons.lang.time.DateUtils;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.jumpmind.symmetric.common.ParameterConstants;
33 import org.jumpmind.symmetric.db.IDbDialect;
34 import org.jumpmind.symmetric.model.Node;
35 import org.jumpmind.symmetric.model.NodeSecurity;
36 import org.jumpmind.symmetric.service.IClusterService;
37 import org.jumpmind.symmetric.service.IConfigurationService;
38 import org.jumpmind.symmetric.service.IDataExtractorService;
39 import org.jumpmind.symmetric.service.IDataLoaderService;
40 import org.jumpmind.symmetric.service.IDataService;
41 import org.jumpmind.symmetric.service.INodeService;
42 import org.jumpmind.symmetric.service.IRegistrationService;
43 import org.jumpmind.symmetric.transport.ITransportManager;
44 import org.jumpmind.symmetric.util.RandomTimeSlot;
45
46
47
48 public class RegistrationService extends AbstractService implements IRegistrationService {
49
50 protected static final Log logger = LogFactory.getLog(RegistrationService.class);
51
52 private INodeService nodeService;
53
54 private IDataExtractorService dataExtractorService;
55
56 private IConfigurationService configurationService;
57
58 private IClusterService clusterService;
59
60 private IDataService dataService;
61
62 private IDataLoaderService dataLoaderService;
63
64 private ITransportManager transportManager;
65
66 private IDbDialect dbDialect;
67
68 /***
69 * Register a node for the given domain name and domain ID if the
70 * registration is open.
71 * @param isRequestedRegistration An indicator that registration has been requested by the remote client
72 */
73 public boolean registerNode(Node node, OutputStream out, boolean isRequestedRegistration) throws IOException {
74 if (!configurationService.isRegistrationServer()) {
75
76 NodeSecurity security = nodeService.findNodeSecurity(nodeService.findIdentity().getNodeId());
77 if (security == null || security.getInitialLoadTime() == null) {
78 logger.warn("Registration is not allowed until this node has an initial load");
79 return false;
80 }
81 }
82 String nodeId = findNodeToRegister(node.getNodeGroupId(), node.getExternalId());
83 if (nodeId == null && parameterService.is(ParameterConstants.AUTO_REGISTER_ENABLED)) {
84 Node existingNode = nodeService.findNodeByExternalId(node.getNodeGroupId(), node.getExternalId());
85 if (existingNode != null) {
86 nodeId = existingNode.getNodeId();
87 } else {
88 openRegistration(node.getNodeGroupId(), node.getExternalId());
89 nodeId = findNodeToRegister(node.getNodeGroupId(), node.getExternalId());
90 }
91 }
92 if (nodeId == null) {
93 return false;
94 }
95 node.setNodeId(nodeId);
96 jdbcTemplate.update(getSql("registerNodeSecuritySql"), new Object[] { node.getNodeId() });
97 jdbcTemplate.update(getSql("registerNodeSql"), new Object[] { node.getSyncURL(), node.getSchemaVersion(),
98 node.getDatabaseType(), node.getDatabaseVersion(), node.getSymmetricVersion(), node.getNodeId() },
99 new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR });
100 boolean success = writeConfiguration(node, out);
101 if (success && parameterService.is(ParameterConstants.AUTO_RELOAD_ENABLED)) {
102
103 NodeSecurity security = nodeService.findNodeSecurity(node.getNodeId());
104 if ((security != null && security.getInitialLoadTime() == null) || isRequestedRegistration) {
105 dataService.reloadNode(node.getNodeId());
106 }
107 }
108 return success;
109 }
110
111 private String findNodeToRegister(String nodeGroupId, String externald) {
112 return (String) jdbcTemplate.queryForObject(getSql("findNodeToRegisterSql"), new Object[] { nodeGroupId,
113 externald }, String.class);
114 }
115
116 private void sleepBeforeRegistrationRetry() {
117 try {
118 RandomTimeSlot randomSleepTimeSlot = new RandomTimeSlot(parameterService
119 .getString(ParameterConstants.EXTERNAL_ID), 60);
120 long sleepTimeInMs = DateUtils.MILLIS_PER_SECOND * randomSleepTimeSlot.getRandomValueSeededByDomainId();
121 logger.warn("Could not register. Sleeping for " + sleepTimeInMs + "ms before attempting again.");
122 Thread.sleep(sleepTimeInMs);
123 } catch (InterruptedException e) {
124 }
125 }
126
127 public boolean isRegisteredWithServer() {
128 return nodeService.findIdentity() != null;
129 }
130
131 public void registerWithServer() {
132 boolean registered = isRegisteredWithServer();
133
134
135 while (!registered) {
136 try {
137 logger.info("Attempting to register with " + parameterService.getRegistrationUrl());
138 registered = dataLoaderService.loadData(transportManager.getRegisterTransport(new Node(
139 this.parameterService, dbDialect)));
140 } catch (ConnectException e) {
141 logger.warn("Connection failed while registering.");
142 } catch (Exception e) {
143 logger.error(e, e);
144 }
145
146 if (!registered) {
147 sleepBeforeRegistrationRetry();
148 } else {
149 Node node = nodeService.findIdentity();
150 if (node != null) {
151 logger.info("Successfully registered node [id=" + node.getNodeId() + "]");
152 } else {
153 logger.error("Node registration is unavailable");
154 }
155 }
156 }
157 }
158
159 /***
160 * Synchronize node configuration.
161 */
162 @Deprecated
163 protected boolean writeConfiguration(Node node, OutputStream out) throws IOException {
164 dataExtractorService.extractConfigurationStandalone(node, out);
165 return true;
166 }
167
168 /***
169 * Re-open registration for a single node that already exists in the
170 * database. A new password is generated and the registration_enabled flag
171 * is turned on. The next node to try registering for this node group and
172 * external ID will be given this information.
173 */
174 public void reOpenRegistration(String nodeId) {
175 String password = nodeService.generatePassword();
176 Node node = nodeService.findNode(nodeId);
177 if (node != null) {
178 int updateCount = jdbcTemplate.update(getSql("reopenRegistrationSql"), new Object[] { password, nodeId });
179 if (updateCount == 0) {
180
181
182
183 jdbcTemplate.update(getSql("openRegistrationNodeSecuritySql"), new Object[] { nodeId, password });
184 }
185 } else {
186 logger.warn("There was no row with a node id of " + nodeId + " to 'reopen' registration for.");
187 }
188 }
189
190 /***
191 * Open registration for a single new node given a node group (f.e.,
192 * "STORE") and external ID (f.e., "00001"). The unique node ID and password
193 * are generated and stored in the node and node_security tables with the
194 * registration_enabled flag turned on. The next node to try registering for
195 * this node group and external ID will be given this information.
196 */
197 public void openRegistration(String nodeGroup, String externalId) {
198 Node me = nodeService.findIdentity();
199 String nodeId = nodeService.generateNodeId(nodeGroup, externalId);
200 String password = nodeService.generatePassword();
201 jdbcTemplate.update(getSql("openRegistrationNodeSql"), new Object[] { nodeId, nodeGroup, externalId, me.getNodeId() });
202 jdbcTemplate.update(getSql("openRegistrationNodeSecuritySql"), new Object[] { nodeId, password, me.getNodeId() });
203 clusterService.initLockTableForNode(nodeService.findNode(nodeId));
204 logger.info("Just opened registration for external id of " + externalId + " and a node group of " + nodeGroup);
205 }
206
207 public void setNodeService(INodeService nodeService) {
208 this.nodeService = nodeService;
209 }
210
211 public void setDataExtractorService(IDataExtractorService dataExtractorService) {
212 this.dataExtractorService = dataExtractorService;
213 }
214
215 public void setConfigurationService(IConfigurationService configurationService) {
216 this.configurationService = configurationService;
217 }
218
219 public void setClusterService(IClusterService clusterService) {
220 this.clusterService = clusterService;
221 }
222
223 public void setDataService(IDataService dataService) {
224 this.dataService = dataService;
225 }
226
227 public boolean isAutoRegistration() {
228 return parameterService.is(ParameterConstants.AUTO_REGISTER_ENABLED);
229 }
230
231 public void setDataLoaderService(IDataLoaderService dataLoaderService) {
232 this.dataLoaderService = dataLoaderService;
233 }
234
235 public void setTransportManager(ITransportManager transportManager) {
236 this.transportManager = transportManager;
237 }
238
239 public void setDbDialect(IDbDialect dbDialect) {
240 this.dbDialect = dbDialect;
241 }
242
243 }