Project

General

Profile

Download (18.5 KB) Statistics
| Branch: | Tag: | Revision:
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_INTEGRATION = "edit-integration";
66
    private final static String SERVER_INTEGRATION = "int.e-taxonomy.eu";
67

    
68
    private final static String NAME_DEMO_1 = "edit-WS I";
69
    private final static String SERVER_DEMO_1 = "160.45.63.230";
70

    
71
    private final static String NAME_DEMO_2 = "edit-WS II";
72
    private final static String SERVER_DEMO_2 = "160.45.63.231";
73

    
74
    private final static String NAME_TEST = "edit-test";
75
    private final static String SERVER_TEST = "test.e-taxonomy.eu";
76

    
77
    public final static String SERVER_LOCALHOST = "localhost";
78
    private final static String NAME_LOCALHOST = "localhost";
79
    public final static String NAME_LOCALHOST_MGD = "localhost mgd.";
80

    
81
    private final static String NAME_LOCALHOST_DEV = "localhost-dev";
82
    private final static String NAME_INSTANCE_LOCALHOST_DEV = "local-dev";
83
    private final static String SERVER_LOCALHOST_DEV = "localhost";
84
    private final static int PORT_LOCALHOST_DEV = 8080;
85
    private final static String BASEPATH_LOCALHOST_DEV = "";
86

    
87
    public final static int NULL_PORT = -1;
88
    public final static String NULL_PORT_STRING = "N/A";
89

    
90
    private static final String CDM_REMOTE_SERVERS_CONFIG_FILE = "cdm_remote_servers.json";
91

    
92

    
93
    private final String name;
94
    private final String server;
95
    private int port;
96
    private final List<CdmInstanceInfo> instances;
97

    
98
    private String cdmlibServicesVersion = "";
99
    private String cdmlibServicesLastModified = "";
100

    
101
    private String prefix = "";
102

    
103
    private boolean ignoreCdmLibVersion = false;
104

    
105

    
106
    public CdmServerInfo(CdmServerInfoConfig parameterObject) {
107
        this.name = parameterObject.getName();
108
        this.server = parameterObject.getServer();
109
        this.port = parameterObject.getPort();
110
        this.prefix = parameterObject.getPrefix();
111
        this.ignoreCdmLibVersion = parameterObject.isIgnoreCdmLibVersion();
112
        instances = new ArrayList<CdmInstanceInfo>();
113
    }
114

    
115

    
116
    public CdmInstanceInfo addInstance(String name, String basePath) {
117
        String _basePath = basePath;
118
        if(isLocalhostMgd()) {
119
            _basePath = "";
120
        }
121
        CdmInstanceInfo cii = new CdmInstanceInfo(name, _basePath);
122
        instances.add(cii);
123
        return cii;
124

    
125
    }
126

    
127
    public boolean isLocalhost() {
128
        return name.startsWith(SERVER_LOCALHOST);
129
    }
130

    
131
    public boolean isLocalhostMgd() {
132
        return NAME_LOCALHOST_MGD.equals(name);
133
    }
134

    
135
    public String getCdmlibServicesVersion() {
136
        return cdmlibServicesVersion;
137
    }
138

    
139
    public String getCdmlibLastModified() {
140
        return cdmlibServicesLastModified;
141
    }
142

    
143
    public void refreshInstances() throws CDMServerException {
144
        instances.clear();
145
        if(isLocalhostMgd()) {
146
            addInstancesFromDataSourcesConfig();
147
        } else {
148
            addInstancesViaHttp();
149
        }
150
        Collections.sort(instances, new Comparator<CdmInstanceInfo>() {
151
            @Override
152
            public int compare(CdmInstanceInfo cii1, CdmInstanceInfo cii2)
153
            {
154
                return cii1.getName().toString().compareTo(cii2.getName().toString());
155
            }
156
        });
157
    }
158

    
159
    public void updateInfo() throws CDMServerException {
160
        String url = "http://" + server + ":" + String.valueOf(port) + "/" + prefix + "info.jsp";
161
        String responseBody = getResponse(url);
162
        if(responseBody != null) {
163
            try {
164
                JSONObject info = new JSONObject(responseBody);
165
                cdmlibServicesVersion =  info.getString("cdmlibServicesVersion");
166
                cdmlibServicesLastModified = info.getString("cdmlibServicesLastModified");
167
            } catch (JSONException e) {
168
                throw new CDMServerException(e);
169
            }
170
        }
171
    }
172

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

    
200
    private String getResponse(String url) throws CDMServerException {
201
        HttpClient client = new DefaultHttpClient();
202
        HttpParams params = client.getParams();
203

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

    
207
        HttpGet httpGet = new HttpGet(url);
208

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

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

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

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

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

    
246
    public String toString(String instanceName, int port) {
247
        return server + ":" + String.valueOf(port) + "/" + instanceName;
248
    }
249

    
250
    public CdmInstanceInfo getInstanceFromName(String instanceName) {
251
        if(instanceName == null) {
252
            return null;
253
        }
254

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

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

    
274
    public boolean pingServer() {
275
        if(isLocalhostMgd()) {
276
            return true;
277
        }
278
        try {
279
            Socket s = new Socket(server, port);
280
            logger.info("[CDM-Server] Available @ " + server + ":" + port );
281
            updateInfo();
282
            return true;
283
        } catch (IOException ioe) {
284

    
285
        } catch (CDMServerException e) {
286

    
287
        }
288
        return false;
289
    }
290

    
291
    public boolean pingInstance(CdmInstanceInfo instance, int port) throws CDMServerException  {
292

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

    
303
        return false;
304
    }
305

    
306
    public int compareDbSchemaVersion(CdmInstanceInfo instance, int port) throws CDMServerException {
307

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

    
316

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

    
324
    public int compareCdmlibServicesVersion() throws CdmSourceException {
325

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

    
335

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

    
343
        String editorVersion = CdmApplicationState.getCdmlibVersion();
344
        String editorCdmlibLastModified = CdmApplicationState.getCdmlibLastModified();
345

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

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

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

    
358
        Integer serverVersionPart;
359
        Integer editorVersionPart;
360

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

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

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

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

    
383
        return 0;
384
    }
385

    
386

    
387

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

    
400

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

    
410
        List<CdmServerInfoConfig> serverList = null;
411

    
412
        ObjectMapper mapper = new ObjectMapper();
413

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

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

    
432
        return serverList;
433

    
434

    
435
    }
436

    
437

    
438
    /**
439
     *
440
     */
441
    private static List<CdmServerInfoConfig> createDefaultServerConfigList() {
442

    
443
        List<CdmServerInfoConfig> serverInfoList = new ArrayList<CdmServerInfoConfig>();
444
       // serverInfoList.add(new CdmServerInfoConfig(NAME_PRODUCTION, SERVER_PRODUCTION, 80, ""));
445
       //serverInfoList.add(new CdmServerInfoConfig(NAME_INTEGRATION, SERVER_INTEGRATION, 80, CDMSERVER_PREFIX));
446
        serverInfoList.add(new CdmServerInfoConfig(NAME_DEMO_1, SERVER_DEMO_1, 80, CDMSERVER_PREFIX, false));
447
       // serverInfoList.add(new CdmServerInfoConfig(NAME_DEMO_2, SERVER_DEMO_2, 80, CDMSERVER_PREFIX));
448
        serverInfoList.add(new CdmServerInfoConfig(NAME_TEST, SERVER_TEST, 80, CDMSERVER_PREFIX, false));
449
        serverInfoList.add(new CdmServerInfoConfig(NAME_LOCALHOST, SERVER_LOCALHOST, 8080, CDMSERVER_PREFIX, true));
450
        return serverInfoList;
451
    }
452

    
453
    public String getName() {
454
        return name;
455
    }
456

    
457
    public String getServer() {
458
        return server;
459
    }
460

    
461

    
462
    public int getPort() {
463
        return port;
464
    }
465

    
466
    public void setPort(int port) {
467
        this.port = port;
468
    }
469

    
470
    public List<CdmInstanceInfo> getInstances() throws CDMServerException {
471
        if(instances.isEmpty()) {
472
            refreshInstances();
473
        }
474
        return instances;
475
    }
476

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

    
492
            }
493
        }
494
        return null;
495
    }
496

    
497
    public class CdmInstanceInfo {
498
        private final String name;
499

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

    
507

    
508
        public CdmInstanceInfo(String name, String basePath) {
509
            this.name = name;
510
            this.basePath = basePath;
511
        }
512

    
513

    
514
        public String getName() {
515
            return name;
516
        }
517

    
518
        public String getBasePath() {
519
            return basePath;
520
        }
521
    }
522
}
(5-5/7)