Merge branch 'release/5.18.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.cdmlib / src / main / java / eu / etaxonomy / taxeditor / remoting / source / CdmServerInfo.java
index 28e6446b29d963d1fec667167159dc73810d607e..3ce4c8e3abc9b1ad71bec8651e9e6ca8ee8a7653 100644 (file)
@@ -1,4 +1,3 @@
-// $Id$
 /**
  * Copyright (C) 2015 EDIT
  * European Distributed Institute of Taxonomy
@@ -11,69 +10,59 @@ package eu.etaxonomy.taxeditor.remoting.source;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
 import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.util.EntityUtils;
 import org.apache.log4j.Logger;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteConfiguration;
 import eu.etaxonomy.cdm.api.application.CdmApplicationState;
-import eu.etaxonomy.cdm.common.CdmUtils;
 import eu.etaxonomy.cdm.config.CdmSourceException;
+import eu.etaxonomy.cdm.config.ConfigFileUtil;
+import eu.etaxonomy.cdm.config.ICdmSource;
 import eu.etaxonomy.cdm.database.CdmPersistentDataSource;
 import eu.etaxonomy.cdm.database.ICdmDataSource;
 import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
-import eu.etaxonomy.taxeditor.remoting.server.CDMServerException;
-import eu.etaxonomy.taxeditor.remoting.server.CDMServerUtils;
+import eu.etaxonomy.taxeditor.remoting.server.CdmServerException;
+import eu.etaxonomy.taxeditor.remoting.server.CdmServerUtils;
 
 /**
  * @author cmathew
  * @date 20 Jan 2015
- *
  */
 public class CdmServerInfo {
+
     public static final Logger logger = Logger.getLogger(CdmServerInfo.class);
 
-    private final static String CDMSERVER_PREFIX = "cdmserver/";
+    protected final static String CDMSERVER_PREFIX = "cdmserver/";
     private final static String NAME_PRODUCTION = "cybertaxonomy.org";
     private final static String SERVER_PRODUCTION = "api.cybertaxonomy.org";
 
-    private final static String NAME_INTEGRATION = "edit-integration";
-    private final static String SERVER_INTEGRATION = "int.e-taxonomy.eu";
-
-    private final static String NAME_DEMO_1 = "edit-WS I";
+    private final static String NAME_DEMO_1 = "demo I";
     private final static String SERVER_DEMO_1 = "160.45.63.230";
 
-    private final static String NAME_DEMO_2 = "edit-WS II";
-    private final static String SERVER_DEMO_2 = "160.45.63.231";
-
-    private final static String NAME_TEST = "edit-test";
-    private final static String SERVER_TEST = "test.e-taxonomy.eu";
-
     public final static String SERVER_LOCALHOST = "localhost";
     private final static String NAME_LOCALHOST = "localhost";
     public final static String NAME_LOCALHOST_MGD = "localhost mgd.";
@@ -81,19 +70,18 @@ public class CdmServerInfo {
     private final static String NAME_LOCALHOST_DEV = "localhost-dev";
     private final static String NAME_INSTANCE_LOCALHOST_DEV = "local-dev";
     private final static String SERVER_LOCALHOST_DEV = "localhost";
-    private final static int PORT_LOCALHOST_DEV = 8080;
     private final static String BASEPATH_LOCALHOST_DEV = "";
 
     public final static int NULL_PORT = -1;
     public final static String NULL_PORT_STRING = "N/A";
 
-    private static final String CDM_REMOTE_SERVERS_CONFIG_FILE = "cdm_remote_servers.json";
+    protected static final String CDM_REMOTE_SERVERS_CONFIG_FILE = "cdm_remote_servers.json";
 
 
     private final String name;
     private final String server;
     private int port;
-    private final List<CdmInstanceInfo> instances;
+    protected final List<CdmInstanceInfo> instances;
 
     private String cdmlibServicesVersion = "";
     private String cdmlibServicesLastModified = "";
@@ -109,19 +97,19 @@ public class CdmServerInfo {
         this.port = parameterObject.getPort();
         this.prefix = parameterObject.getPrefix();
         this.ignoreCdmLibVersion = parameterObject.isIgnoreCdmLibVersion();
-        instances = new ArrayList<CdmInstanceInfo>();
+        this.instances = new ArrayList<>();
     }
 
+    public CdmInstanceInfo addInstance(String name, ICdmDataSource dataSource) {
+        CdmInstanceInfo cii = new CdmInstanceInfo(name, dataSource);
+        instances.add(cii);
+        return cii;
+    }
 
     public CdmInstanceInfo addInstance(String name, String basePath) {
-        String _basePath = basePath;
-        if(isLocalhostMgd()) {
-            _basePath = "";
-        }
-        CdmInstanceInfo cii = new CdmInstanceInfo(name, _basePath);
+        CdmInstanceInfo cii = new CdmInstanceInfo(name, basePath);
         instances.add(cii);
         return cii;
-
     }
 
     public boolean isLocalhost() {
@@ -140,24 +128,26 @@ public class CdmServerInfo {
         return cdmlibServicesLastModified;
     }
 
-    public void refreshInstances() throws CDMServerException {
+    public void refreshInstances() throws CdmServerException {
         instances.clear();
         if(isLocalhostMgd()) {
             addInstancesFromDataSourcesConfig();
         } else {
             addInstancesViaHttp();
         }
+
+
         Collections.sort(instances, new Comparator<CdmInstanceInfo>() {
             @Override
-            public int compare(CdmInstanceInfo cii1, CdmInstanceInfo cii2)
-            {
+            public int compare(CdmInstanceInfo cii1, CdmInstanceInfo cii2){
                 return cii1.getName().toString().compareTo(cii2.getName().toString());
             }
         });
     }
 
-    public void updateInfo() throws CDMServerException {
-        String url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "info.jsp";
+    public void updateInfo() throws CdmServerException {
+
+        String url = guessProtocol() + "://" + server + ":" + String.valueOf(port) + "/" + prefix + "info.jsp";
         String responseBody = getResponse(url);
         if(responseBody != null) {
             try {
@@ -165,14 +155,18 @@ public class CdmServerInfo {
                 cdmlibServicesVersion =  info.getString("cdmlibServicesVersion");
                 cdmlibServicesLastModified = info.getString("cdmlibServicesLastModified");
             } catch (JSONException e) {
-                throw new CDMServerException(e);
+                throw new CdmServerException(e);
             }
         }
     }
 
-    public void addInstancesViaHttp() throws CDMServerException {
+    String guessProtocol() {
+        return port == 443 ? "https" : "http";
+    }
+
+    public void addInstancesViaHttp() throws CdmServerException {
         updateInfo();
-        String url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "instances.jsp";
+        String url = guessProtocol() + "://" + server + ":" + String.valueOf(port) + "/" + prefix + "instances.jsp";
         String responseBody = getResponse(url);
         if(responseBody != null) {
             try {
@@ -192,17 +186,18 @@ public class CdmServerInfo {
                     }
                 }
             } catch (JSONException e) {
-                throw new CDMServerException(e);
+                throw new CdmServerException(e);
             }
         }
     }
 
-    private String getResponse(String url) throws CDMServerException {
-        HttpClient client = new DefaultHttpClient();
-        HttpParams params = client.getParams();
+    private String getResponse(String url) throws CdmServerException {
 
-        HttpConnectionParams.setConnectionTimeout(params, 5000);
-        HttpConnectionParams.setSoTimeout(params, 5000);
+        RequestConfig.Builder requestBuilder = RequestConfig.custom();
+        requestBuilder.setConnectTimeout(CdmApplicationRemoteConfiguration.HTTP_READ_TIMEOUT_MIN);
+        requestBuilder.setConnectionRequestTimeout(CdmApplicationRemoteConfiguration.HTTP_READ_TIMEOUT_MIN);
+        requestBuilder.setSocketTimeout(CdmApplicationRemoteConfiguration.HTTP_READ_TIMEOUT_MIN);
+        CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(requestBuilder.build()).build();
 
         HttpGet httpGet = new HttpGet(url);
 
@@ -228,18 +223,25 @@ public class CdmServerInfo {
         try {
             responseBody = client.execute(httpGet, responseHandler);
         } catch (ClientProtocolException e) {
-            throw new CDMServerException(e);
-        } catch (IOException e) {
-            throw new CDMServerException(e);
+            throw new CdmServerException(e);
+        } catch (IOException e) { // java.net.ConnectException: Connection refused, java.net.SocketTimeoutException: Read timed out
+            throw new CdmServerException(e);
+        } finally{
+            try {
+                client.close();
+                client = null;
+            } catch (IOException e) {
+                // IGNORE //
+            }
         }
         return responseBody;
     }
 
     public void addInstancesFromDataSourcesConfig() {
         for(ICdmDataSource dataSource : CdmPersistentDataSource.getAllDataSources()){
-            String datasourceNCName = CDMServerUtils.xmlNCNamefrom(dataSource.getName());
+            String datasourceNCName = CdmServerUtils.xmlNCNamefrom(dataSource.getName());
             logger.info("Adding local instance " + dataSource.getName() + " as " + datasourceNCName);
-            addInstance(datasourceNCName, datasourceNCName);
+            addInstance(datasourceNCName, dataSource);
         }
     }
 
@@ -260,64 +262,67 @@ public class CdmServerInfo {
         return null;
     }
 
-    public CdmRemoteSource getCdmRemoteSource(CdmInstanceInfo instance, int port) {
+    public ICdmRemoteSource getCdmRemoteSource(CdmInstanceInfo instance, int port) {
         if(instance != null) {
-            return CdmRemoteSource.NewInstance(name,
-                    server,
-                    port,
-                    instance.getBasePath(),
-                    null);
+            if (instance.getDataSource()!=null){
+                return CdmRemoteLocalhostSource.NewInstance(name,
+                        server,
+                        port,
+                        instance.getDataSource(),
+                        instance.name
+                        );
+            }else{
+                return CdmRemoteSource.NewInstance(name,
+                        server,
+                        port,
+                        instance.getBasePath()
+                        );
+            }
         }
         return null;
     }
 
-    public boolean pingServer() {
+    public boolean pingServer() throws CdmServerException, IOException {
         if(isLocalhostMgd()) {
             return true;
         }
-        try {
-            Socket s = new Socket(server, port);
-            logger.info("[CDM-Server] Available @ " + server + ":" + port );
-            updateInfo();
-            return true;
-        } catch (IOException ioe) {
-
-        } catch (CDMServerException e) {
-
-        }
-        return false;
+        Socket s = new Socket();
+        s.connect(new InetSocketAddress(server, port), CdmApplicationRemoteConfiguration.HTTP_READ_TIMEOUT_MIN);
+        s.close();
+        logger.info("[CDM-Server] Available @ " + server + ":" + port );
+        updateInfo();
+        return true;
     }
 
-    public boolean pingInstance(CdmInstanceInfo instance, int port) throws CDMServerException  {
-
-        ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
+    public boolean pingInstance(CdmInstanceInfo instance, int port) throws CdmServerException  {
+        ICdmSource cdmRemoteSource = getCdmRemoteSource(instance, port);
         try {
-            if(crs != null && crs.checkConnection()) {
+            if(cdmRemoteSource != null && cdmRemoteSource.checkConnection()) {
                 logger.info("[CDM-Server] Running @ " + server + ":" + port + " for instance " + instance);
                 return true;
             }
         } catch (CdmSourceException e) {
-            throw new CDMServerException(e);
+            logger.error(e.getMessage(), e);
+            throw new CdmServerException(e);
         }
 
         return false;
     }
 
-    public int compareDbSchemaVersion(CdmInstanceInfo instance, int port) throws CDMServerException {
+    public int compareDbSchemaVersion(CdmInstanceInfo instance, int port) throws CdmServerException {
 
-        ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
-        String dbSchemaVersion;
+        ICdmSource remoteSource = getCdmRemoteSource(instance, port);
+        String remoteDbSchemaVersion;
         try {
-            dbSchemaVersion = crs.getDbSchemaVersion();
+            remoteDbSchemaVersion = remoteSource.getDbSchemaVersion();
         } catch (CdmSourceException e) {
-            throw new CDMServerException(e);
+            throw new CdmServerException(e);
         }
 
-
-        if(dbSchemaVersion != null) {
-            return CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
+        if(remoteDbSchemaVersion != null) {
+            return CdmMetaData.compareVersion(remoteDbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
         } else {
-            throw new CDMServerException("Cannot determine editor db. schema version");
+            throw new CdmServerException("Cannot determine editor db schema version");
         }
     }
 
@@ -332,12 +337,6 @@ public class CdmServerInfo {
         }
     }
 
-
-    /**
-     * @param serverVersion
-     * @param editorVersion
-     * @throws CdmSourceException
-     */
     public static int compareCdmlibServicesVersion(String serverVersion, String serverCdmlibLastModified) throws CdmSourceException {
 
         String editorVersion = CdmApplicationState.getCdmlibVersion();
@@ -380,32 +379,31 @@ public class CdmServerInfo {
             return serverLastModified.compareTo(editorLastModified);
         }
 
-        return 0;
+        return result;
     }
 
-
-
-    public static List<CdmServerInfo> getCdmServers() {
-        List<CdmServerInfoConfig> configList = loadFromConfigFile(new File(CdmUtils.perUserCdmFolder, CDM_REMOTE_SERVERS_CONFIG_FILE));
-        List<CdmServerInfo> serverInfoList = new ArrayList<CdmServerInfo>(configList.size());
+    public static List<CdmServerInfo> getCdmServers(boolean isLocal) {
+        List<CdmServerInfoConfig> configList;
+        File file = new File(ConfigFileUtil.perUserCdmFolderFallback(), CDM_REMOTE_SERVERS_CONFIG_FILE);
+        if (file.exists()){
+            configList = loadFromConfigFile(file);
+        }else{
+            configList = loadFromConfigFile(new File(ConfigFileUtil.perUserCdmFolderFallback(), CDM_REMOTE_SERVERS_CONFIG_FILE));
+        }
+        List<CdmServerInfo> serverInfoList = new ArrayList<>(configList.size());
         for(CdmServerInfoConfig config : configList) {
             serverInfoList.add(new CdmServerInfo(config));
         }
-        // The local host managed server must not be in the config file
-        CdmServerInfoConfig localHostManagedConfig = new CdmServerInfoConfig(NAME_LOCALHOST_MGD, SERVER_LOCALHOST, NULL_PORT, CDMSERVER_PREFIX, false);
-        serverInfoList.add(new CdmServerInfo(localHostManagedConfig));
+        // The local host managed server must not be in the config file, this should be moved and only added when plugin is installed
+        if (isLocal){
+            CdmServerInfoConfig localHostManagedConfig = new CdmServerInfoConfig(NAME_LOCALHOST_MGD, SERVER_LOCALHOST, NULL_PORT, CDMSERVER_PREFIX, false);
+            serverInfoList.add(new CdmServerInfo(localHostManagedConfig));
+        }
+
         return serverInfoList;
     }
 
-
-    /**
-     * @param file
-     * @throws IOException
-     * @throws FileNotFoundException
-     * @throws JsonMappingException
-     * @throws JsonParseException
-     */
-    private static List<CdmServerInfoConfig>  loadFromConfigFile(File file) {
+    protected static List<CdmServerInfoConfig>  loadFromConfigFile(File file) {
 
         List<CdmServerInfoConfig> serverList = null;
 
@@ -430,22 +428,13 @@ public class CdmServerInfo {
         }
 
         return serverList;
-
-
     }
 
-
-    /**
-     *
-     */
     private static List<CdmServerInfoConfig> createDefaultServerConfigList() {
 
-        List<CdmServerInfoConfig> serverInfoList = new ArrayList<CdmServerInfoConfig>();
-       // serverInfoList.add(new CdmServerInfoConfig(NAME_PRODUCTION, SERVER_PRODUCTION, 80, ""));
-       //serverInfoList.add(new CdmServerInfoConfig(NAME_INTEGRATION, SERVER_INTEGRATION, 80, CDMSERVER_PREFIX));
+        List<CdmServerInfoConfig> serverInfoList = new ArrayList<>();
+        serverInfoList.add(new CdmServerInfoConfig(NAME_PRODUCTION, SERVER_PRODUCTION, 80, "", false));
         serverInfoList.add(new CdmServerInfoConfig(NAME_DEMO_1, SERVER_DEMO_1, 80, CDMSERVER_PREFIX, false));
-       // serverInfoList.add(new CdmServerInfoConfig(NAME_DEMO_2, SERVER_DEMO_2, 80, CDMSERVER_PREFIX));
-        serverInfoList.add(new CdmServerInfoConfig(NAME_TEST, SERVER_TEST, 80, CDMSERVER_PREFIX, false));
         serverInfoList.add(new CdmServerInfoConfig(NAME_LOCALHOST, SERVER_LOCALHOST, 8080, CDMSERVER_PREFIX, true));
         return serverInfoList;
     }
@@ -458,7 +447,6 @@ public class CdmServerInfo {
         return server;
     }
 
-
     public int getPort() {
         return port;
     }
@@ -467,14 +455,14 @@ public class CdmServerInfo {
         this.port = port;
     }
 
-    public List<CdmInstanceInfo> getInstances() throws CDMServerException {
+    public List<CdmInstanceInfo> getInstances() throws CdmServerException {
         if(instances.isEmpty()) {
             refreshInstances();
         }
         return instances;
     }
 
-    public static CdmRemoteSource getDevServerRemoteSource() {
+    public static ICdmSource getDevServerRemoteSource() {
         String value = System.getProperty("cdm.server.dev.port");
         boolean available = false;
         CdmInstanceInfo devInstance = null;
@@ -485,16 +473,23 @@ public class CdmServerInfo {
                 devInstance = devCii.addInstance(NAME_INSTANCE_LOCALHOST_DEV, BASEPATH_LOCALHOST_DEV);
                 available = devCii.pingInstance(devInstance, devPort);
                 if(available) {
+                    logger.info("Will connect local development cdm instance: at port " + devPort);
                     return devCii.getCdmRemoteSource(devInstance, devPort);
                 }
-            } catch (Exception e) {
-
+            } catch (CdmServerException e) {
+                logger.error("Can not connect to local development cdm instance at port " + devPort + ". "
+                        + "Make sure the cdm instance is running and that the Spring profile \"remoting\" is "
+                        + "activated (-Dspring.profiles.active=remoting)", e);
+                //TODO show message dialog only instead of throwing the exception to show the error
+                // dialog is not necessary in this situation
             }
+            logger.error("local development cdm instance at port " + devPort + " is not accessible");
         }
         return null;
     }
 
     public class CdmInstanceInfo {
+
         private final String name;
 
         /**
@@ -504,12 +499,19 @@ public class CdmServerInfo {
          */
         private final String basePath;
 
+        private final ICdmDataSource dataSource;
 
         public CdmInstanceInfo(String name, String basePath) {
             this.name = name;
             this.basePath = basePath;
+            this.dataSource = null;
         }
 
+        public CdmInstanceInfo(String name, ICdmDataSource dataSource) {
+            this.name = name;
+            this.basePath = "";
+            this.dataSource = dataSource;
+        }
 
         public String getName() {
             return name;
@@ -518,5 +520,9 @@ public class CdmServerInfo {
         public String getBasePath() {
             return basePath;
         }
+
+        public ICdmDataSource getDataSource() {
+            return dataSource;
+        }
     }
 }