ref #3658 remove nomenclatural code from datasources
[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.File;
13 import java.io.FileInputStream;
14 import java.io.FileNotFoundException;
15 import java.io.FileOutputStream;
16 import java.io.IOException;
17 import java.net.Socket;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.List;
22
23 import org.apache.commons.lang.StringUtils;
24 import org.apache.http.HttpEntity;
25 import org.apache.http.HttpResponse;
26 import org.apache.http.client.ClientProtocolException;
27 import org.apache.http.client.HttpClient;
28 import org.apache.http.client.ResponseHandler;
29 import org.apache.http.client.methods.HttpGet;
30 import org.apache.http.impl.client.DefaultHttpClient;
31 import org.apache.http.params.HttpConnectionParams;
32 import org.apache.http.params.HttpParams;
33 import org.apache.http.util.EntityUtils;
34 import org.apache.log4j.Logger;
35 import org.json.JSONArray;
36 import org.json.JSONException;
37 import org.json.JSONObject;
38
39 import com.fasterxml.jackson.core.JsonParseException;
40 import com.fasterxml.jackson.core.type.TypeReference;
41 import com.fasterxml.jackson.databind.JsonMappingException;
42 import com.fasterxml.jackson.databind.ObjectMapper;
43
44 import eu.etaxonomy.cdm.api.application.CdmApplicationState;
45 import eu.etaxonomy.cdm.common.CdmUtils;
46 import eu.etaxonomy.cdm.config.CdmSourceException;
47 import eu.etaxonomy.cdm.database.CdmPersistentDataSource;
48 import eu.etaxonomy.cdm.database.ICdmDataSource;
49 import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
50 import eu.etaxonomy.taxeditor.remoting.server.CDMServerException;
51 import eu.etaxonomy.taxeditor.remoting.server.CDMServerUtils;
52
53 /**
54 * @author cmathew
55 * @date 20 Jan 2015
56 *
57 */
58 public class CdmServerInfo {
59 public static final Logger logger = Logger.getLogger(CdmServerInfo.class);
60
61 private final static String CDMSERVER_PREFIX = "cdmserver/";
62 private final static String NAME_PRODUCTION = "cybertaxonomy.org";
63 private final static String SERVER_PRODUCTION = "api.cybertaxonomy.org";
64
65 private final static String NAME_DEMO_1 = "edit-WS I";
66 private final static String SERVER_DEMO_1 = "160.45.63.230";
67
68 public final static String SERVER_LOCALHOST = "localhost";
69 private final static String NAME_LOCALHOST = "localhost";
70 public final static String NAME_LOCALHOST_MGD = "localhost mgd.";
71
72 private final static String NAME_LOCALHOST_DEV = "localhost-dev";
73 private final static String NAME_INSTANCE_LOCALHOST_DEV = "local-dev";
74 private final static String SERVER_LOCALHOST_DEV = "localhost";
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 private static final String CDM_REMOTE_SERVERS_CONFIG_FILE = "cdm_remote_servers.json";
81
82
83 private final String name;
84 private final String server;
85 private int port;
86 private final List<CdmInstanceInfo> instances;
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(CdmServerInfoConfig parameterObject) {
97 this.name = parameterObject.getName();
98 this.server = parameterObject.getServer();
99 this.port = parameterObject.getPort();
100 this.prefix = parameterObject.getPrefix();
101 this.ignoreCdmLibVersion = parameterObject.isIgnoreCdmLibVersion();
102 instances = new ArrayList<CdmInstanceInfo>();
103 }
104
105
106 public CdmInstanceInfo addInstance(String name, String basePath) {
107 String _basePath = basePath;
108 if(isLocalhostMgd()) {
109 _basePath = "";
110 }
111 CdmInstanceInfo cii = new CdmInstanceInfo(name, _basePath);
112 instances.add(cii);
113 return cii;
114
115 }
116
117 public boolean isLocalhost() {
118 return name.startsWith(SERVER_LOCALHOST);
119 }
120
121 public boolean isLocalhostMgd() {
122 return NAME_LOCALHOST_MGD.equals(name);
123 }
124
125 public String getCdmlibServicesVersion() {
126 return cdmlibServicesVersion;
127 }
128
129 public String getCdmlibLastModified() {
130 return cdmlibServicesLastModified;
131 }
132
133 public void refreshInstances() throws CDMServerException {
134 instances.clear();
135 if(isLocalhostMgd()) {
136 addInstancesFromDataSourcesConfig();
137 } else {
138 addInstancesViaHttp();
139 }
140 Collections.sort(instances, new Comparator<CdmInstanceInfo>() {
141 @Override
142 public int compare(CdmInstanceInfo cii1, CdmInstanceInfo cii2)
143 {
144 return cii1.getName().toString().compareTo(cii2.getName().toString());
145 }
146 });
147 }
148
149 public void updateInfo() throws CDMServerException {
150 String url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "info.jsp";
151 String responseBody = getResponse(url);
152 if(responseBody != null) {
153 try {
154 JSONObject info = new JSONObject(responseBody);
155 cdmlibServicesVersion = info.getString("cdmlibServicesVersion");
156 cdmlibServicesLastModified = info.getString("cdmlibServicesLastModified");
157 } catch (JSONException e) {
158 throw new CDMServerException(e);
159 }
160 }
161 }
162
163 public void addInstancesViaHttp() throws CDMServerException {
164 updateInfo();
165 String url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "instances.jsp";
166 String responseBody = getResponse(url);
167 if(responseBody != null) {
168 try {
169 JSONArray array = new JSONArray(responseBody);
170 for(int i=0;i<array.length();i++) {
171 JSONObject instance = (JSONObject)array.get(i);
172 if(instance != null) {
173 JSONObject conf = (JSONObject)instance.get("configuration");
174 if(conf != null) {
175 String instanceName = conf.getString("instanceName");
176 // we need to remove the first (char) forward slash from
177 // the base path
178 String basePath = conf.getString("basePath").substring(1);
179 addInstance(instanceName, basePath);
180 logger.info("Added instance with name : " + instanceName + ", basePath : " + basePath);
181 }
182 }
183 }
184 } catch (JSONException e) {
185 throw new CDMServerException(e);
186 }
187 }
188 }
189
190 private String getResponse(String url) throws CDMServerException {
191 HttpClient client = new DefaultHttpClient();
192 HttpParams params = client.getParams();
193
194 HttpConnectionParams.setConnectionTimeout(params, 5000);
195 HttpConnectionParams.setSoTimeout(params, 5000);
196
197 HttpGet httpGet = new HttpGet(url);
198
199 logger.info("Executing request " + httpGet.getRequestLine());
200
201 // Create a custom response handler
202 ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
203
204 @Override
205 public String handleResponse(
206 final HttpResponse response) throws ClientProtocolException, IOException {
207 int status = response.getStatusLine().getStatusCode();
208 if (status >= 200 && status < 300) {
209 HttpEntity entity = response.getEntity();
210 return entity != null ? EntityUtils.toString(entity) : null;
211 } else {
212 throw new ClientProtocolException("Unexpected response status: " + status);
213 }
214 }
215
216 };
217 String responseBody = null;
218 try {
219 responseBody = client.execute(httpGet, responseHandler);
220 } catch (ClientProtocolException e) {
221 throw new CDMServerException(e);
222 } catch (IOException e) {
223 throw new CDMServerException(e);
224 }
225 return responseBody;
226 }
227
228 public void addInstancesFromDataSourcesConfig() {
229 for(ICdmDataSource dataSource : CdmPersistentDataSource.getAllDataSources()){
230 String datasourceNCName = CDMServerUtils.xmlNCNamefrom(dataSource.getName());
231 logger.info("Adding local instance " + dataSource.getName() + " as " + datasourceNCName);
232 addInstance(datasourceNCName, datasourceNCName);
233 }
234 }
235
236 public String toString(String instanceName, int port) {
237 return server + ":" + String.valueOf(port) + "/" + instanceName;
238 }
239
240 public CdmInstanceInfo getInstanceFromName(String instanceName) {
241 if(instanceName == null) {
242 return null;
243 }
244
245 for(CdmInstanceInfo instance : instances) {
246 if(instance.getName() != null && instance.getName().equals(instanceName)) {
247 return instance;
248 }
249 }
250 return null;
251 }
252
253 public CdmRemoteSource getCdmRemoteSource(CdmInstanceInfo instance, int port) {
254 if(instance != null) {
255 return CdmRemoteSource.NewInstance(name,
256 server,
257 port,
258 instance.getBasePath()
259 );
260 }
261 return null;
262 }
263
264 public boolean pingServer() {
265 if(isLocalhostMgd()) {
266 return true;
267 }
268 try {
269 Socket s = new Socket(server, port);
270 logger.info("[CDM-Server] Available @ " + server + ":" + port );
271 updateInfo();
272 return true;
273 } catch (IOException ioe) {
274
275 } catch (CDMServerException e) {
276
277 }
278 return false;
279 }
280
281 public boolean pingInstance(CdmInstanceInfo instance, int port) throws CDMServerException {
282
283 ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
284 try {
285 if(crs != null && crs.checkConnection()) {
286 logger.info("[CDM-Server] Running @ " + server + ":" + port + " for instance " + instance);
287 return true;
288 }
289 } catch (CdmSourceException e) {
290 throw new CDMServerException(e);
291 }
292
293 return false;
294 }
295
296 public int compareDbSchemaVersion(CdmInstanceInfo instance, int port) throws CDMServerException {
297
298 ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
299 String dbSchemaVersion;
300 try {
301 dbSchemaVersion = crs.getDbSchemaVersion();
302 } catch (CdmSourceException e) {
303 throw new CDMServerException(e);
304 }
305
306
307 if(dbSchemaVersion != null) {
308 return CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
309 } else {
310 throw new CDMServerException("Cannot determine editor db. schema version");
311 }
312 }
313
314 public int compareCdmlibServicesVersion() throws CdmSourceException {
315
316 String serverVersion = cdmlibServicesVersion;
317 String serverCdmlibLastModified = cdmlibServicesLastModified;
318 if(ignoreCdmLibVersion) {
319 return 0;
320 } else {
321 return compareCdmlibServicesVersion(serverVersion, serverCdmlibLastModified);
322 }
323 }
324
325
326 /**
327 * @param serverVersion
328 * @param editorVersion
329 * @throws CdmSourceException
330 */
331 public static int compareCdmlibServicesVersion(String serverVersion, String serverCdmlibLastModified) throws CdmSourceException {
332
333 String editorVersion = CdmApplicationState.getCdmlibVersion();
334 String editorCdmlibLastModified = CdmApplicationState.getCdmlibLastModified();
335
336 int result = 0;
337 if(StringUtils.isBlank(serverVersion) || StringUtils.isBlank(editorVersion)) {
338 throw new CdmSourceException("cdmlib-services server or editor version is empty");
339 }
340
341 String[] serverVersionSplit = serverVersion.split("\\.");
342 String[] editorVersionSplit = editorVersion.split("\\.");
343
344 if(serverVersionSplit.length < 3 || editorVersionSplit.length < 3 || serverVersionSplit.length > 4 || editorVersionSplit.length > 4) {
345 throw new CdmSourceException("cdmlib-services server or editor version is invalid");
346 }
347
348 Integer serverVersionPart;
349 Integer editorVersionPart;
350
351 for(int i=0 ; i<3 ; i++) {
352 serverVersionPart = Integer.valueOf(serverVersionSplit[i]);
353 editorVersionPart = Integer.valueOf(editorVersionSplit[i]);
354
355 int partCompare = serverVersionPart.compareTo(editorVersionPart);
356 if (partCompare != 0){
357 return partCompare;
358 }
359 }
360 // at this point major, minor and patch versions are matching
361
362 if(StringUtils.isBlank(serverCdmlibLastModified) || StringUtils.isBlank(editorCdmlibLastModified)) {
363 throw new CdmSourceException("cdmlib-services server or editor version is empty");
364 }
365
366 String cdmServerIgnoreVersion = System.getProperty("cdm.server.version.lm.ignore");
367 if(StringUtils.isBlank(cdmServerIgnoreVersion) || !cdmServerIgnoreVersion.equals("true")) {
368 Long serverLastModified = Long.valueOf(serverCdmlibLastModified);
369 Long editorLastModified = Long.valueOf(editorCdmlibLastModified);
370 return serverLastModified.compareTo(editorLastModified);
371 }
372
373 return result;
374 }
375
376
377
378 public static List<CdmServerInfo> getCdmServers() {
379 List<CdmServerInfoConfig> configList = loadFromConfigFile(new File(CdmUtils.perUserCdmFolder, CDM_REMOTE_SERVERS_CONFIG_FILE));
380 List<CdmServerInfo> serverInfoList = new ArrayList<CdmServerInfo>(configList.size());
381 for(CdmServerInfoConfig config : configList) {
382 serverInfoList.add(new CdmServerInfo(config));
383 }
384 // The local host managed server must not be in the config file
385 CdmServerInfoConfig localHostManagedConfig = new CdmServerInfoConfig(NAME_LOCALHOST_MGD, SERVER_LOCALHOST, NULL_PORT, CDMSERVER_PREFIX, false);
386 serverInfoList.add(new CdmServerInfo(localHostManagedConfig));
387 return serverInfoList;
388 }
389
390
391 /**
392 * @param file
393 * @throws IOException
394 * @throws FileNotFoundException
395 * @throws JsonMappingException
396 * @throws JsonParseException
397 */
398 private static List<CdmServerInfoConfig> loadFromConfigFile(File file) {
399
400 List<CdmServerInfoConfig> serverList = null;
401
402 ObjectMapper mapper = new ObjectMapper();
403
404 if(!file.exists()) {
405 logger.info("The remote server config file '" + file.getAbsolutePath() +
406 "' does not yet exist, it will be created based on the defaults.");
407 try {
408 serverList = createDefaultServerConfigList();
409 mapper.writerWithDefaultPrettyPrinter().writeValue(new FileOutputStream(file), serverList);
410
411 } catch (IOException e) {
412 throw new RuntimeException(e);
413 }
414 } else {
415 try {
416 serverList = mapper.readValue(new FileInputStream(file), new TypeReference<List<CdmServerInfoConfig>>(){});
417 } catch (IOException e) {
418 throw new RuntimeException(e);
419 }
420 }
421
422 return serverList;
423
424
425 }
426
427
428 /**
429 *
430 */
431 private static List<CdmServerInfoConfig> createDefaultServerConfigList() {
432
433 List<CdmServerInfoConfig> serverInfoList = new ArrayList<CdmServerInfoConfig>();
434 serverInfoList.add(new CdmServerInfoConfig(NAME_PRODUCTION, SERVER_PRODUCTION, 80, "", false));
435 serverInfoList.add(new CdmServerInfoConfig(NAME_DEMO_1, SERVER_DEMO_1, 80, CDMSERVER_PREFIX, false));
436 serverInfoList.add(new CdmServerInfoConfig(NAME_LOCALHOST, SERVER_LOCALHOST, 8080, CDMSERVER_PREFIX, true));
437 return serverInfoList;
438 }
439
440 public String getName() {
441 return name;
442 }
443
444 public String getServer() {
445 return server;
446 }
447
448
449 public int getPort() {
450 return port;
451 }
452
453 public void setPort(int port) {
454 this.port = port;
455 }
456
457 public List<CdmInstanceInfo> getInstances() throws CDMServerException {
458 if(instances.isEmpty()) {
459 refreshInstances();
460 }
461 return instances;
462 }
463
464 public static CdmRemoteSource getDevServerRemoteSource() {
465 String value = System.getProperty("cdm.server.dev.port");
466 boolean available = false;
467 CdmInstanceInfo devInstance = null;
468 if(value != null && !value.isEmpty()) {
469 int devPort = Integer.valueOf(value);
470 CdmServerInfo devCii = new CdmServerInfo(new CdmServerInfoConfig(NAME_LOCALHOST_DEV, SERVER_LOCALHOST_DEV, devPort, "", false));
471 try {
472 devInstance = devCii.addInstance(NAME_INSTANCE_LOCALHOST_DEV, BASEPATH_LOCALHOST_DEV);
473 available = devCii.pingInstance(devInstance, devPort);
474 if(available) {
475 return devCii.getCdmRemoteSource(devInstance, devPort);
476 }
477 } catch (Exception e) {
478
479 }
480 }
481 return null;
482 }
483
484 public class CdmInstanceInfo {
485 private final String name;
486
487 /**
488 * The full path of the instance including the the prefix (if any).
489 * E.g. for an EDIT instance this would be something like "cdmserver/remoting"
490 * For a managed local server this would simply be ""
491 */
492 private final String basePath;
493
494
495 public CdmInstanceInfo(String name, String basePath) {
496 this.name = name;
497 this.basePath = basePath;
498 }
499
500
501 public String getName() {
502 return name;
503 }
504
505 public String getBasePath() {
506 return basePath;
507 }
508 }
509 }