3 * Copyright (C) 2015 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.taxeditor
.remoting
.source
;
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
;
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
;
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
;
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
;
58 public class CdmServerInfo
{
59 public static final Logger logger
= Logger
.getLogger(CdmServerInfo
.class);
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";
65 private final static String NAME_DEMO_1
= "edit-WS I";
66 private final static String SERVER_DEMO_1
= "160.45.63.230";
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.";
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
= "";
77 public final static int NULL_PORT
= -1;
78 public final static String NULL_PORT_STRING
= "N/A";
80 private static final String CDM_REMOTE_SERVERS_CONFIG_FILE
= "cdm_remote_servers.json";
83 private final String name
;
84 private final String server
;
86 private final List
<CdmInstanceInfo
> instances
;
88 private String cdmlibServicesVersion
= "";
89 private String cdmlibServicesLastModified
= "";
91 private String prefix
= "";
93 private boolean ignoreCdmLibVersion
= false;
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
>();
106 public CdmInstanceInfo
addInstance(String name
, String basePath
) {
107 String _basePath
= basePath
;
108 if(isLocalhostMgd()) {
111 CdmInstanceInfo cii
= new CdmInstanceInfo(name
, _basePath
);
117 public boolean isLocalhost() {
118 return name
.startsWith(SERVER_LOCALHOST
);
121 public boolean isLocalhostMgd() {
122 return NAME_LOCALHOST_MGD
.equals(name
);
125 public String
getCdmlibServicesVersion() {
126 return cdmlibServicesVersion
;
129 public String
getCdmlibLastModified() {
130 return cdmlibServicesLastModified
;
133 public void refreshInstances() throws CDMServerException
{
135 if(isLocalhostMgd()) {
136 addInstancesFromDataSourcesConfig();
138 addInstancesViaHttp();
140 Collections
.sort(instances
, new Comparator
<CdmInstanceInfo
>() {
142 public int compare(CdmInstanceInfo cii1
, CdmInstanceInfo cii2
)
144 return cii1
.getName().toString().compareTo(cii2
.getName().toString());
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) {
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
);
163 public void addInstancesViaHttp() throws CDMServerException
{
165 String url
= "http://" + server
+ ":" + String
.valueOf(port
) + "/" + prefix
+ "instances.jsp";
166 String responseBody
= getResponse(url
);
167 if(responseBody
!= null) {
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");
175 String instanceName
= conf
.getString("instanceName");
176 // we need to remove the first (char) forward slash from
178 String basePath
= conf
.getString("basePath").substring(1);
179 addInstance(instanceName
, basePath
);
180 logger
.info("Added instance with name : " + instanceName
+ ", basePath : " + basePath
);
184 } catch (JSONException e
) {
185 throw new CDMServerException(e
);
190 private String
getResponse(String url
) throws CDMServerException
{
191 HttpClient client
= new DefaultHttpClient();
192 HttpParams params
= client
.getParams();
194 HttpConnectionParams
.setConnectionTimeout(params
, 5000);
195 HttpConnectionParams
.setSoTimeout(params
, 5000);
197 HttpGet httpGet
= new HttpGet(url
);
199 logger
.info("Executing request " + httpGet
.getRequestLine());
201 // Create a custom response handler
202 ResponseHandler
<String
> responseHandler
= new ResponseHandler
<String
>() {
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;
212 throw new ClientProtocolException("Unexpected response status: " + status
);
217 String responseBody
= null;
219 responseBody
= client
.execute(httpGet
, responseHandler
);
220 } catch (ClientProtocolException e
) {
221 throw new CDMServerException(e
);
222 } catch (IOException e
) {
223 throw new CDMServerException(e
);
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
);
236 public String
toString(String instanceName
, int port
) {
237 return server
+ ":" + String
.valueOf(port
) + "/" + instanceName
;
240 public CdmInstanceInfo
getInstanceFromName(String instanceName
) {
241 if(instanceName
== null) {
245 for(CdmInstanceInfo instance
: instances
) {
246 if(instance
.getName() != null && instance
.getName().equals(instanceName
)) {
253 public CdmRemoteSource
getCdmRemoteSource(CdmInstanceInfo instance
, int port
) {
254 if(instance
!= null) {
255 return CdmRemoteSource
.NewInstance(name
,
258 instance
.getBasePath(),
264 public boolean pingServer() {
265 if(isLocalhostMgd()) {
269 Socket s
= new Socket(server
, port
);
270 logger
.info("[CDM-Server] Available @ " + server
+ ":" + port
);
273 } catch (IOException ioe
) {
275 } catch (CDMServerException e
) {
281 public boolean pingInstance(CdmInstanceInfo instance
, int port
) throws CDMServerException
{
283 ICdmRemoteSource crs
= getCdmRemoteSource(instance
, port
);
285 if(crs
!= null && crs
.checkConnection()) {
286 logger
.info("[CDM-Server] Running @ " + server
+ ":" + port
+ " for instance " + instance
);
289 } catch (CdmSourceException e
) {
290 throw new CDMServerException(e
);
296 public int compareDbSchemaVersion(CdmInstanceInfo instance
, int port
) throws CDMServerException
{
298 ICdmRemoteSource crs
= getCdmRemoteSource(instance
, port
);
299 String dbSchemaVersion
;
301 dbSchemaVersion
= crs
.getDbSchemaVersion();
302 } catch (CdmSourceException e
) {
303 throw new CDMServerException(e
);
307 if(dbSchemaVersion
!= null) {
308 return CdmMetaData
.compareVersion(dbSchemaVersion
, CdmMetaData
.getDbSchemaVersion(), 3, null);
310 throw new CDMServerException("Cannot determine editor db. schema version");
314 public int compareCdmlibServicesVersion() throws CdmSourceException
{
316 String serverVersion
= cdmlibServicesVersion
;
317 String serverCdmlibLastModified
= cdmlibServicesLastModified
;
318 if(ignoreCdmLibVersion
) {
321 return compareCdmlibServicesVersion(serverVersion
, serverCdmlibLastModified
);
327 * @param serverVersion
328 * @param editorVersion
329 * @throws CdmSourceException
331 public static int compareCdmlibServicesVersion(String serverVersion
, String serverCdmlibLastModified
) throws CdmSourceException
{
333 String editorVersion
= CdmApplicationState
.getCdmlibVersion();
334 String editorCdmlibLastModified
= CdmApplicationState
.getCdmlibLastModified();
337 if(StringUtils
.isBlank(serverVersion
) || StringUtils
.isBlank(editorVersion
)) {
338 throw new CdmSourceException("cdmlib-services server or editor version is empty");
341 String
[] serverVersionSplit
= serverVersion
.split("\\.");
342 String
[] editorVersionSplit
= editorVersion
.split("\\.");
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");
348 Integer serverVersionPart
;
349 Integer editorVersionPart
;
351 for(int i
=0 ; i
<3 ; i
++) {
352 serverVersionPart
= Integer
.valueOf(serverVersionSplit
[i
]);
353 editorVersionPart
= Integer
.valueOf(editorVersionSplit
[i
]);
355 int partCompare
= serverVersionPart
.compareTo(editorVersionPart
);
356 if (partCompare
!= 0){
360 // at this point major, minor and patch versions are matching
362 if(StringUtils
.isBlank(serverCdmlibLastModified
) || StringUtils
.isBlank(editorCdmlibLastModified
)) {
363 throw new CdmSourceException("cdmlib-services server or editor version is empty");
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
);
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
));
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
;
393 * @throws IOException
394 * @throws FileNotFoundException
395 * @throws JsonMappingException
396 * @throws JsonParseException
398 private static List
<CdmServerInfoConfig
> loadFromConfigFile(File file
) {
400 List
<CdmServerInfoConfig
> serverList
= null;
402 ObjectMapper mapper
= new ObjectMapper();
405 logger
.info("The remote server config file '" + file
.getAbsolutePath() +
406 "' does not yet exist, it will be created based on the defaults.");
408 serverList
= createDefaultServerConfigList();
409 mapper
.writerWithDefaultPrettyPrinter().writeValue(new FileOutputStream(file
), serverList
);
411 } catch (IOException e
) {
412 throw new RuntimeException(e
);
416 serverList
= mapper
.readValue(new FileInputStream(file
), new TypeReference
<List
<CdmServerInfoConfig
>>(){});
417 } catch (IOException e
) {
418 throw new RuntimeException(e
);
431 private static List
<CdmServerInfoConfig
> createDefaultServerConfigList() {
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
;
440 public String
getName() {
444 public String
getServer() {
449 public int getPort() {
453 public void setPort(int port
) {
457 public List
<CdmInstanceInfo
> getInstances() throws CDMServerException
{
458 if(instances
.isEmpty()) {
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));
472 devInstance
= devCii
.addInstance(NAME_INSTANCE_LOCALHOST_DEV
, BASEPATH_LOCALHOST_DEV
);
473 available
= devCii
.pingInstance(devInstance
, devPort
);
475 return devCii
.getCdmRemoteSource(devInstance
, devPort
);
477 } catch (Exception e
) {
484 public class CdmInstanceInfo
{
485 private final String name
;
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 ""
492 private final String basePath
;
495 public CdmInstanceInfo(String name
, String basePath
) {
497 this.basePath
= basePath
;
501 public String
getName() {
505 public String
getBasePath() {