for managed servers the datasource name is now converted into a valid XML type NCName
[taxeditor.git] / eu.etaxonomy.taxeditor.cdmlib / src / main / java / eu / etaxonomy / taxeditor / remoting / source / CdmServerInfo.java
1 // $Id$
2 /**
3 * Copyright (C) 2015 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10 package eu.etaxonomy.taxeditor.remoting.source;
11
12 import java.io.IOException;
13 import java.net.Socket;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Comparator;
17 import java.util.List;
18
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.http.HttpEntity;
21 import org.apache.http.HttpResponse;
22 import org.apache.http.client.ClientProtocolException;
23 import org.apache.http.client.HttpClient;
24 import org.apache.http.client.ResponseHandler;
25 import org.apache.http.client.methods.HttpGet;
26 import org.apache.http.impl.client.DefaultHttpClient;
27 import org.apache.http.params.HttpConnectionParams;
28 import org.apache.http.params.HttpParams;
29 import org.apache.http.util.EntityUtils;
30 import org.apache.log4j.Logger;
31 import org.json.JSONArray;
32 import org.json.JSONException;
33 import org.json.JSONObject;
34
35 import eu.etaxonomy.cdm.api.application.CdmApplicationState;
36 import eu.etaxonomy.cdm.config.CdmSourceException;
37 import eu.etaxonomy.cdm.database.CdmPersistentDataSource;
38 import eu.etaxonomy.cdm.database.ICdmDataSource;
39 import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
40 import eu.etaxonomy.taxeditor.remoting.server.CDMServerException;
41 import eu.etaxonomy.taxeditor.remoting.server.CDMServerUtils;
42
43 /**
44 * @author cmathew
45 * @date 20 Jan 2015
46 *
47 */
48 public class CdmServerInfo {
49 public static final Logger logger = Logger.getLogger(CdmServerInfo.class);
50
51 private final static String CDMSERVER_PREFIX = "";
52 private final static String NAME_PRODUCTION = "cybertaxonomy.org";
53 private final static String SERVER_PRODUCTION = "api.cybertaxonomy.org";
54
55 private final static String NAME_INTEGRATION = "edit-integration";
56 private final static String SERVER_INTEGRATION = "int.e-taxonomy.eu";
57
58 private final static String NAME_DEMO_1 = "edit-WS I";
59 private final static String SERVER_DEMO_1 = "160.45.63.230";
60
61 private final static String NAME_DEMO_2 = "edit-WS II";
62 private final static String SERVER_DEMO_2 = "160.45.63.231";
63
64 private final static String NAME_TEST = "edit-test";
65 private final static String SERVER_TEST = "test.e-taxonomy.eu";
66
67 public final static String SERVER_LOCALHOST = "localhost";
68 private final static String NAME_LOCALHOST = "localhost";
69 public final static String NAME_LOCALHOST_MGD = "localhost mgd.";
70
71 private final static String NAME_LOCALHOST_DEV = "localhost-dev";
72 private final static String NAME_INSTANCE_LOCALHOST_DEV = "local-dev";
73 private final static String SERVER_LOCALHOST_DEV = "localhost";
74 private final static int PORT_LOCALHOST_DEV = 8080;
75 private final static String BASEPATH_LOCALHOST_DEV = "";
76
77 public final static int NULL_PORT = -1;
78 public final static String NULL_PORT_STRING = "N/A";
79
80
81 private final String name;
82 private final String server;
83 private int port;
84 private final List<CdmInstanceInfo> instances;
85
86 private static List<CdmServerInfo> cdmServerInfoList;
87
88 private String cdmlibServicesVersion = "";
89 private String cdmlibServicesLastModified = "";
90
91
92 public CdmServerInfo(String name, String server, int port) {
93 this.name = name;
94 this.server = server;
95 this.port = port;
96 instances = new ArrayList<CdmInstanceInfo>();
97
98 }
99
100
101 public CdmInstanceInfo addInstance(String name, String basePath) {
102 String _basePath = basePath;
103 if(isLocalhostMgd()) {
104 _basePath = "";
105 }
106 CdmInstanceInfo cii = new CdmInstanceInfo(name, _basePath);
107 instances.add(cii);
108 return cii;
109
110 }
111
112 public boolean isLocalhost() {
113 return name.startsWith(SERVER_LOCALHOST);
114 }
115
116 public boolean isLocalhostMgd() {
117 return NAME_LOCALHOST_MGD.equals(name);
118 }
119
120 public String getCdmlibServicesVersion() {
121 return cdmlibServicesVersion;
122 }
123
124 public String getCdmlibLastModified() {
125 return cdmlibServicesLastModified;
126 }
127
128 public void refreshInstances() throws CDMServerException {
129 instances.clear();
130 if(isLocalhostMgd()) {
131 addInstancesFromDataSourcesConfig();
132 } else {
133 addInstancesViaHttp();
134 }
135 Collections.sort(instances, new Comparator<CdmInstanceInfo>() {
136 @Override
137 public int compare(CdmInstanceInfo cii1, CdmInstanceInfo cii2)
138 {
139 return cii1.getName().toString().compareTo(cii2.getName().toString());
140 }
141 });
142 }
143
144 public void updateInfo() throws CDMServerException {
145 String url = "http://" + server + ":" + String.valueOf(port) + "/" + CDMSERVER_PREFIX + "/info.jsp";
146 String responseBody = getResponse(url);
147 if(responseBody != null) {
148 try {
149 JSONObject info = new JSONObject(responseBody);
150 cdmlibServicesVersion = info.getString("cdmlibServicesVersion");
151 cdmlibServicesLastModified = info.getString("cdmlibServicesLastModified");
152 } catch (JSONException e) {
153 throw new CDMServerException(e);
154 }
155 }
156 }
157
158 public void addInstancesViaHttp() throws CDMServerException {
159 updateInfo();
160 String url = "http://" + server + ":" + String.valueOf(port) + "/" + CDMSERVER_PREFIX + "/instances.jsp";
161 String responseBody = getResponse(url);
162 if(responseBody != null) {
163 try {
164 JSONArray array = new JSONArray(responseBody);
165 for(int i=0;i<array.length();i++) {
166 JSONObject instance = (JSONObject)array.get(i);
167 if(instance != null) {
168 JSONObject conf = (JSONObject)instance.get("configuration");
169 if(conf != null) {
170 String instanceName = conf.getString("instanceName");
171 // we need to remove the first (char) forward slash from
172 // the base path
173 String basePath = conf.getString("basePath").substring(1);
174 addInstance(instanceName, basePath);
175 logger.info("Added instance with name : " + instanceName + ", basePath : " + basePath);
176 }
177 }
178 }
179 } catch (JSONException e) {
180 throw new CDMServerException(e);
181 }
182 }
183 }
184
185 private String getResponse(String url) throws CDMServerException {
186 HttpClient client = new DefaultHttpClient();
187 HttpParams params = client.getParams();
188
189 HttpConnectionParams.setConnectionTimeout(params, 5000);
190 HttpConnectionParams.setSoTimeout(params, 5000);
191
192 HttpGet httpGet = new HttpGet(url);
193
194 logger.info("Executing request " + httpGet.getRequestLine());
195
196 // Create a custom response handler
197 ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
198
199 @Override
200 public String handleResponse(
201 final HttpResponse response) throws ClientProtocolException, IOException {
202 int status = response.getStatusLine().getStatusCode();
203 if (status >= 200 && status < 300) {
204 HttpEntity entity = response.getEntity();
205 return entity != null ? EntityUtils.toString(entity) : null;
206 } else {
207 throw new ClientProtocolException("Unexpected response status: " + status);
208 }
209 }
210
211 };
212 String responseBody = null;
213 try {
214 responseBody = client.execute(httpGet, responseHandler);
215 } catch (ClientProtocolException e) {
216 throw new CDMServerException(e);
217 } catch (IOException e) {
218 throw new CDMServerException(e);
219 }
220 return responseBody;
221 }
222
223 public void addInstancesFromDataSourcesConfig() {
224 for(ICdmDataSource dataSource : CdmPersistentDataSource.getAllDataSources()){
225 String datasourceNCName = CDMServerUtils.xmlNCNamefrom(dataSource.getName());
226 logger.info("Adding local instance " + dataSource.getName() + " as " + datasourceNCName);
227 addInstance(datasourceNCName, datasourceNCName);
228 }
229 }
230
231 public String toString(String instanceName, int port) {
232 return server + ":" + String.valueOf(port) + "/" + instanceName;
233 }
234
235 public CdmInstanceInfo getInstanceFromName(String instanceName) {
236 if(instanceName == null) {
237 return null;
238 }
239
240 for(CdmInstanceInfo instance : instances) {
241 if(instance.getName() != null && instance.getName().equals(instanceName)) {
242 return instance;
243 }
244 }
245 return null;
246 }
247
248 public CdmRemoteSource getCdmRemoteSource(CdmInstanceInfo instance, int port) {
249 if(instance != null) {
250 return CdmRemoteSource.NewInstance(name,
251 server,
252 port,
253 instance.getBasePath(),
254 null);
255 }
256 return null;
257 }
258
259 public boolean pingServer() {
260 if(isLocalhostMgd()) {
261 return true;
262 }
263 try {
264 Socket s = new Socket(server, port);
265 logger.info("[CDM-Server] Available @ " + server + ":" + port );
266 updateInfo();
267 return true;
268 } catch (IOException ioe) {
269
270 } catch (CDMServerException e) {
271
272 }
273 return false;
274 }
275
276 public boolean pingInstance(CdmInstanceInfo instance, int port) throws CDMServerException {
277
278 ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
279 try {
280 if(crs != null && crs.checkConnection()) {
281 logger.info("[CDM-Server] Running @ " + server + ":" + port + " for instance " + instance);
282 return true;
283 }
284 } catch (CdmSourceException e) {
285 throw new CDMServerException(e);
286 }
287
288 return false;
289 }
290
291 public int compareDbSchemaVersion(CdmInstanceInfo instance, int port) throws CDMServerException {
292
293 ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
294 String dbSchemaVersion;
295 try {
296 dbSchemaVersion = crs.getDbSchemaVersion();
297 } catch (CdmSourceException e) {
298 throw new CDMServerException(e);
299 }
300
301
302 if(dbSchemaVersion != null) {
303 return CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
304 } else {
305 throw new CDMServerException("Cannot determine editor db. schema version");
306 }
307 }
308
309 public int compareCdmlibServicesVersion() throws CdmSourceException {
310
311 String serverVersion = cdmlibServicesVersion;
312 String serverCdmlibLastModified = cdmlibServicesLastModified;
313
314 return compareCdmlibServicesVersion(serverVersion, serverCdmlibLastModified);
315 }
316
317
318 /**
319 * @param serverVersion
320 * @param editorVersion
321 * @throws CdmSourceException
322 */
323 public static int compareCdmlibServicesVersion(String serverVersion, String serverCdmlibLastModified) throws CdmSourceException {
324
325 String editorVersion = CdmApplicationState.getCdmlibVersion();
326 String editorCdmlibLastModified = CdmApplicationState.getCdmlibLastModified();
327
328 int result = 0;
329 if(StringUtils.isBlank(serverVersion) || StringUtils.isBlank(editorVersion)) {
330 throw new CdmSourceException("cdmlib-services server or editor version is empty");
331 }
332
333 String[] serverVersionSplit = serverVersion.split("\\.");
334 String[] editorVersionSplit = editorVersion.split("\\.");
335
336 if(serverVersionSplit.length < 3 || editorVersionSplit.length < 3 || serverVersionSplit.length > 4 || editorVersionSplit.length > 4) {
337 throw new CdmSourceException("cdmlib-services server or editor version is invalid");
338 }
339
340 Integer serverVersionPart;
341 Integer editorVersionPart;
342
343 for(int i=0 ; i<3 ; i++) {
344 serverVersionPart = Integer.valueOf(serverVersionSplit[i]);
345 editorVersionPart = Integer.valueOf(editorVersionSplit[i]);
346
347 int partCompare = serverVersionPart.compareTo(editorVersionPart);
348 if (partCompare != 0){
349 return partCompare;
350 }
351 }
352 // at this point major, minor and patch versions are matching
353
354 if(StringUtils.isBlank(serverCdmlibLastModified) || StringUtils.isBlank(editorCdmlibLastModified)) {
355 throw new CdmSourceException("cdmlib-services server or editor version is empty");
356 }
357
358 String cdmServerIgnoreVersion = System.getProperty("cdm.server.version.lm.ignore");
359 if(StringUtils.isBlank(cdmServerIgnoreVersion) || !cdmServerIgnoreVersion.equals("true")) {
360 Long serverLastModified = Long.valueOf(serverCdmlibLastModified);
361 Long editorLastModified = Long.valueOf(editorCdmlibLastModified);
362 return serverLastModified.compareTo(editorLastModified);
363 }
364
365 return 0;
366 }
367
368
369
370 public static List<CdmServerInfo> getCdmServers() {
371 if(cdmServerInfoList == null) {
372 cdmServerInfoList = new ArrayList<CdmServerInfo>();
373 cdmServerInfoList.add(new CdmServerInfo(NAME_PRODUCTION, SERVER_PRODUCTION, 80));
374 //cdmServerInfoList.add(new CdmServerInfo(NAME_INTEGRATION, SERVER_INTEGRATION, 80));
375 cdmServerInfoList.add(new CdmServerInfo(NAME_DEMO_1, SERVER_DEMO_1, 80));
376 // cdmServerInfoList.add(new CdmServerInfo(NAME_DEMO_2, SERVER_DEMO_2, 80));
377 //cdmServerInfoList.add(new CdmServerInfo(NAME_TEST, SERVER_TEST, 80));
378 // cdmServerInfoList.add(new CdmServerInfo(NAME_LOCALHOST, SERVER_LOCALHOST, 8080));
379 cdmServerInfoList.add(new CdmServerInfo(NAME_LOCALHOST_MGD, SERVER_LOCALHOST,NULL_PORT));
380 }
381 return cdmServerInfoList;
382 }
383
384 public String getName() {
385 return name;
386 }
387
388 public String getServer() {
389 return server;
390 }
391
392
393 public int getPort() {
394 return port;
395 }
396
397 public void setPort(int port) {
398 this.port = port;
399 }
400
401 public List<CdmInstanceInfo> getInstances() throws CDMServerException {
402 if(instances.isEmpty()) {
403 refreshInstances();
404 }
405 return instances;
406 }
407
408 public static CdmRemoteSource getDevServerRemoteSource() {
409 String value = System.getProperty("cdm.server.dev.port");
410 boolean available = false;
411 CdmInstanceInfo devInstance = null;
412 if(value != null && !value.isEmpty()) {
413 int devPort = Integer.valueOf(value);
414 CdmServerInfo devCii = new CdmServerInfo(NAME_LOCALHOST_DEV, SERVER_LOCALHOST_DEV, devPort);
415 try {
416 devInstance = devCii.addInstance(NAME_INSTANCE_LOCALHOST_DEV, BASEPATH_LOCALHOST_DEV);
417 available = devCii.pingInstance(devInstance, devPort);
418 if(available) {
419 return devCii.getCdmRemoteSource(devInstance, devPort);
420 }
421 } catch (Exception e) {
422
423 }
424 }
425 return null;
426 }
427
428 public class CdmInstanceInfo {
429 private final String name;
430
431 /**
432 * The full path of the instance including the the prefix (if any).
433 * E.g. for an EDIT instance this would be something like "cdmserver/remoting"
434 * For a managed local server this would simply be ""
435 */
436 private final String basePath;
437
438
439 public CdmInstanceInfo(String name, String basePath) {
440 this.name = name;
441 this.basePath = basePath;
442 }
443
444
445 public String getName() {
446 return name;
447 }
448
449 public String getBasePath() {
450 return basePath;
451 }
452 }
453 }