Project

General

Profile

Download (24.6 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
 * Copyright (C) 2009 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

    
11
package eu.etaxonomy.cdm.server;
12

    
13
import static eu.etaxonomy.cdm.server.AssumedMemoryRequirements.KB;
14
import static eu.etaxonomy.cdm.server.CommandOptions.DATASOURCES_FILE;
15
import static eu.etaxonomy.cdm.server.CommandOptions.HELP;
16
import static eu.etaxonomy.cdm.server.CommandOptions.HTTP_PORT;
17
import static eu.etaxonomy.cdm.server.CommandOptions.JMX;
18
import static eu.etaxonomy.cdm.server.CommandOptions.LOG_DIR;
19
import static eu.etaxonomy.cdm.server.CommandOptions.WEBAPP;
20
import static eu.etaxonomy.cdm.server.CommandOptions.WEBAPP_CLASSPATH;
21
import static eu.etaxonomy.cdm.server.CommandOptions.WIN32SERVICE;
22

    
23
import java.io.BufferedReader;
24
import java.io.File;
25
import java.io.FileNotFoundException;
26
import java.io.FileOutputStream;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.io.InputStreamReader;
30
import java.io.OutputStream;
31
import java.lang.management.ManagementFactory;
32
import java.net.URL;
33
import java.util.List;
34
import java.util.Properties;
35

    
36
import org.apache.commons.cli.CommandLine;
37
import org.apache.commons.cli.CommandLineParser;
38
import org.apache.commons.cli.GnuParser;
39
import org.apache.commons.cli.HelpFormatter;
40
import org.apache.commons.cli.ParseException;
41
import org.apache.commons.io.FileUtils;
42
import org.apache.log4j.Logger;
43
import org.apache.log4j.PatternLayout;
44
import org.apache.log4j.RollingFileAppender;
45
import org.eclipse.jetty.jmx.MBeanContainer;
46
import org.eclipse.jetty.security.HashLoginService;
47
import org.eclipse.jetty.server.Handler;
48
import org.eclipse.jetty.server.Server;
49
import org.eclipse.jetty.server.handler.ContextHandler;
50
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
51
import org.eclipse.jetty.util.log.Log;
52
import org.eclipse.jetty.webapp.WebAppClassLoader;
53
import org.eclipse.jetty.webapp.WebAppContext;
54

    
55
import eu.etaxonomy.cdm.server.instance.CdmInstance;
56
import eu.etaxonomy.cdm.server.instance.Configuration;
57
import eu.etaxonomy.cdm.server.instance.InstanceManager;
58
import eu.etaxonomy.cdm.server.instance.SharedAttributes;
59
import eu.etaxonomy.cdm.server.instance.Status;
60
import eu.etaxonomy.cdm.server.win32service.Win32Service;
61

    
62

    
63
/**
64
 * A bootstrap class for starting Jetty Runner using an embedded war.
65
 *
66
 * Recommended start options for the java virtual machine:
67
 * <pre>
68
 * -Xmx1024M
69
 *
70
 * -XX:PermSize=128m
71
 * -XX:MaxPermSize=192m
72
 *
73
 * -XX:+UseConcMarkSweepGC
74
 * -XX:+CMSClassUnloadingEnabled
75
 * -XX:+CMSPermGenSweepingEnabled
76
 * </pre>
77
 *
78
 * @version $Revision$
79
 */
80
public final class Bootloader {
81
    /**
82
     *
83
     */
84
    private static final String VERSION_PROPERTIES_FILE = "version.properties";
85

    
86
    //private static final String DEFAULT_WARFILE = "target/";
87

    
88

    
89

    
90
    private static final Logger logger = Logger.getLogger(Bootloader.class);
91

    
92
    private static final String DATASOURCE_BEANDEF_FILE = "datasources.xml";
93
    private static final String REALM_PROPERTIES_FILE = "cdm-server-realm.properties";
94

    
95
    private static final String USERHOME_CDM_LIBRARY_PATH = System.getProperty("user.home")+File.separator+".cdmLibrary"+File.separator;
96
    private static final String TMP_PATH = USERHOME_CDM_LIBRARY_PATH + "server" + File.separator;
97
    private static final String LOG_PATH = USERHOME_CDM_LIBRARY_PATH + "log" + File.separator;
98

    
99
    private static final String APPLICATION_NAME = "CDM Server";
100
    private static final String WAR_POSTFIX = ".war";
101

    
102
    private static final String CDMLIB_REMOTE_WEBAPP = "cdmlib-remote-webapp";
103
    private static final String CDMLIB_REMOTE_WEBAPP_VERSION = "cdmlib-remote-webapp.version";
104

    
105
    private static final String DEFAULT_WEBAPP_WAR_NAME = "default-webapp";
106
    private static final File DEFAULT_WEBAPP_TEMP_FOLDER = new File(TMP_PATH + DEFAULT_WEBAPP_WAR_NAME);
107
    private static final File CDM_WEBAPP_TEMP_FOLDER = new File(TMP_PATH + CDMLIB_REMOTE_WEBAPP);
108

    
109
    private final InstanceManager instanceManager = new InstanceManager(new File(USERHOME_CDM_LIBRARY_PATH, DATASOURCE_BEANDEF_FILE));
110

    
111
    public List<CdmInstance> getCdmInstances() {
112
        return instanceManager.getInstances();
113
    }
114

    
115
    public InstanceManager getInstanceManager(){
116
        return instanceManager;
117
    }
118

    
119
    private File cdmRemoteWebAppFile = null;
120
    private File defaultWebAppFile = null;
121

    
122
    private String logPath = null;
123

    
124
    private String webAppClassPath = null;
125

    
126
    private Server server = null;
127
    private final ContextHandlerCollection contexts = new ContextHandlerCollection();
128

    
129
    private CommandLine cmdLine;
130

    
131
    private boolean isRunningFromSource;
132

    
133
    private boolean isRunningfromTargetFolder;
134

    
135
    private boolean isRunningFromWarFile;
136

    
137
    /* thread save singleton implementation */
138

    
139
    private static Bootloader bootloader = new Bootloader();
140

    
141
    private Bootloader() {}
142

    
143
    /**
144
     * @return the thread save singleton instance of the Bootloader
145
     */
146
    public synchronized static Bootloader getBootloader(){
147
        return bootloader;
148
    }
149

    
150
    /* end of singleton implementation */
151

    
152

    
153
    /**
154
     * @param input
155
     * @param output
156
     * @param bufferSize
157
     * @return
158
     * @throws IOException
159
     */
160
    public int writeStreamTo(final InputStream input, final OutputStream output, int bufferSize) throws IOException {
161
        int available = Math.min(input.available(), 256 * KB);
162
        byte[] buffer = new byte[Math.max(bufferSize, available)];
163
        int answer = 0;
164
        int count = input.read(buffer);
165
        while (count >= 0) {
166
            output.write(buffer, 0, count);
167
            answer += count;
168
            count = input.read(buffer);
169
        }
170
        return answer;
171
    }
172

    
173

    
174

    
175
    public void parseCommandOptions(String[] args) throws ParseException {
176
        CommandLineParser parser = new GnuParser();
177
        cmdLine = parser.parse( CommandOptions.getOptions(), args );
178

    
179
         // print the help message
180
         if(cmdLine.hasOption(HELP.getOpt())){
181
             HelpFormatter formatter = new HelpFormatter();
182
             formatter.setWidth(200);
183
             formatter.printHelp( "java .. ", CommandOptions.getOptions() );
184
             System.exit(0);
185
         }
186
    }
187

    
188

    
189
    private File extractWar(String warName) throws IOException, FileNotFoundException {
190
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
191
        String warFileName = warName + WAR_POSTFIX;
192

    
193
        // 1. find in classpath
194
        URL resource = classLoader.getResource(warFileName);
195
        if (resource == null) {
196
            logger.error("Could not find the " + warFileName + " on classpath!");
197

    
198
            File pomxml = new File("pom.xml");
199
            if(pomxml.exists()){
200
                // 2. try finding in target folder of maven project
201
                File warFile = new File("target" + File.separator + warFileName);
202
                logger.debug("looking for war file at " + warFile.getAbsolutePath());
203
                if (warFile.canRead()) {
204
                    resource = warFile.toURI().toURL();
205
                } else {
206
                    logger.error("Also could not find the " + warFileName + " in maven project, try excuting 'mvn install'");
207
                }
208
            }
209
        }
210

    
211
        if (resource == null) {
212
            // no way finding the war file :-(
213
            System.exit(1);
214
        }
215

    
216

    
217
        File warFile = new File(TMP_PATH, warName + "-" + WAR_POSTFIX);
218
        logger.info("Extracting " + warFileName + " to " + warFile + " ...");
219

    
220
        writeStreamTo(resource.openStream(), new FileOutputStream(warFile), 8 * KB);
221

    
222
        logger.info("Extracted " + warFileName);
223
        return warFile;
224
    }
225

    
226

    
227
    /**
228
     * MAIN METHOD
229
     *
230
     * @param args
231
     * @throws Exception
232
     */
233
    public static void main(String[] args) throws Exception {
234

    
235
        Bootloader bootloader = Bootloader.getBootloader();
236

    
237
        bootloader.parseCommandOptions(args);
238

    
239
        bootloader.startServer();
240
    }
241

    
242

    
243

    
244
    public void startServer() throws IOException,
245
            FileNotFoundException, Exception, InterruptedException {
246

    
247

    
248
        if(cmdLine.hasOption(LOG_DIR.getOpt())){
249
            logPath = cmdLine.getOptionValue(LOG_DIR.getOpt());
250
        } else {
251
            logPath = LOG_PATH;
252
        }
253

    
254

    
255
        //assure LOG_PATH exists
256
        File logPathFile = new File(logPath);
257
        if(!logPathFile.exists()){
258
            FileUtils.forceMkdir(new File(logPath));
259
        }
260

    
261
        //append logger
262
        configureFileLogger();
263

    
264
        logger.info("Starting "+APPLICATION_NAME);
265
        logger.info("Using  " + System.getProperty("user.home") + " as home directory. Can be specified by -Duser.home=<FOLDER>");
266

    
267
        //assure TMP_PATH exists and clean it up
268
        File tempDir = new File(TMP_PATH);
269
        if(!tempDir.exists() && !tempDir.mkdirs()){
270
            logger.error("Error creating temporary directory for webapplications " + tempDir.getAbsolutePath());
271
            System.exit(-1);
272
        } else {
273
            if(FileUtils.deleteQuietly(tempDir)){
274
                tempDir.mkdirs();
275
                logger.info("Old webapplications successfully cleared");
276
            }
277
        }
278
        tempDir = null;
279

    
280

    
281
        // WEBAPP options
282
        //   prepare web application files to run either from war files (production mode)
283
        //   or from source (development mode)
284
        if(cmdLine.hasOption(WEBAPP.getOpt())){
285

    
286
            cdmRemoteWebAppFile = new File(cmdLine.getOptionValue(WEBAPP.getOpt()));
287
            if(cdmRemoteWebAppFile.isDirectory()){
288
                logger.info("using user defined web application folder: " + cdmRemoteWebAppFile.getAbsolutePath());
289
            } else {
290
                logger.info("using user defined warfile: " + cdmRemoteWebAppFile.getAbsolutePath());
291
            }
292

    
293
            updateServerRunMode();
294

    
295
            // load the default-web-application from source if running in development mode mode
296
            if(isRunningFromWarFile){
297
                defaultWebAppFile = extractWar(DEFAULT_WEBAPP_WAR_NAME);
298
            } else {
299
                defaultWebAppFile = new File("./src/main/webapp");
300
            }
301

    
302
            if(isRunningFromSource){
303
                if(cmdLine.hasOption(WEBAPP_CLASSPATH.getOpt())){
304
                    String classPathOption = cmdLine.getOptionValue(WEBAPP_CLASSPATH.getOpt());
305
                    normalizeClasspath(classPathOption);
306
                }
307
            }
308
        } else {
309
            // read version number
310
            String version = readCdmRemoteVersion();
311
            cdmRemoteWebAppFile = extractWar(CDMLIB_REMOTE_WEBAPP + "-" + version);
312
            defaultWebAppFile = extractWar(DEFAULT_WEBAPP_WAR_NAME);
313
        }
314

    
315

    
316
        // HTTP Port
317
        int httpPort = 8080;
318
        if(cmdLine.hasOption(HTTP_PORT.getOpt())){
319
            try {
320
               httpPort = Integer.parseInt(cmdLine.getOptionValue(HTTP_PORT.getOpt()));
321
               logger.info(HTTP_PORT.getOpt()+" set to "+cmdLine.getOptionValue(HTTP_PORT.getOpt()));
322
           } catch (NumberFormatException e) {
323
               logger.error("Supplied portnumber is not an integer");
324
               System.exit(-1);
325
           }
326
        }
327

    
328
         if(cmdLine.hasOption(DATASOURCES_FILE.getOpt())){
329
             File datasourcesFile = new File(cmdLine.getOptionValue(DATASOURCES_FILE.getOpt()));
330
             if(datasourcesFile.canRead()) {
331
                instanceManager.setDatasourcesFile(datasourcesFile);
332
            } else {
333
                logger.error("File set as " + DATASOURCES_FILE.getOpt()
334
                        + " (" + cmdLine.getOptionValue(DATASOURCES_FILE.getOpt())
335
                        + ") is not readable.");
336
            }
337
         }
338

    
339
        verifySystemResources();
340

    
341
         // load the configured instances for the first time
342
        instanceManager.reLoadInstanceConfigurations();
343

    
344
        server = new Server(httpPort);
345
        server.addLifeCycleListener(instanceManager);
346

    
347
        // JMX support
348
        if(cmdLine.hasOption(JMX.getOpt())){
349
            logger.info("adding JMX support ...");
350
            MBeanContainer mBeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
351
            server.getContainer().addEventListener(mBeanContainer);
352
            mBeanContainer.addBean(Log.getLog());
353
            mBeanContainer.start();
354
        }
355

    
356
        if(cmdLine.hasOption(WIN32SERVICE.getOpt())){
357
            Win32Service win32Service = new Win32Service();
358
            win32Service.setServer(server);
359
            server.setStopAtShutdown(true);
360
            server.addBean(win32Service);
361
        }
362

    
363
        // add default servlet context
364
        logger.info("preparing default WebAppContext");
365
        WebAppContext defaultWebappContext = new WebAppContext();
366

    
367
        setWebApp(defaultWebappContext, defaultWebAppFile);
368
        defaultWebappContext.setContextPath("/");
369
        defaultWebappContext.setTempDirectory(DEFAULT_WEBAPP_TEMP_FOLDER);
370

    
371
        // configure security context
372
        // see for reference * http://docs.codehaus.org/display/JETTY/Realms
373
        //                   * http://wiki.eclipse.org/Jetty/Starting/Porting_to_Jetty_7
374
        HashLoginService loginService = new HashLoginService();
375
        loginService.setConfig(USERHOME_CDM_LIBRARY_PATH + REALM_PROPERTIES_FILE);
376
        defaultWebappContext.getSecurityHandler().setLoginService(loginService);
377

    
378
        // Important:
379
        // the defaultWebappContext MUST USE the super classloader
380
        // otherwise the status page (index.jsp) might not work
381
        defaultWebappContext.setClassLoader(this.getClass().getClassLoader());
382
        contexts.addHandler(defaultWebappContext);
383

    
384
        logger.info("setting contexts ...");
385
        server.setHandler(contexts);
386
        logger.info("starting jetty ...");
387
//        try {
388

    
389
            server.start();
390

    
391
//        } catch(org.springframework.beans.BeansException e){
392
//        	Throwable rootCause = null;
393
//        	while(e.getCause() != null){
394
//        		rootCause = e.getCause();
395
//        	}
396
//        	if(rootCause != null && rootCause.getClass().getSimpleName().equals("InvalidCdmVersionException")){
397
//
398
//        		logger.error("rootCause ----------->" + rootCause.getMessage());
399
////        		for(CdmInstanceProperties props : configAndStatus){
400
////        			if(props.getDataSourceName())
401
////        		}
402
//        	}
403
//        }
404

    
405
        if(cmdLine.hasOption(WIN32SERVICE.getOpt())){
406
            logger.info("jetty has started as win32 service");
407
        } else {
408
            server.join();
409
            logger.info(APPLICATION_NAME+" stopped.");
410
            System.exit(0);
411
        }
412
    }
413

    
414
    /**
415
     * @param classpath
416
     */
417
    private void normalizeClasspath(String classpath) {
418
        StringBuilder classPathBuilder = new StringBuilder((int) (classpath.length() * 1.2));
419
        String[] cpEntries = classpath.split("[\\:]");
420
        for(String cpEntry : cpEntries){
421
            classPathBuilder.append(',');
422
//            if(cpEntry.endsWith(".jar")){
423
//                classPathBuilder.append("jar:");
424
//            }
425
            classPathBuilder.append(cpEntry);
426
        }
427
        webAppClassPath = classPathBuilder.toString();
428
    }
429

    
430
    public String readCdmRemoteVersion() throws IOException {
431
        String version = "cdmlib version unreadable";
432
        InputStream versionInStream = Bootloader.class.getClassLoader().getResourceAsStream(VERSION_PROPERTIES_FILE);
433
        if (versionInStream != null){
434
            Properties versionProperties = new Properties();
435
            versionProperties.load(versionInStream);
436
            version = versionProperties.getProperty(CDMLIB_REMOTE_WEBAPP_VERSION, version);
437
        }
438
        return version;
439
    }
440

    
441

    
442

    
443
    private void verifySystemResources() {
444

    
445
        OsChecker osChecker = new OsChecker();
446
        if(osChecker.isLinux()){
447
            try {
448
                Process p = Runtime.getRuntime().exec(new String[] { "bash", "-c", "ulimit -n" });
449
                BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
450
                String line;
451
                StringBuilder response = new StringBuilder();
452
                     while ((line = in.readLine()) != null) {
453
                         response.append(line);
454
                     }
455
               logger.info("OS Limit (Linux): maximum number of open files: " + response);
456
            } catch (IOException e) {
457
                // TODO Auto-generated catch block
458
                e.printStackTrace();
459
            }
460
        } else {
461
            logger.info("verifySystemResources only implemented for linux");
462
        }
463
    }
464

    
465

    
466
    /**
467
     * Configures and adds a {@link RollingFileAppender} to the root logger
468
     *
469
     * The log files of the cdm-remote instances are configured by the
470
     * {@link eu.etaxonomy.cdm.remote.config.LoggingConfigurer}
471
     */
472
    private void configureFileLogger() {
473

    
474
        PatternLayout layout = new PatternLayout("%d %p [%c] - %m%n");
475
        try {
476
            String logFile = logPath + File.separator + "cdmserver.log";
477
            RollingFileAppender appender = new RollingFileAppender(layout, logFile);
478
            appender.setMaxBackupIndex(3);
479
            appender.setMaxFileSize("2MB");
480
            Logger.getRootLogger().addAppender(appender);
481
            logger.info("logging to :" + logFile);
482
        } catch (IOException e) {
483
            logger.error("Creating RollingFileAppender failed:", e);
484
        }
485
    }
486

    
487

    
488
    /**
489
     * Adds a new WebAppContext to the contexts of the running jetty instance.
490
     * <ol>
491
     * <li>Initialize WebAppContext:
492
     * <ol>
493
     * <li>set context path</li>
494
     * <li>set tmp directory</li>
495
     * <li>bind JndiDataSource</li>
496
     * <li>set web app context attributes</li>
497
     * <li>create and setup individual classloader for the instance</li>
498
     * </ol>
499
     * </li>
500
     * <li>
501
     * finally add the new webappcontext to the contexts of the jetty instance</li>
502
     * </ol>
503
     *
504
     * @param instance
505
     * @return the instance given as parameter of null in case the instance has
506
     *         {@link Status.#disabled} or if it is already added.
507
     * @throws IOException
508
     */
509
    public WebAppContext addCdmInstanceContext(CdmInstance instance) throws IOException {
510

    
511
        Configuration conf = instance.getConfiguration();
512
        if(!instance.isEnabled()){
513
            logger.info(conf.getInstanceName() + " is disabled, possibly due to JVM memory limitations");
514
            return null;
515
        }
516
        if(getContextFor(conf) != null){
517
            logger.info(conf.getInstanceName() + " is alreaddy added to the contexts - skipping");
518
            return null;
519
        }
520

    
521
        instance.setStatus(Status.initializing);
522
        logger.info("preparing WebAppContext for '"+ conf.getInstanceName() + "'");
523
        WebAppContext cdmWebappContext = new WebAppContext();
524

    
525
        cdmWebappContext.setContextPath(constructContextPath(conf));
526
        cdmWebappContext.setTempDirectory(CDM_WEBAPP_TEMP_FOLDER);
527

    
528
        if(!instance.bindJndiDataSource()){
529
            // a problem with the datasource occurred skip this webapp
530
            cdmWebappContext = null;
531
            logger.error("a problem with the datasource occurred -> skipping /" + conf.getInstanceName());
532
            instance.setStatus(Status.error);
533
            return cdmWebappContext;
534
        }
535

    
536
        cdmWebappContext.setAttribute(SharedAttributes.ATTRIBUTE_DATASOURCE_NAME, conf.getInstanceName());
537
        cdmWebappContext.setAttribute(SharedAttributes.ATTRIBUTE_JDBC_JNDI_NAME, conf.getJdbcJndiName());
538
        setWebApp(cdmWebappContext, getCdmRemoteWebAppFile());
539

    
540
        cdmWebappContext.setAttribute(SharedAttributes.ATTRIBUTE_CDM_LOGFILE,
541
                logPath + File.separator + "cdm-"
542
                        + conf.getInstanceName() + ".log");
543

    
544
        if( isRunningFromSource ){
545

    
546
            /*
547
             * when running the webapp from {projectpath} src/main/webapp we
548
             * must assure that each web application is using it's own
549
             * classloader thus we tell the WebAppClassLoader where the
550
             * dependencies of the webapplication can be found. Otherwise
551
             * the system classloader would load these resources.
552
             */
553
            WebAppClassLoader classLoader = new WebAppClassLoader(cdmWebappContext);
554
            if(webAppClassPath != null){
555
                logger.info("Running cdmlib-remote-webapp from source folder: Adding class path supplied by option '-" +  WEBAPP_CLASSPATH.getOpt() +" =" + webAppClassPath +"'  to WebAppClassLoader");
556
                classLoader.addClassPath(webAppClassPath);
557
            } else {
558
                throw new RuntimeException("Classpath cdmlib-remote-webapp for missing while running cdmlib-remote-webapp from source folder. Please supplied cdm-server option '-" +  WEBAPP_CLASSPATH.getOpt() +"");
559
            }
560
            cdmWebappContext.setClassLoader(classLoader);
561
        }
562

    
563
        contexts.addHandler(cdmWebappContext);
564
        instance.setWebAppContext(cdmWebappContext);
565
        cdmWebappContext.addLifeCycleListener(instance);
566
        instance.setStatus(Status.stopped);
567

    
568
        return cdmWebappContext;
569
    }
570

    
571
    /**
572
     * @param conf
573
     * @return
574
     */
575
    private String constructContextPath(Configuration conf) {
576
        return "/" + conf.getInstanceName();
577
    }
578

    
579
    /**
580
     * Removes the given instance from the contexts. If the instance is running
581
     * at the time of calling this method it will be stopped first.
582
     * The JndiDataSource and the webapplicationContext will be released and removed.
583
     *
584
     * @param instance the instance to be removed
585
     *
586
     * @throws Exception in case stopping the instance fails
587
     */
588
    public void removeCdmInstanceContext(CdmInstance instance) throws Exception {
589

    
590
        if(instance.getWebAppContext() != null){
591
            if(instance.getWebAppContext().isRunning()){
592
                try {
593
                    instance.getWebAppContext().stop();
594
                } catch (Exception e) {
595
                    instance.getProblems().add("Error while stopping instance: " + e.getMessage());
596
                    throw e;
597
                }
598
            }
599
            contexts.removeHandler(instance.getWebAppContext());
600
            instance.releaseWebAppContext();
601
        } else  {
602
            // maybe something went wrong before, try to find the potentially lost
603
            // contexts directly in the server
604
            ContextHandler handler = getContextFor(instance.getConfiguration());
605
            if(handler != null){
606
                contexts.removeHandler(handler);
607
            }
608
        }
609
        instance.unbindJndiDataSource();
610
    }
611

    
612
    /**
613
     * Sets the webapp specified by the <code>webApplicationResource</code> to
614
     * the given <code>context</code>.
615
     *
616
     * @param context
617
     * @param webApplicationResource the resource can either be a directory containing
618
     * a Java web application or *.war file.
619
     *
620
     */
621
    private void setWebApp(WebAppContext context, File webApplicationResource) {
622
        if(webApplicationResource.isDirectory()){
623
            context.setResourceBase(webApplicationResource.getAbsolutePath());
624
            logger.debug("setting directory " + webApplicationResource.getAbsolutePath() + " as webapplication");
625
        } else {
626
            context.setWar(webApplicationResource.getAbsolutePath());
627
            logger.debug("setting war file " + webApplicationResource.getAbsolutePath() + " as webapplication");
628
        }
629
    }
630

    
631
    private void updateServerRunMode() {
632
        String webappPathNormalized = cdmRemoteWebAppFile.getAbsolutePath().replace('\\', '/');
633
        isRunningFromSource =  webappPathNormalized.endsWith("src/main/webapp");
634
        isRunningfromTargetFolder = webappPathNormalized.endsWith("cdmlib-remote-webapp/target/cdmserver");
635
        isRunningFromWarFile = !(isRunningFromSource || isRunningfromTargetFolder);
636
    }
637

    
638

    
639
    public Server getServer() {
640
        return server;
641
    }
642

    
643
    public ContextHandler getContextFor(Configuration conf) {
644
        return getContextFor(constructContextPath(conf));
645
    }
646

    
647
    public ContextHandler getContextFor(String contextPath) {
648
        for( Handler handler : contexts.getHandlers()){
649
            if(handler instanceof ContextHandler){
650
                if(((ContextHandler)handler).getContextPath().equals(contextPath)){
651
                    return (ContextHandler)handler;
652
                }
653
            }
654
        }
655
        return null;
656
    }
657

    
658
    public ContextHandlerCollection getContexts() {
659
        return contexts;
660
    }
661

    
662
    /**
663
     * @return a File object pointing to the location of the cdmlib-remote-webapp
664
     */
665
    public File getCdmRemoteWebAppFile(){
666
        if(cdmRemoteWebAppFile == null){
667
            throw new RuntimeException("Invalid order of action. Server not yet started. The startServer() method must be called first. ");
668
        }
669
        return cdmRemoteWebAppFile;
670
    }
671
}
(2-2/5)