Merge branch 'hotfix/3.12.3' into develop
[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 = "cdmserver/";
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 private String prefix = "";
92
93 private boolean ignoreCdmLibVersion = false;
94
95
96 public CdmServerInfo(String name, String server, int port, String prefix, boolean ignoreCdmLibVersion) {
97 this.name = name;
98 this.server = server;
99 this.port = port;
100 this.prefix = prefix;
101 this.ignoreCdmLibVersion = ignoreCdmLibVersion;
102 instances = new ArrayList<CdmInstanceInfo>();
103
104 }
105
106
107 public CdmInstanceInfo addInstance(String name, String basePath) {
108 String _basePath = basePath;
109 if(isLocalhostMgd()) {
110 _basePath = "";
111 }
112 CdmInstanceInfo cii = new CdmInstanceInfo(name, _basePath);
113 instances.add(cii);
114 return cii;
115
116 }
117
118 public boolean isLocalhost() {
119 return name.startsWith(SERVER_LOCALHOST);
120 }
121
122 public boolean isLocalhostMgd() {
123 return NAME_LOCALHOST_MGD.equals(name);
124 }
125
126 public String getCdmlibServicesVersion() {
127 return cdmlibServicesVersion;
128 }
129
130 public String getCdmlibLastModified() {
131 return cdmlibServicesLastModified;
132 }
133
134 public void refreshInstances() throws CDMServerException {
135 instances.clear();
136 if(isLocalhostMgd()) {
137 addInstancesFromDataSourcesConfig();
138 } else {
139 addInstancesViaHttp();
140 }
141 Collections.sort(instances, new Comparator<CdmInstanceInfo>() {
142 @Override
143 public int compare(CdmInstanceInfo cii1, CdmInstanceInfo cii2)
144 {
145 return cii1.getName().toString().compareTo(cii2.getName().toString());
146 }
147 });
148 }
149
150 public void updateInfo() throws CDMServerException {
151 String url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "info.jsp";
152 String responseBody = getResponse(url);
153 if(responseBody != null) {
154 try {
155 JSONObject info = new JSONObject(responseBody);
156 cdmlibServicesVersion = info.getString("cdmlibServicesVersion");
157 cdmlibServicesLastModified = info.getString("cdmlibServicesLastModified");
158 } catch (JSONException e) {
159 throw new CDMServerException(e);
160 }
161 }
162 }
163
164 public void addInstancesViaHttp() throws CDMServerException {
165 updateInfo();
166 String url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "instances.jsp";
167 String responseBody = getResponse(url);
168 if(responseBody != null) {
169 try {
170 JSONArray array = new JSONArray(responseBody);
171 for(int i=0;i<array.length();i++) {
172 JSONObject instance = (JSONObject)array.get(i);
173 if(instance != null) {
174 JSONObject conf = (JSONObject)instance.get("configuration");
175 if(conf != null) {
176 String instanceName = conf.getString("instanceName");
177 // we need to remove the first (char) forward slash from
178 // the base path
179 String basePath = conf.getString("basePath").substring(1);
180 addInstance(instanceName, basePath);
181 logger.info("Added instance with name : " + instanceName + ", basePath : " + basePath);
182 }
183 }
184 }
185 } catch (JSONException e) {
186 throw new CDMServerException(e);
187 }
188 }
189 }
190
191 private String getResponse(String url) throws CDMServerException {
192 HttpClient client = new DefaultHttpClient();
193 HttpParams params = client.getParams();
194
195 HttpConnectionParams.setConnectionTimeout(params, 5000);
196 HttpConnectionParams.setSoTimeout(params, 5000);
197
198 HttpGet httpGet = new HttpGet(url);
199
200 logger.info("Executing request " + httpGet.getRequestLine());
201
202 // Create a custom response handler
203 ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
204
205 @Override
206 public String handleResponse(
207 final HttpResponse response) throws ClientProtocolException, IOException {
208 int status = response.getStatusLine().getStatusCode();
209 if (status >= 200 && status < 300) {
210 HttpEntity entity = response.getEntity();
211 return entity != null ? EntityUtils.toString(entity) : null;
212 } else {
213 throw new ClientProtocolException("Unexpected response status: " + status);
214 }
215 }
216
217 };
218 String responseBody = null;
219 try {
220 responseBody = client.execute(httpGet, responseHandler);
221 } catch (ClientProtocolException e) {
222 throw new CDMServerException(e);
223 } catch (IOException e) {
224 throw new CDMServerException(e);
225 }
226 return responseBody;
227 }
228
229 public void addInstancesFromDataSourcesConfig() {
230 for(ICdmDataSource dataSource : CdmPersistentDataSource.getAllDataSources()){
231 String datasourceNCName = CDMServerUtils.xmlNCNamefrom(dataSource.getName());
232 logger.info("Adding local instance " + dataSource.getName() + " as " + datasourceNCName);
233 addInstance(datasourceNCName, datasourceNCName);
234 }
235 }
236
237 public String toString(String instanceName, int port) {
238 return server + ":" + String.valueOf(port) + "/" + instanceName;
239 }
240
241 public CdmInstanceInfo getInstanceFromName(String instanceName) {
242 if(instanceName == null) {
243 return null;
244 }
245
246 for(CdmInstanceInfo instance : instances) {
247 if(instance.getName() != null && instance.getName().equals(instanceName)) {
248 return instance;
249 }
250 }
251 return null;
252 }
253
254 public CdmRemoteSource getCdmRemoteSource(CdmInstanceInfo instance, int port) {
255 if(instance != null) {
256 return CdmRemoteSource.NewInstance(name,
257 server,
258 port,
259 instance.getBasePath(),
260 null);
261 }
262 return null;
263 }
264
265 public boolean pingServer() {
266 if(isLocalhostMgd()) {
267 return true;
268 }
269 try {
270 Socket s = new Socket(server, port);
271 logger.info("[CDM-Server] Available @ " + server + ":" + port );
272 updateInfo();
273 return true;
274 } catch (IOException ioe) {
275
276 } catch (CDMServerException e) {
277
278 }
279 return false;
280 }
281
282 public boolean pingInstance(CdmInstanceInfo instance, int port) throws CDMServerException {
283
284 ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
285 try {
286 if(crs != null && crs.checkConnection()) {
287 logger.info("[CDM-Server] Running @ " + server + ":" + port + " for instance " + instance);
288 return true;
289 }
290 } catch (CdmSourceException e) {
291 throw new CDMServerException(e);
292 }
293
294 return false;
295 }
296
297 public int compareDbSchemaVersion(CdmInstanceInfo instance, int port) throws CDMServerException {
298
299 ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
300 String dbSchemaVersion;
301 try {
302 dbSchemaVersion = crs.getDbSchemaVersion();
303 } catch (CdmSourceException e) {
304 throw new CDMServerException(e);
305 }
306
307
308 if(dbSchemaVersion != null) {
309 return CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
310 } else {
311 throw new CDMServerException("Cannot determine editor db. schema version");
312 }
313 }
314
315 public int compareCdmlibServicesVersion() throws CdmSourceException {
316
317 String serverVersion = cdmlibServicesVersion;
318 String serverCdmlibLastModified = cdmlibServicesLastModified;
319 if(ignoreCdmLibVersion) {
320 return 0;
321 } else {
322 return compareCdmlibServicesVersion(serverVersion, serverCdmlibLastModified);
323 }
324 }
325
326
327 /**
328 * @param serverVersion
329 * @param editorVersion
330 * @throws CdmSourceException
331 */
332 public static int compareCdmlibServicesVersion(String serverVersion, String serverCdmlibLastModified) throws CdmSourceException {
333
334 String editorVersion = CdmApplicationState.getCdmlibVersion();
335 String editorCdmlibLastModified = CdmApplicationState.getCdmlibLastModified();
336
337 int result = 0;
338 if(StringUtils.isBlank(serverVersion) || StringUtils.isBlank(editorVersion)) {
339 throw new CdmSourceException("cdmlib-services server or editor version is empty");
340 }
341
342 String[] serverVersionSplit = serverVersion.split("\\.");
343 String[] editorVersionSplit = editorVersion.split("\\.");
344
345 if(serverVersionSplit.length < 3 || editorVersionSplit.length < 3 || serverVersionSplit.length > 4 || editorVersionSplit.length > 4) {
346 throw new CdmSourceException("cdmlib-services server or editor version is invalid");
347 }
348
349 Integer serverVersionPart;
350 Integer editorVersionPart;
351
352 for(int i=0 ; i<3 ; i++) {
353 serverVersionPart = Integer.valueOf(serverVersionSplit[i]);
354 editorVersionPart = Integer.valueOf(editorVersionSplit[i]);
355
356 int partCompare = serverVersionPart.compareTo(editorVersionPart);
357 if (partCompare != 0){
358 return partCompare;
359 }
360 }
361 // at this point major, minor and patch versions are matching
362
363 if(StringUtils.isBlank(serverCdmlibLastModified) || StringUtils.isBlank(editorCdmlibLastModified)) {
364 throw new CdmSourceException("cdmlib-services server or editor version is empty");
365 }
366
367 String cdmServerIgnoreVersion = System.getProperty("cdm.server.version.lm.ignore");
368 if(StringUtils.isBlank(cdmServerIgnoreVersion) || !cdmServerIgnoreVersion.equals("true")) {
369 Long serverLastModified = Long.valueOf(serverCdmlibLastModified);
370 Long editorLastModified = Long.valueOf(editorCdmlibLastModified);
371 return serverLastModified.compareTo(editorLastModified);
372 }
373
374 return 0;
375 }
376
377
378
379 public static List<CdmServerInfo> getCdmServers() {
380 if(cdmServerInfoList == null) {
381 cdmServerInfoList = new ArrayList<CdmServerInfo>();
382 // cdmServerInfoList.add(new CdmServerInfo(NAME_PRODUCTION, SERVER_PRODUCTION, 80, ""));
383 //cdmServerInfoList.add(new CdmServerInfo(NAME_INTEGRATION, SERVER_INTEGRATION, 80, CDMSERVER_PREFIX));
384 cdmServerInfoList.add(new CdmServerInfo(NAME_DEMO_1, SERVER_DEMO_1, 80, CDMSERVER_PREFIX, false));
385 // cdmServerInfoList.add(new CdmServerInfo(NAME_DEMO_2, SERVER_DEMO_2, 80, CDMSERVER_PREFIX));
386 cdmServerInfoList.add(new CdmServerInfo(NAME_TEST, SERVER_TEST, 80, CDMSERVER_PREFIX, false));
387 cdmServerInfoList.add(new CdmServerInfo(NAME_LOCALHOST, SERVER_LOCALHOST, 8080, CDMSERVER_PREFIX, true));
388 cdmServerInfoList.add(new CdmServerInfo(NAME_LOCALHOST_MGD, SERVER_LOCALHOST, NULL_PORT, CDMSERVER_PREFIX, false));
389 }
390 return cdmServerInfoList;
391 }
392
393 public String getName() {
394 return name;
395 }
396
397 public String getServer() {
398 return server;
399 }
400
401
402 public int getPort() {
403 return port;
404 }
405
406 public void setPort(int port) {
407 this.port = port;
408 }
409
410 public List<CdmInstanceInfo> getInstances() throws CDMServerException {
411 if(instances.isEmpty()) {
412 refreshInstances();
413 }
414 return instances;
415 }
416
417 public static CdmRemoteSource getDevServerRemoteSource() {
418 String value = System.getProperty("cdm.server.dev.port");
419 boolean available = false;
420 CdmInstanceInfo devInstance = null;
421 if(value != null && !value.isEmpty()) {
422 int devPort = Integer.valueOf(value);
423 CdmServerInfo devCii = new CdmServerInfo(NAME_LOCALHOST_DEV, SERVER_LOCALHOST_DEV, devPort, "", false);
424 try {
425 devInstance = devCii.addInstance(NAME_INSTANCE_LOCALHOST_DEV, BASEPATH_LOCALHOST_DEV);
426 available = devCii.pingInstance(devInstance, devPort);
427 if(available) {
428 return devCii.getCdmRemoteSource(devInstance, devPort);
429 }
430 } catch (Exception e) {
431
432 }
433 }
434 return null;
435 }
436
437 public class CdmInstanceInfo {
438 private final String name;
439
440 /**
441 * The full path of the instance including the the prefix (if any).
442 * E.g. for an EDIT instance this would be something like "cdmserver/remoting"
443 * For a managed local server this would simply be ""
444 */
445 private final String basePath;
446
447
448 public CdmInstanceInfo(String name, String basePath) {
449 this.name = name;
450 this.basePath = basePath;
451 }
452
453
454 public String getName() {
455 return name;
456 }
457
458 public String getBasePath() {
459 return basePath;
460 }
461 }
462 }