Project

General

Profile

Download (18 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2015 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9
package eu.etaxonomy.taxeditor.remoting.source;
10

    
11
import java.io.File;
12
import java.io.FileInputStream;
13
import java.io.FileNotFoundException;
14
import java.io.FileOutputStream;
15
import java.io.IOException;
16
import java.net.InetSocketAddress;
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.ResponseHandler;
28
import org.apache.http.client.methods.HttpGet;
29
import org.apache.http.impl.client.DefaultHttpClient;
30
import org.apache.http.params.HttpConnectionParams;
31
import org.apache.http.params.HttpParams;
32
import org.apache.http.util.EntityUtils;
33
import org.apache.log4j.Logger;
34
import org.json.JSONArray;
35
import org.json.JSONException;
36
import org.json.JSONObject;
37

    
38
import com.fasterxml.jackson.core.JsonParseException;
39
import com.fasterxml.jackson.core.type.TypeReference;
40
import com.fasterxml.jackson.databind.JsonMappingException;
41
import com.fasterxml.jackson.databind.ObjectMapper;
42

    
43
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
44
import eu.etaxonomy.cdm.common.CdmUtils;
45
import eu.etaxonomy.cdm.config.CdmSourceException;
46
import eu.etaxonomy.cdm.database.CdmPersistentDataSource;
47
import eu.etaxonomy.cdm.database.ICdmDataSource;
48
import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
49
import eu.etaxonomy.taxeditor.remoting.server.CDMServerException;
50
import eu.etaxonomy.taxeditor.remoting.server.CDMServerUtils;
51

    
52
/**
53
 * @author cmathew
54
 * @date 20 Jan 2015
55
 *
56
 */
57
public class CdmServerInfo {
58
    public static final Logger logger = Logger.getLogger(CdmServerInfo.class);
59

    
60
    private final static String CDMSERVER_PREFIX = "cdmserver/";
61
    private final static String NAME_PRODUCTION = "cybertaxonomy.org";
62
    private final static String SERVER_PRODUCTION = "api.cybertaxonomy.org";
63

    
64
    private final static String NAME_DEMO_1 = "demo I";
65
    private final static String SERVER_DEMO_1 = "160.45.63.230";
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 String BASEPATH_LOCALHOST_DEV = "";
75

    
76
    public final static int NULL_PORT = -1;
77
    public final static String NULL_PORT_STRING = "N/A";
78

    
79
    private static final String CDM_REMOTE_SERVERS_CONFIG_FILE = "cdm_remote_servers.json";
80

    
81

    
82
    private final String name;
83
    private final String server;
84
    private int port;
85
    private final List<CdmInstanceInfo> instances;
86

    
87
    private String cdmlibServicesVersion = "";
88
    private String cdmlibServicesLastModified = "";
89

    
90
    private String prefix = "";
91

    
92
    private boolean ignoreCdmLibVersion = false;
93

    
94

    
95
    public CdmServerInfo(CdmServerInfoConfig parameterObject) {
96
        this.name = parameterObject.getName();
97
        this.server = parameterObject.getServer();
98
        this.port = parameterObject.getPort();
99
        this.prefix = parameterObject.getPrefix();
100
        this.ignoreCdmLibVersion = parameterObject.isIgnoreCdmLibVersion();
101
        instances = new ArrayList<>();
102
    }
103

    
104

    
105
    public CdmInstanceInfo addInstance(String name, String basePath) {
106
        String _basePath = basePath;
107
        if(isLocalhostMgd()) {
108
            _basePath = "";
109
        }
110
        CdmInstanceInfo cii = new CdmInstanceInfo(name, _basePath);
111
        instances.add(cii);
112
        return cii;
113

    
114
    }
115

    
116
    public boolean isLocalhost() {
117
        return name.startsWith(SERVER_LOCALHOST);
118
    }
119

    
120
    public boolean isLocalhostMgd() {
121
        return NAME_LOCALHOST_MGD.equals(name);
122
    }
123

    
124
    public String getCdmlibServicesVersion() {
125
        return cdmlibServicesVersion;
126
    }
127

    
128
    public String getCdmlibLastModified() {
129
        return cdmlibServicesLastModified;
130
    }
131

    
132
    public void refreshInstances() throws CDMServerException {
133
        instances.clear();
134
        if(isLocalhostMgd()) {
135
            addInstancesFromDataSourcesConfig();
136
        } else {
137
            addInstancesViaHttp();
138
        }
139
        Collections.sort(instances, new Comparator<CdmInstanceInfo>() {
140
            @Override
141
            public int compare(CdmInstanceInfo cii1, CdmInstanceInfo cii2)
142
            {
143
                return cii1.getName().toString().compareTo(cii2.getName().toString());
144
            }
145
        });
146
    }
147

    
148
    public void updateInfo() throws CDMServerException {
149
        String url ;
150
        if (this.isLocalhost()){
151
            url = "http://localhost:58080/cdmserver/" + "info.jsp";
152
        }else{
153
            url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "info.jsp";
154
        }
155
        String responseBody = getResponse(url);
156
        if(responseBody != null) {
157
            try {
158
                JSONObject info = new JSONObject(responseBody);
159
                cdmlibServicesVersion =  info.getString("cdmlibServicesVersion");
160
                cdmlibServicesLastModified = info.getString("cdmlibServicesLastModified");
161
            } catch (JSONException e) {
162
                throw new CDMServerException(e);
163
            }
164
        }
165
    }
166

    
167
    public void addInstancesViaHttp() throws CDMServerException {
168
        updateInfo();
169
        String url;
170
        if (this.isLocalhost()){
171
            url = "http://localhost:58080" + "instances.jsp";
172
        }else{
173
            url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "instances.jsp";
174
        }
175
        String responseBody = getResponse(url);
176
        if(responseBody != null) {
177
            try {
178
                JSONArray array = new JSONArray(responseBody);
179
                for(int i=0;i<array.length();i++) {
180
                    JSONObject instance = (JSONObject)array.get(i);
181
                    if(instance != null) {
182
                        JSONObject conf = (JSONObject)instance.get("configuration");
183
                        if(conf != null) {
184
                            String instanceName = conf.getString("instanceName");
185
                            // we need to remove the first (char) forward slash from
186
                            // the base path
187
                            String basePath = conf.getString("basePath").substring(1);
188
                            addInstance(instanceName, basePath);
189
                            logger.info("Added instance with name : " + instanceName + ", basePath : " + basePath);
190
                        }
191
                    }
192
                }
193
            } catch (JSONException e) {
194
                throw new CDMServerException(e);
195
            }
196
        }
197
    }
198

    
199
    private String getResponse(String url) throws CDMServerException {
200
        DefaultHttpClient client = new DefaultHttpClient();
201
       // client = HttpClientBuilder.create().build();
202
       // client.getParams();
203
        HttpParams params = client.getParams();
204

    
205
        HttpConnectionParams.setConnectionTimeout(params, 5000);
206
        HttpConnectionParams.setSoTimeout(params, 5000);
207

    
208
        HttpGet httpGet = new HttpGet(url);
209

    
210
        logger.info("Executing request " + httpGet.getRequestLine());
211

    
212
        // Create a custom response handler
213
        ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
214

    
215
            @Override
216
            public String handleResponse(
217
                    final HttpResponse response) throws ClientProtocolException, IOException {
218
                int status = response.getStatusLine().getStatusCode();
219
                if (status >= 200 && status < 300) {
220
                    HttpEntity entity = response.getEntity();
221
                    return entity != null ? EntityUtils.toString(entity) : null;
222
                } else {
223
                    throw new ClientProtocolException("Unexpected response status: " + status);
224
                }
225
            }
226

    
227
        };
228
        String responseBody = null;
229
        try {
230
            responseBody = client.execute(httpGet, responseHandler);
231
        } catch (ClientProtocolException e) {
232
            throw new CDMServerException(e);
233
        } catch (IOException e) {
234
            throw new CDMServerException(e);
235
        } finally{
236
            client.close();
237
        }
238
        return responseBody;
239
    }
240

    
241
    public void addInstancesFromDataSourcesConfig() {
242
        for(ICdmDataSource dataSource : CdmPersistentDataSource.getAllDataSources()){
243
            String datasourceNCName = CDMServerUtils.xmlNCNamefrom(dataSource.getName());
244
            logger.info("Adding local instance " + dataSource.getName() + " as " + datasourceNCName);
245
            addInstance(datasourceNCName, datasourceNCName);
246
        }
247
    }
248

    
249
    public String toString(String instanceName, int port) {
250
        return server + ":" + String.valueOf(port) + "/" + instanceName;
251
    }
252

    
253
    public CdmInstanceInfo getInstanceFromName(String instanceName) {
254
        if(instanceName == null) {
255
            return null;
256
        }
257

    
258
        for(CdmInstanceInfo instance : instances) {
259
            if(instance.getName() != null && instance.getName().equals(instanceName)) {
260
                return instance;
261
            }
262
        }
263
        return null;
264
    }
265

    
266
    public CdmRemoteSource getCdmRemoteSource(CdmInstanceInfo instance, int port) {
267
        if(instance != null) {
268
            return CdmRemoteSource.NewInstance(name,
269
                    server,
270
                    port,
271
                    instance.getBasePath()
272
                    );
273
        }
274
        return null;
275
    }
276

    
277
    public boolean pingServer() throws CDMServerException, IOException {
278
        if(isLocalhostMgd()) {
279
            return true;
280
        }
281
        Socket s = new Socket();
282
        s.connect(new InetSocketAddress(server, port), 2000);
283
        s.close();
284
        logger.info("[CDM-Server] Available @ " + server + ":" + port );
285
        updateInfo();
286
        return true;
287
    }
288

    
289
    public boolean pingInstance(CdmInstanceInfo instance, int port) throws CDMServerException  {
290

    
291
        ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
292
        try {
293
            if(crs != null && crs.checkConnection()) {
294
                logger.info("[CDM-Server] Running @ " + server + ":" + port + " for instance " + instance);
295
                return true;
296
            }
297
        } catch (CdmSourceException e) {
298
            throw new CDMServerException(e);
299
        }
300

    
301
        return false;
302
    }
303

    
304
    public int compareDbSchemaVersion(CdmInstanceInfo instance, int port) throws CDMServerException {
305

    
306
        ICdmRemoteSource crs = getCdmRemoteSource(instance, port);
307
        String dbSchemaVersion;
308
        try {
309
            dbSchemaVersion = crs.getDbSchemaVersion();
310
        } catch (CdmSourceException e) {
311
            throw new CDMServerException(e);
312
        }
313

    
314

    
315
        if(dbSchemaVersion != null) {
316
            return CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
317
        } else {
318
            throw new CDMServerException("Cannot determine editor db. schema version");
319
        }
320
    }
321

    
322
    public int compareCdmlibServicesVersion() throws CdmSourceException {
323

    
324
        String serverVersion = cdmlibServicesVersion;
325
        String serverCdmlibLastModified = cdmlibServicesLastModified;
326
        if(ignoreCdmLibVersion) {
327
            return 0;
328
        } else {
329
            return compareCdmlibServicesVersion(serverVersion, serverCdmlibLastModified);
330
        }
331
    }
332

    
333

    
334
    /**
335
     * @param serverVersion
336
     * @param editorVersion
337
     * @throws CdmSourceException
338
     */
339
    public static int compareCdmlibServicesVersion(String serverVersion, String serverCdmlibLastModified) throws CdmSourceException {
340

    
341
        String editorVersion = CdmApplicationState.getCdmlibVersion();
342
        String editorCdmlibLastModified = CdmApplicationState.getCdmlibLastModified();
343

    
344
        int result = 0;
345
        if(StringUtils.isBlank(serverVersion) || StringUtils.isBlank(editorVersion)) {
346
            throw new CdmSourceException("cdmlib-services server or editor version is empty");
347
        }
348

    
349
        String[] serverVersionSplit = serverVersion.split("\\.");
350
        String[] editorVersionSplit = editorVersion.split("\\.");
351

    
352
        if(serverVersionSplit.length < 3 || editorVersionSplit.length < 3 || serverVersionSplit.length > 4 || editorVersionSplit.length > 4) {
353
            throw new CdmSourceException("cdmlib-services server or editor version is invalid");
354
        }
355

    
356
        Integer serverVersionPart;
357
        Integer editorVersionPart;
358

    
359
        for(int i=0 ; i<3 ; i++) {
360
            serverVersionPart = Integer.valueOf(serverVersionSplit[i]);
361
            editorVersionPart = Integer.valueOf(editorVersionSplit[i]);
362

    
363
            int partCompare = serverVersionPart.compareTo(editorVersionPart);
364
            if (partCompare != 0){
365
                return partCompare;
366
            }
367
        }
368
        // at this point major, minor and patch versions are matching
369

    
370
        if(StringUtils.isBlank(serverCdmlibLastModified) || StringUtils.isBlank(editorCdmlibLastModified)) {
371
            throw new CdmSourceException("cdmlib-services server or editor version is empty");
372
        }
373

    
374
        String cdmServerIgnoreVersion = System.getProperty("cdm.server.version.lm.ignore");
375
        if(StringUtils.isBlank(cdmServerIgnoreVersion) || !cdmServerIgnoreVersion.equals("true")) {
376
            Long serverLastModified = Long.valueOf(serverCdmlibLastModified);
377
            Long editorLastModified = Long.valueOf(editorCdmlibLastModified);
378
            return serverLastModified.compareTo(editorLastModified);
379
        }
380

    
381
        return result;
382
    }
383

    
384

    
385

    
386
    public static List<CdmServerInfo> getCdmServers() {
387
        List<CdmServerInfoConfig> configList = loadFromConfigFile(new File(CdmUtils.PER_USER_CDM_FOLDER, CDM_REMOTE_SERVERS_CONFIG_FILE));
388
        List<CdmServerInfo> serverInfoList = new ArrayList<CdmServerInfo>(configList.size());
389
        for(CdmServerInfoConfig config : configList) {
390
            serverInfoList.add(new CdmServerInfo(config));
391
        }
392
        // The local host managed server must not be in the config file
393
        CdmServerInfoConfig localHostManagedConfig = new CdmServerInfoConfig(NAME_LOCALHOST_MGD, SERVER_LOCALHOST, NULL_PORT, CDMSERVER_PREFIX, false);
394
        serverInfoList.add(new CdmServerInfo(localHostManagedConfig));
395
        return serverInfoList;
396
    }
397

    
398

    
399
    /**
400
     * @param file
401
     * @throws IOException
402
     * @throws FileNotFoundException
403
     * @throws JsonMappingException
404
     * @throws JsonParseException
405
     */
406
    private static List<CdmServerInfoConfig>  loadFromConfigFile(File file) {
407

    
408
        List<CdmServerInfoConfig> serverList = null;
409

    
410
        ObjectMapper mapper = new ObjectMapper();
411

    
412
        if(!file.exists()) {
413
            logger.info("The remote server config file '" + file.getAbsolutePath() +
414
                    "' does not yet exist, it will be created based on the defaults.");
415
             try {
416
                serverList = createDefaultServerConfigList();
417
                mapper.writerWithDefaultPrettyPrinter().writeValue(new FileOutputStream(file), serverList);
418

    
419
            } catch (IOException e) {
420
                throw new RuntimeException(e);
421
            }
422
        } else {
423
            try {
424
                serverList = mapper.readValue(new FileInputStream(file), new TypeReference<List<CdmServerInfoConfig>>(){});
425
            } catch (IOException e) {
426
               throw new RuntimeException(e);
427
            }
428
        }
429

    
430
        return serverList;
431

    
432

    
433
    }
434

    
435

    
436
    /**
437
     *
438
     */
439
    private static List<CdmServerInfoConfig> createDefaultServerConfigList() {
440

    
441
        List<CdmServerInfoConfig> serverInfoList = new ArrayList<CdmServerInfoConfig>();
442
        serverInfoList.add(new CdmServerInfoConfig(NAME_PRODUCTION, SERVER_PRODUCTION, 80, "", false));
443
        serverInfoList.add(new CdmServerInfoConfig(NAME_DEMO_1, SERVER_DEMO_1, 80, CDMSERVER_PREFIX, false));
444
        serverInfoList.add(new CdmServerInfoConfig(NAME_LOCALHOST, SERVER_LOCALHOST, 8080, CDMSERVER_PREFIX, true));
445
        return serverInfoList;
446
    }
447

    
448
    public String getName() {
449
        return name;
450
    }
451

    
452
    public String getServer() {
453
        return server;
454
    }
455

    
456

    
457
    public int getPort() {
458
        return port;
459
    }
460

    
461
    public void setPort(int port) {
462
        this.port = port;
463
    }
464

    
465
    public List<CdmInstanceInfo> getInstances() throws CDMServerException {
466
        if(instances.isEmpty()) {
467
            refreshInstances();
468
        }
469
        return instances;
470
    }
471

    
472
    public static CdmRemoteSource getDevServerRemoteSource() {
473
        String value = System.getProperty("cdm.server.dev.port");
474
        boolean available = false;
475
        CdmInstanceInfo devInstance = null;
476
        if(value != null && !value.isEmpty()) {
477
            int devPort = Integer.valueOf(value);
478
            CdmServerInfo devCii = new CdmServerInfo(new CdmServerInfoConfig(NAME_LOCALHOST_DEV, SERVER_LOCALHOST_DEV, devPort, "", false));
479
            try {
480
                devInstance = devCii.addInstance(NAME_INSTANCE_LOCALHOST_DEV, BASEPATH_LOCALHOST_DEV);
481
                available = devCii.pingInstance(devInstance, devPort);
482
                if(available) {
483
                    return devCii.getCdmRemoteSource(devInstance, devPort);
484
                }
485
            } catch (Exception e) {
486

    
487
            }
488
        }
489
        return null;
490
    }
491

    
492
    public class CdmInstanceInfo {
493
        private final String name;
494

    
495
        /**
496
         * The full path of the instance including the the prefix (if any).
497
         * E.g. for an EDIT instance this would be something like "cdmserver/remoting"
498
         * For a managed local server this would simply be ""
499
         */
500
        private final String basePath;
501

    
502

    
503
        public CdmInstanceInfo(String name, String basePath) {
504
            this.name = name;
505
            this.basePath = basePath;
506
        }
507

    
508

    
509
        public String getName() {
510
            return name;
511
        }
512

    
513
        public String getBasePath() {
514
            return basePath;
515
        }
516
    }
517
}
(5-5/7)