Project

General

Profile

Revision 929a8c09

ID929a8c09d30e762bddf4da0fa029ddb3db80e91f
Parent 439d9913
Child 24841ac2

Added by Andreas Kohlbecker over 7 years ago

refactoring in preparation for #3471 (cdmlib-remote-webapp instances can be stopped / started individually)

View differences:

.gitattributes
26 26
src/main/installer/win32/program-folder/start-service.bat -text
27 27
src/main/installer/win32/program-folder/stop-service.bat -text
28 28
src/main/installer/win32/setup.nsi -text
29
src/main/java/eu/etaxonomy/cdm/server/AssumedMemoryRequirements.java -text
29 30
src/main/java/eu/etaxonomy/cdm/server/Bootloader.java -text
30
src/main/java/eu/etaxonomy/cdm/server/CdmInstanceProperties.java -text
31 31
src/main/java/eu/etaxonomy/cdm/server/CommandOptions.java -text
32
src/main/java/eu/etaxonomy/cdm/server/DataSourcePropertyParser.java -text
33 32
src/main/java/eu/etaxonomy/cdm/server/JvmManager.java -text
34 33
src/main/java/eu/etaxonomy/cdm/server/OsChecker.java -text
34
src/main/java/eu/etaxonomy/cdm/server/instance/CdmInstance.java -text
35
src/main/java/eu/etaxonomy/cdm/server/instance/Configuration.java -text
36
src/main/java/eu/etaxonomy/cdm/server/instance/DataSourcePropertyParser.java -text
37
src/main/java/eu/etaxonomy/cdm/server/instance/InstanceManager.java -text
38
src/main/java/eu/etaxonomy/cdm/server/instance/Status.java -text
35 39
src/main/java/eu/etaxonomy/cdm/server/jsvc/ServiceWrapper.java -text
36 40
src/main/java/eu/etaxonomy/cdm/server/win32service/CDMServerWrapperListener.java -text
37 41
src/main/java/eu/etaxonomy/cdm/server/win32service/Win32Service.java -text
pom.xml
611 611
			<artifactId>commons-io</artifactId>
612 612
			<version>2.4</version>
613 613
		</dependency>
614
        <dependency>
615
            <groupId>commons-collections</groupId>
616
            <artifactId>commons-collections</artifactId>
617
            <version>3.2.1</version>
618
        </dependency>
614 619
		<dependency>
615 620
			<groupId>net.sf.jopt-simple</groupId>
616 621
			<artifactId>jopt-simple</artifactId>
src/main/java/eu/etaxonomy/cdm/server/AssumedMemoryRequirements.java
1
/**
2
* Copyright (C) 2012 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.cdm.server;
10

  
11
/**
12
 * @author a.kohlbecker
13
 * @date May 10, 2013
14
 *
15
 */
16
public class AssumedMemoryRequirements {
17

  
18
    // memory requirements
19
	public static final int KB = 1024;
20
	public static final long MB = 1024 * KB;
21
    public static final long PERM_GEN_SPACE_PER_INSTANCE = 55 * MB;
22
    public static final long HEAP_PER_INSTANCE = 130 * MB;
23
    public static final long PERM_GEN_SPACE_CDMSERVER = 19 * MB;
24
    public static final long HEAP_CDMSERVER = 15 * MB;
25

  
26
}
src/main/java/eu/etaxonomy/cdm/server/Bootloader.java
10 10

  
11 11
package eu.etaxonomy.cdm.server;
12 12

  
13
import static eu.etaxonomy.cdm.server.AssumedMemoryRequirements.KB;
13 14
import static eu.etaxonomy.cdm.server.CommandOptions.DATASOURCES_FILE;
14 15
import static eu.etaxonomy.cdm.server.CommandOptions.HELP;
15 16
import static eu.etaxonomy.cdm.server.CommandOptions.HTTP_PORT;
......
49 50
import org.eclipse.jetty.jmx.MBeanContainer;
50 51
import org.eclipse.jetty.security.HashLoginService;
51 52
import org.eclipse.jetty.server.Server;
52
import org.eclipse.jetty.server.handler.ContextHandler.Context;
53 53
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
54
import org.eclipse.jetty.util.component.LifeCycle;
55
import org.eclipse.jetty.util.component.LifeCycle.Listener;
56 54
import org.eclipse.jetty.util.log.Log;
57 55
import org.eclipse.jetty.webapp.WebAppClassLoader;
58 56
import org.eclipse.jetty.webapp.WebAppContext;
59 57

  
60
import eu.etaxonomy.cdm.server.CdmInstanceProperties.Status;
58
import eu.etaxonomy.cdm.server.instance.CdmInstance;
59
import eu.etaxonomy.cdm.server.instance.Configuration;
60
import eu.etaxonomy.cdm.server.instance.InstanceManager;
61
import eu.etaxonomy.cdm.server.instance.Status;
61 62
import eu.etaxonomy.cdm.server.win32service.Win32Service;
62 63

  
63 64

  
......
88 89

  
89 90

  
90 91

  
91
    /**
92
     * @author a.kohlbecker
93
     * @date 03.02.2011
94
     *
95
     */
96
    private class WebAppContextListener implements Listener {
97

  
98
        WebAppContext cdmWebappContext;
99
        /**
100
         * @param cdmWebappContext
101
         */
102
        public WebAppContextListener(WebAppContext cdmWebappContext) {
103
            this.cdmWebappContext = cdmWebappContext;
104
        }
105

  
106
        @Override
107
        public void lifeCycleStopping(LifeCycle event) {
108
            logger.info("lifeCycleStopping");
109
        }
110

  
111
        @Override
112
        public void lifeCycleStopped(LifeCycle event) {
113
            logger.info("lifeCycleStopped");
114

  
115
        }
116

  
117
        @Override
118
        public void lifeCycleStarting(LifeCycle event) {
119
            logger.info("lifeCycleStarting");
120
        }
121

  
122
        @SuppressWarnings("unchecked")
123
        @Override
124
        public void lifeCycleStarted(LifeCycle event) {
125
            logger.info("lifeCycleStarted");
126

  
127
            List<String> messages = getServletContextAttribute(cdmWebappContext, ATTRIBUTE_ERROR_MESSAGES, List.class);
128
            String dataSourceName = getServletContextAttribute(cdmWebappContext, ATTRIBUTE_DATASOURCE_NAME, String.class);
129

  
130
            if(messages != null && dataSourceName != null){
131
                CdmInstanceProperties configAndStatus = findConfigAndStatusFor(dataSourceName);
132
                configAndStatus.getProblems().addAll(messages);
133
                configAndStatus.setStatus(Status.error);
134
                try {
135
                    logger.warn("Stopping context '" + dataSourceName + "' due to errors reported in ServletContext");
136
                    cdmWebappContext.stop();
137
                } catch (Exception e) {
138
                    logger.error(e);
139
                }
140
            }
141
        }
142

  
143

  
144
        @Override
145
        public void lifeCycleFailure(LifeCycle event, Throwable cause) {
146
            logger.error("lifeCycleFailure");
147
        }
148
    }
149

  
150 92
    private static final Logger logger = Logger.getLogger(Bootloader.class);
151 93

  
152 94
    private static final String DATASOURCE_BEANDEF_FILE = "datasources.xml";
......
167 109
    private static final File CDM_WEBAPP_TEMP_FOLDER = new File(TMP_PATH + CDMLIB_REMOTE_WEBAPP);
168 110

  
169 111
    private static final String ATTRIBUTE_JDBC_JNDI_NAME = "cdm.jdbcJndiName";
170
    private static final String ATTRIBUTE_DATASOURCE_NAME = "cdm.datasource";
112
    public static final String ATTRIBUTE_DATASOURCE_NAME = "cdm.datasource";
171 113
    private static final String ATTRIBUTE_CDM_LOGFILE = "cdm.logfile";
172 114
    /**
173 115
     * same as in eu.etaxonomy.cdm.remote.config.DataSourceConfigurer
174 116
     */
175
    private static final String ATTRIBUTE_ERROR_MESSAGES = "cdm.errorMessages";
176

  
117
    public static final String ATTRIBUTE_ERROR_MESSAGES = "cdm.errorMessages";
177 118

  
178
    // memory requirements
179
    private static final int KB = 1024;
180
    private static final long MB = 1024 * KB;
181
    public static final long PERM_GEN_SPACE_PER_INSTANCE = 55 * MB;
182
    public static final long HEAP_PER_INSTANCE = 130 * MB;
183
    public static final long PERM_GEN_SPACE_CDMSERVER = 19 * MB;
184
    public static final long HEAP_CDMSERVER = 15 * MB;
185 119

  
120
    private final InstanceManager instanceManager = new InstanceManager(new File(USERHOME_CDM_LIBRARY_PATH, DATASOURCE_BEANDEF_FILE));
186 121

  
122
    public List<CdmInstance> getCdmInstances() {
123
        return instanceManager.getInstances();
124
    }
187 125

  
188
    private List<CdmInstanceProperties> configAndStatusList = null;
189

  
190
    public List<CdmInstanceProperties> getConfigAndStatus() {
191
        return configAndStatusList;
126
    public InstanceManager getInstanceManager(){
127
    	return instanceManager;
192 128
    }
193 129

  
194 130
    private File cdmRemoteWebAppFile = null;
......
203 139

  
204 140
    /* thread save singleton implementation */
205 141

  
206
    private static Bootloader instance = new Bootloader();
142
    private static Bootloader bootloader = new Bootloader();
207 143

  
208 144
    private Bootloader() {}
209 145

  
......
211 147
     * @return the thread save singleton instance of the Bootloader
212 148
     */
213 149
    public synchronized static Bootloader getBootloader(){
214
        return instance;
150
        return bootloader;
215 151
    }
216 152

  
217 153
    /* end of singleton implementation */
218 154

  
219
    private List<CdmInstanceProperties> loadDataSources(){
220
        if(configAndStatusList == null){
221
            File datasourcesFile = new File(USERHOME_CDM_LIBRARY_PATH, DATASOURCE_BEANDEF_FILE);
222
            configAndStatusList = DataSourcePropertyParser.parseDataSourceConfigs(datasourcesFile);
223
            logger.info("cdm server instance names loaded: "+ configAndStatusList.toString());
224
        }
225
        return configAndStatusList;
226
    }
227 155

  
228 156
    public int writeStreamTo(final InputStream input, final OutputStream output, int bufferSize) throws IOException {
229 157
        int available = Math.min(input.available(), 256 * KB);
......
238 166
        return answer;
239 167
    }
240 168

  
241
    private boolean bindJndiDataSource(CdmInstanceProperties conf) {
169
    private boolean bindJndiDataSource(CdmInstance instance) {
242 170
        try {
171
        	Configuration conf = instance.getConfiguration();
243 172
            Class<DataSource> dsCass = (Class<DataSource>) Thread.currentThread().getContextClassLoader().loadClass("com.mchange.v2.c3p0.ComboPooledDataSource");
244 173
            DataSource datasource = dsCass.newInstance();
245 174
            dsCass.getMethod("setDriverClass", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getDriverClass()});
246
            dsCass.getMethod("setJdbcUrl", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getUrl()});
175
            dsCass.getMethod("setJdbcUrl", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getDataSourceUrl()});
247 176
            dsCass.getMethod("setUser", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getUsername()});
248 177
            dsCass.getMethod("setPassword", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getPassword()});
249 178

  
......
254 183
                connection.close();
255 184
            } catch (SQLException e) {
256 185
                sqlerror = e.getMessage() + "["+ e.getSQLState() + "]";
257
                conf.getProblems().add(sqlerror);
186
                instance.getProblems().add(sqlerror);
258 187
                if(connection !=  null){
259 188
                    try {connection.close();} catch (SQLException e1) { /* IGNORE */ }
260 189
                }
261 190
                logger.error(conf.toString() + " has problem : "+ sqlerror );
262 191
            }
263 192

  
264
            if(!conf.hasProblems()){
265
                logger.info("binding jndi datasource at " + conf.getJdbcJndiName() + " with "+conf.getUsername() +"@"+ conf.getUrl());
193
            if(!instance.hasProblems()){
194
                logger.info("binding jndi datasource at " + conf.getJdbcJndiName() + " with "+conf.getUsername() +"@"+ conf.getDataSourceUrl());
266 195
                org.eclipse.jetty.plus.jndi.Resource jdbcResource = new org.eclipse.jetty.plus.jndi.Resource(conf.getJdbcJndiName(), datasource);
267 196
                return true;
268 197
            }
......
433 362
             logger.error(DATASOURCES_FILE.getOpt() + " NOT JET IMPLEMENTED!!!");
434 363
         }
435 364

  
436
        loadDataSources();
437

  
438
        verifyMemoryRequirements();
439

  
440 365
        verifySystemResources();
441 366

  
367
         // load the configured instances for the first time
368
        instanceManager.reLoadInstanceConfigurations();
442 369

  
443 370
        server = new Server(httpPort);
371
        server.addLifeCycleListener(instanceManager);
444 372

  
445 373
        // JMX support
446 374
        if(cmdLine.hasOption(JMX.getOpt())){
......
458 386
            server.addBean(win32Service);
459 387
        }
460 388

  
461
        // add servelet contexts
462

  
463

  
464
        //
465
        // 1. default context
466
        //
389
        // add default servlet context
467 390
        logger.info("preparing default WebAppContext");
468 391
        WebAppContext defaultWebappContext = new WebAppContext();
469 392

  
......
484 407
        defaultWebappContext.setClassLoader(this.getClass().getClassLoader());
485 408
        contexts.addHandler(defaultWebappContext);
486 409

  
487
        //
488
        // 2. cdm server contexts
489
        //
490
        server.addLifeCycleListener(new LifeCycle.Listener(){
491

  
492
            @Override
493
            public void lifeCycleFailure(LifeCycle event, Throwable cause) {
494
                logger.error("Jetty LifeCycleFailure", cause);
495
            }
496

  
497
            @Override
498
            public void lifeCycleStarted(LifeCycle event) {
499
                logger.info("cdmserver has started, now adding CDM server contexts");
500
                try {
501
                    addCdmServerContexts(true);
502
                } catch (IOException e1) {
503
                    logger.error(e1);
504
                }
505
            }
506

  
507
            @Override
508
            public void lifeCycleStarting(LifeCycle event) {
509
            }
510

  
511
            @Override
512
            public void lifeCycleStopped(LifeCycle event) {
513
            }
514

  
515
            @Override
516
            public void lifeCycleStopping(LifeCycle event) {
517
            }
518

  
519
            });
520

  
521

  
522 410
        logger.info("setting contexts ...");
523 411
        server.setHandler(contexts);
524 412
        logger.info("starting jetty ...");
......
560 448
        return version;
561 449
    }
562 450

  
563
    /**
564
     *
565
     */
566
    private void verifyMemoryRequirements() {
567

  
568
        verifyMemoryRequirement("PermGenSpace", PERM_GEN_SPACE_CDMSERVER, PERM_GEN_SPACE_PER_INSTANCE, JvmManager.getPermGenSpaceUsage().getMax());
569
        verifyMemoryRequirement("HeapSpace", HEAP_CDMSERVER, HEAP_PER_INSTANCE, JvmManager.getHeapMemoryUsage().getMax());
570 451

  
571
    }
572 452

  
573 453
    private void verifySystemResources() {
574 454

  
......
592 472
        }
593 473
    }
594 474

  
595
    private void verifyMemoryRequirement(String memoryName, long requiredSpaceServer, long requiredSpacePerInstance, long availableSpace) {
596

  
597

  
598
        long recommendedMinimumSpace = recommendedMinimumSpace(requiredSpaceServer, requiredSpacePerInstance, null);
599

  
600
        if(recommendedMinimumSpace > availableSpace){
601

  
602
            String message = memoryName + " ("
603
                + (availableSpace / MB)
604
                + "MB) insufficient for "
605
                + configAndStatusList.size()
606
                + " instances. Increase " + memoryName + " to "
607
                + (recommendedMinimumSpace / MB)
608
                + "MB";
609
                ;
610
            logger.error(message + " => disabling some instances!!!");
611

  
612
            // disabling some instances
613
            int i=0;
614
            for(CdmInstanceProperties instanceProps : configAndStatusList){
615
                i++;
616
                if(recommendedMinimumSpace(requiredSpaceServer, requiredSpacePerInstance, i)  > availableSpace){
617
                    instanceProps.setStatus(Status.disabled);
618
                    instanceProps.getProblems().add("Disabled due to: " + message);
619
                }
620
            }
621
        }
622
    }
623

  
624
    /**
625
     * @param requiredServerSpace
626
     * @param requiredSpacePerIntance
627
     * @param numOfInstances may be null, the total number of instances found in the current configuration is used in this case.
628
     * @return
629
     */
630
    public long recommendedMinimumSpace(long requiredServerSpace, long requiredSpacePerIntance, Integer numOfInstances) {
631
        if(numOfInstances == null){
632
            numOfInstances = configAndStatusList.size();
633
        }
634
        return (numOfInstances * requiredSpacePerIntance) + requiredServerSpace;
635
    }
636 475

  
637 476
    /**
638 477
     * Configures and adds a {@link RollingFileAppender} to the root logger
......
655 494
        }
656 495
    }
657 496

  
658
    private void addCdmServerContexts(boolean austostart) throws IOException {
659

  
660
        for(CdmInstanceProperties conf : configAndStatusList){
661

  
662
            if(!conf.isEnabled()){
663
                logger.info(conf.getDataSourceName() + " is disabled due to JVM memory limitations => skipping");
664
                continue;
665
            }
666
            conf.setStatus(CdmInstanceProperties.Status.initializing);
667
            logger.info("preparing WebAppContext for '"+ conf.getDataSourceName() + "'");
668
            WebAppContext cdmWebappContext = new WebAppContext();
669

  
670
            cdmWebappContext.setContextPath("/"+conf.getDataSourceName());
671
            cdmWebappContext.setTempDirectory(CDM_WEBAPP_TEMP_FOLDER);
672

  
673
            if(!bindJndiDataSource(conf)){
674
                // a problem with the datasource occurred skip this webapp
675
                cdmWebappContext = null;
676
                logger.error("a problem with the datasource occurred -> skipping /" + conf.getDataSourceName());
677
                conf.setStatus(CdmInstanceProperties.Status.error);
678
                continue;
679
            }
680

  
681
            cdmWebappContext.setAttribute(ATTRIBUTE_DATASOURCE_NAME, conf.getDataSourceName());
682
            cdmWebappContext.setAttribute(ATTRIBUTE_JDBC_JNDI_NAME, conf.getJdbcJndiName());
683
            setWebApp(cdmWebappContext, cdmRemoteWebAppFile);
684

  
685
            cdmWebappContext.setAttribute(ATTRIBUTE_CDM_LOGFILE,
686
                    logPath + File.separator + "cdm-"
687
                            + conf.getDataSourceName() + ".log");
688 497

  
689
            if(cdmRemoteWebAppFile.isDirectory() && isRunningFromCdmRemoteWebAppSource()){
690

  
691
                /*
692
                 * when running the webapp from {projectpath} src/main/webapp we
693
                 * must assure that each web application is using it's own
694
                 * classloader thus we tell the WebAppClassLoader where the
695
                 * dependencies of the webapplication can be found. Otherwise
696
                 * the system classloader would load these resources.
697
                 */
698
                logger.info("Running webapp from source folder, thus adding java.class.path to WebAppClassLoader");
699

  
700
                WebAppClassLoader classLoader = new WebAppClassLoader(cdmWebappContext);
701

  
702
                String classPath = System.getProperty("java.class.path");
703
                classLoader.addClassPath(classPath);
704
                cdmWebappContext.setClassLoader(classLoader);
705
            }
706

  
707
            cdmWebappContext.addLifeCycleListener(new WebAppContextListener(cdmWebappContext));
708
            contexts.addHandler(cdmWebappContext);
709

  
710
            if(austostart){
711
                try {
712
                    conf.setStatus(CdmInstanceProperties.Status.starting);
713
                    cdmWebappContext.start();
714
                    if(!conf.getStatus().equals(Status.error)){
715
                        conf.setStatus(CdmInstanceProperties.Status.started);
716
                    }
717
                } catch (Exception e) {
718
                    logger.error("Could not start " + cdmWebappContext.getContextPath());
719
                    conf.setStatus(CdmInstanceProperties.Status.error);
720
                }
721
            }
722

  
723
        }
724
    }
498
	/**
499
	 * @param conf
500
	 * @param austostart
501
	 * @return
502
	 * @throws IOException
503
	 */
504
	public WebAppContext addCdmInstanceContext(CdmInstance instance) throws IOException {
505
		Configuration conf = instance.getConfiguration();
506
		if(!instance.isEnabled()){
507
		    logger.info(conf.getInstanceName() + " is disabled due to JVM memory limitations => skipping");
508
		    return null;
509
		}
510
		instance.setStatus(Status.initializing);
511
		logger.info("preparing WebAppContext for '"+ conf.getInstanceName() + "'");
512
		WebAppContext cdmWebappContext = new WebAppContext();
513

  
514
		cdmWebappContext.setContextPath("/"+conf.getInstanceName());
515
		cdmWebappContext.setTempDirectory(CDM_WEBAPP_TEMP_FOLDER);
516

  
517
		if(!bindJndiDataSource(instance)){
518
		    // a problem with the datasource occurred skip this webapp
519
		    cdmWebappContext = null;
520
		    logger.error("a problem with the datasource occurred -> skipping /" + conf.getInstanceName());
521
		    instance.setStatus(Status.error);
522
		    return cdmWebappContext;
523
		}
524

  
525
		cdmWebappContext.setAttribute(ATTRIBUTE_DATASOURCE_NAME, conf.getInstanceName());
526
		cdmWebappContext.setAttribute(ATTRIBUTE_JDBC_JNDI_NAME, conf.getJdbcJndiName());
527
		setWebApp(cdmWebappContext, cdmRemoteWebAppFile);
528

  
529
		cdmWebappContext.setAttribute(ATTRIBUTE_CDM_LOGFILE,
530
		        logPath + File.separator + "cdm-"
531
		                + conf.getInstanceName() + ".log");
532

  
533
		if(cdmRemoteWebAppFile.isDirectory() && isRunningFromCdmRemoteWebAppSource()){
534

  
535
		    /*
536
		     * when running the webapp from {projectpath} src/main/webapp we
537
		     * must assure that each web application is using it's own
538
		     * classloader thus we tell the WebAppClassLoader where the
539
		     * dependencies of the webapplication can be found. Otherwise
540
		     * the system classloader would load these resources.
541
		     */
542
		    logger.info("Running webapp from source folder, thus adding java.class.path to WebAppClassLoader");
543

  
544
		    WebAppClassLoader classLoader = new WebAppClassLoader(cdmWebappContext);
545

  
546
		    String classPath = System.getProperty("java.class.path");
547
		    classLoader.addClassPath(classPath);
548
		    cdmWebappContext.setClassLoader(classLoader);
549
		}
550

  
551
		contexts.addHandler(cdmWebappContext);
552
		instance.setWebAppContext(cdmWebappContext);
553
		cdmWebappContext.addLifeCycleListener(instance);
554

  
555
		return cdmWebappContext;
556
	}
725 557

  
726 558
    /**
559
     * Sets the webapp specified by the <code>webApplicationResource</code> to
560
     * the given <code>context</code>.
561
     *
727 562
     * @param context
728
     * @param webApplicationResource
563
     * @param webApplicationResource the resource can either be a directory containing
564
     * a Java web application or *.war file.
565
     *
729 566
     */
730 567
    private void setWebApp(WebAppContext context, File webApplicationResource) {
731 568
        if(webApplicationResource.isDirectory()){
......
745 582
        return webappPathNormalized.endsWith("src/main/webapp") || webappPathNormalized.endsWith("cdmlib-remote-webapp/target/cdmserver");
746 583
    }
747 584

  
748
    /**
749
     * @param dataSourceName
750
     * @return
751
     */
752
    private CdmInstanceProperties findConfigAndStatusFor(String dataSourceName){
753
        for(CdmInstanceProperties props : configAndStatusList){
754
            if(props.getDataSourceName().equals(dataSourceName)){
755
                return props;
756
            }
757
        }
758
        return null;
759
    }
760

  
761
    /**
762
     * @param <T>
763
     * @param webAppContext
764
     * @param attributeName
765
     * @param type
766
     * @return
767
     */
768
    @SuppressWarnings("unchecked")
769
    private <T> T getServletContextAttribute(WebAppContext webAppContext, String attributeName, Class<T> type) {
770

  
771
        Context servletContext = webAppContext.getServletContext();
772
        Object value = servletContext.getAttribute(attributeName);
773
        if( value != null && type.isAssignableFrom(value.getClass())){
774

  
775
        }
776
        return (T) value;
777
    }
778 585

  
779 586
    public Server getServer() {
780 587
        return server;
src/main/java/eu/etaxonomy/cdm/server/CdmInstanceProperties.java
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 java.util.ArrayList;
14
import java.util.List;
15

  
16
import org.apache.log4j.Logger;
17

  
18
public class CdmInstanceProperties {
19
 
20
	public static final Logger logger = Logger.getLogger(CdmInstanceProperties.class);
21

  
22
	private String dataSourceName;
23
	private String password;
24
	private String username;
25
	private String url;
26
	private String driverClass;
27
	private List<String> problems;
28
	private Status status = Status.uninitialized;
29
	
30
	public List<String> getProblems() {
31
		if(problems == null){
32
			problems = new ArrayList<String>();
33
		}
34
		return problems;
35
	}
36
	public void setProblems(List<String> problems) {
37
		this.problems = problems;
38
	}
39
	public boolean hasProblems() {
40
		return getProblems().size() > 0;
41
	}
42
	
43
	public String getDataSourceName() {
44
		return dataSourceName;
45
	}
46
	public String getJdbcJndiName() {
47
		return "jdbc/"+dataSourceName;
48
	}
49
	
50
	public void setDataSourceName(String dataSourceName) {
51
		this.dataSourceName = dataSourceName;
52
	}
53
	public String getPassword() {
54
		return password;
55
	}
56
	public void setPassword(String password) {
57
		this.password = password;
58
	}
59
	public String getUsername() {
60
		return username;
61
	}
62
	public void setUsername(String username) {
63
		this.username = username;
64
	}
65
	public String getUrl() {
66
		return url;
67
	}
68
	public void setUrl(String url) {
69
		this.url = url;
70
	}
71
	public String getDriverClass() {
72
		return driverClass;
73
	}
74
	public void setDriverClass(String driverClass) {
75
		this.driverClass = driverClass;
76
	}
77
	
78
	@Override
79
	public String toString(){
80
		return dataSourceName + " : " +  username + "@" + url;
81
		
82
	}
83
	
84
	/**
85
	 * @param status the status to set
86
	 */
87
	public void setStatus(Status status) {
88
		this.status = status;
89
	}
90
	/**
91
	 * @return the status
92
	 */
93
	public Status getStatus() {
94
		return status;
95
	}
96

  
97
	/**
98
	 * @return the enabled
99
	 */
100
	public boolean isEnabled() {
101
		return !status.equals(Status.disabled);
102
	}
103

  
104
	public enum Status{
105
		uninitialized,
106
		initializing,
107
		starting,
108
		started,
109
		stopped,
110
		error,
111
		disabled
112
	}
113
}
src/main/java/eu/etaxonomy/cdm/server/DataSourcePropertyParser.java
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
package eu.etaxonomy.cdm.server;
11

  
12
import java.io.File;
13
import java.io.IOException;
14
import java.util.ArrayList;
15
import java.util.HashSet;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Set;
19

  
20
import javax.xml.parsers.DocumentBuilder;
21
import javax.xml.parsers.DocumentBuilderFactory;
22
import javax.xml.parsers.ParserConfigurationException;
23

  
24
import org.apache.log4j.Logger;
25
import org.w3c.dom.Document;
26
import org.w3c.dom.NamedNodeMap;
27
import org.w3c.dom.Node;
28
import org.w3c.dom.NodeList;
29
import org.xml.sax.SAXException;
30

  
31
/**
32
 * @author a.kohlbecker
33
 * @date 30.03.2010
34
 *
35
 */
36
public class DataSourcePropertyParser {
37

  
38
    public static final Logger logger = Logger.getLogger(DataSourcePropertyParser.class);
39

  
40
    public static List<CdmInstanceProperties> parseDataSourceConfigs(File datasourcesFile){
41

  
42
        logger.info("loading bean definition file: " + datasourcesFile.getAbsolutePath());
43
        List<CdmInstanceProperties> configList = new ArrayList<CdmInstanceProperties>();
44
        Set<String> idSet = new HashSet<String>();
45
        try {
46
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
47
            Document doc = builder.parse(datasourcesFile);
48
            NodeList beanNodes  = doc.getElementsByTagName("bean");
49
            for(int i=0; i < beanNodes.getLength(); i++){
50
                CdmInstanceProperties conf = new CdmInstanceProperties();
51
                Node beanNode = beanNodes.item(i);
52
                // ATTRIBUTE_DATASOURCE_NAME
53
                NamedNodeMap namedNodeMap = beanNode.getAttributes();
54
                String beanId = namedNodeMap.getNamedItem("id").getNodeValue();
55

  
56

  
57
                conf.setDataSourceName(beanId);
58
                // ATTRIBUTE_DATASOURCE_DRIVERCLASS
59
                String driverClass = getXMLNodeProperty(beanNode, "driverClass");
60

  
61
                if(driverClass == null || driverClass.isEmpty()){
62
                    // not a data source bean
63
                    continue;
64
                }
65

  
66
                conf.setDriverClass(driverClass);
67
                conf.setUsername(getXMLNodeProperty(beanNode, "username"));
68
                if(conf.getUsername() == null){
69
                    conf.setUsername(getXMLNodeProperty(beanNode, "user"));
70
                }
71
                conf.setPassword(getXMLNodeProperty(beanNode, "password"));
72

  
73
                conf.setUrl(getXMLNodeProperty(beanNode, "url"));
74
                if(conf.getUrl() == null){
75
                    conf.setUrl(getXMLNodeProperty(beanNode, "jdbcUrl"));
76
                }
77

  
78
                if(idSet.add(conf.getDataSourceName())) {
79
                    logger.debug("adding instanceName '"+ conf.getDataSourceName() + "'");
80
                    configList.add(conf);
81
                } else {
82
                    logger.error("instance with name '"+ conf.getDataSourceName() + "' alreaddy exists");
83
                }
84

  
85
            }
86

  
87
        } catch (SAXException e) {
88
            // TODO Auto-generated catch block
89
            e.printStackTrace();
90
        } catch (IOException e) {
91
            // TODO Auto-generated catch block
92
            e.printStackTrace();
93
        } catch (ParserConfigurationException e) {
94
            // TODO Auto-generated catch block
95
            e.printStackTrace();
96
        }
97
        return configList;
98

  
99
    }
100

  
101
    private static String getXMLNodeProperty(Node beanNode, String name){
102
        NodeList children = beanNode.getChildNodes();
103
        for(int i=0; i < children.getLength(); i++){
104
            Node p = children.item(i);
105
            if(p.getNodeName().equals("property")
106
                    && p.getAttributes().getNamedItem("name").getNodeValue().equals(name)){
107
                return p.getAttributes().getNamedItem("value").getNodeValue();
108
            }
109
        }
110
        return null;
111
    }
112

  
113

  
114

  
115
}
src/main/java/eu/etaxonomy/cdm/server/instance/CdmInstance.java
1
package eu.etaxonomy.cdm.server.instance;
2

  
3
import java.util.ArrayList;
4
import java.util.List;
5

  
6
import org.apache.log4j.Logger;
7
import org.eclipse.jetty.server.handler.ContextHandler.Context;
8
import org.eclipse.jetty.util.component.LifeCycle;
9
import org.eclipse.jetty.util.component.LifeCycle.Listener;
10
import org.eclipse.jetty.webapp.WebAppContext;
11

  
12
import eu.etaxonomy.cdm.server.Bootloader;
13

  
14
public class CdmInstance implements Listener {
15

  
16
	private static final Logger logger = Logger.getLogger(InstanceManager.class);
17

  
18
	private WebAppContext webAppContext = null;
19

  
20
	private final Configuration configuration;
21

  
22
	private List<String> problems;
23
	private Status status = Status.uninitialized;
24

  
25
	public CdmInstance(Configuration configuration) {
26
		this.configuration = configuration;
27
	}
28

  
29
	public List<String> getProblems() {
30
		if (problems == null) {
31
			problems = new ArrayList<String>();
32
		}
33
		return problems;
34
	}
35

  
36
	public void setProblems(List<String> problems) {
37
		this.problems = problems;
38
	}
39

  
40
	public boolean hasProblems() {
41
		return getProblems().size() > 0;
42
	}
43

  
44
	/**
45
	 * @param status
46
	 *            the status to set
47
	 */
48
	public void setStatus(Status status) {
49
		this.status = status;
50
	}
51

  
52
	/**
53
	 * @return the status
54
	 */
55
	public Status getStatus() {
56
		return status;
57
	}
58

  
59
	/**
60
	 * @return the enabled
61
	 */
62
	public boolean isEnabled() {
63
		return !status.equals(Status.disabled);
64
	}
65

  
66
	/**
67
	 * @return the configuration
68
	 */
69
	public Configuration getConfiguration() {
70
		return configuration;
71
	}
72

  
73
	/**
74
	 * @return the webAppContext
75
	 */
76
	public WebAppContext getWebAppContext() {
77
		return webAppContext;
78
	}
79

  
80
	/**
81
	 * @return the webAppContext
82
	 */
83
	public void setWebAppContext(WebAppContext webAppContext) {
84
		this.webAppContext = webAppContext;
85
	}
86

  
87
	/**
88
	 * @param <T>
89
	 * @param webAppContext
90
	 * @param attributeName
91
	 * @param type
92
	 * @return
93
	 */
94
	@SuppressWarnings("unchecked")
95
	private <T> T getServletContextAttribute(WebAppContext webAppContext, String attributeName, Class<T> type) {
96

  
97
		Context servletContext = webAppContext.getServletContext();
98
		Object value = servletContext.getAttribute(attributeName);
99
		if (value != null && type.isAssignableFrom(value.getClass())) {
100

  
101
		}
102
		return (T) value;
103
	}
104

  
105
	@Override
106
	public void lifeCycleStopping(LifeCycle event) {
107
		logger.info("lifeCycleStopping");
108
	}
109

  
110
	@Override
111
	public void lifeCycleStopped(LifeCycle event) {
112
		logger.info("lifeCycleStopped");
113

  
114
	}
115

  
116
	@Override
117
	public void lifeCycleStarting(LifeCycle event) {
118
		logger.info("lifeCycleStarting");
119
	}
120

  
121
	@SuppressWarnings("unchecked")
122
	@Override
123
	public void lifeCycleStarted(LifeCycle event) {
124
		logger.info("lifeCycleStarted");
125

  
126
		List<String> messages = getServletContextAttribute(webAppContext, Bootloader.ATTRIBUTE_ERROR_MESSAGES, List.class);
127
		String dataSourceName = getServletContextAttribute(webAppContext, Bootloader.ATTRIBUTE_DATASOURCE_NAME, String.class);
128

  
129
		if (messages != null && dataSourceName != null) {
130

  
131
			getProblems().addAll(messages);
132
			setStatus(Status.error);
133
			try {
134
				logger.warn("Stopping context '" + dataSourceName + "' due to errors reported in ServletContext");
135
				webAppContext.stop();
136
			} catch (Exception e) {
137
				logger.error(e);
138
			}
139
		}
140
	}
141

  
142
	@Override
143
	public void lifeCycleFailure(LifeCycle event, Throwable cause) {
144
		logger.error("lifeCycleFailure");
145
	}
146

  
147
}
src/main/java/eu/etaxonomy/cdm/server/instance/Configuration.java
1
/**
2
 * Copyright (C) 2009 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

  
10
package eu.etaxonomy.cdm.server.instance;
11

  
12
import org.apache.log4j.Logger;
13

  
14
/**
15
 * @author a.kohlbecker
16
 * @date May 10, 2013
17
 *
18
 */
19
public class Configuration {
20

  
21
	public static final Logger logger = Logger.getLogger(Configuration.class);
22

  
23
	private String instanceName;
24
	private String password;
25
	private String username;
26
	private String dataSourceUrl;
27
	private String driverClass;
28

  
29
	public String getInstanceName() {
30
		return instanceName;
31
	}
32

  
33
	public void setInstanceName(String instanceName) {
34
		this.instanceName = instanceName;
35
	}
36

  
37
	public String getJdbcJndiName() {
38
		return "jdbc/" + instanceName;
39
	}
40

  
41
	public String getPassword() {
42
		return password;
43
	}
44

  
45
	public void setPassword(String password) {
46
		this.password = password;
47
	}
48

  
49
	public String getUsername() {
50
		return username;
51
	}
52

  
53
	public void setUsername(String username) {
54
		this.username = username;
55
	}
56

  
57
	public String getDataSourceUrl() {
58
		return dataSourceUrl;
59
	}
60

  
61
	public void setDataSourceUrl(String url) {
62
		this.dataSourceUrl = url;
63
	}
64

  
65
	public String getDriverClass() {
66
		return driverClass;
67
	}
68

  
69
	public void setDriverClass(String driverClass) {
70
		this.driverClass = driverClass;
71
	}
72

  
73
	@Override
74
	public String toString() {
75
		return instanceName + " : " + username + "@" + dataSourceUrl;
76

  
77
	}
78

  
79
	@Override
80
	public boolean equals(Object obj){
81
		if(obj == null || !(obj instanceof Configuration)){
82
			return false;
83
		}
84
		Configuration other = (Configuration)obj;
85
		return this.dataSourceUrl.equals(other.dataSourceUrl)
86
				&& this.driverClass.equals(other.driverClass)
87
				&& this.instanceName.equals(other.instanceName)
88
				&& this.password.equals(other.password)
89
				&& this.username.equals(other.username);
90
	}
91
}
src/main/java/eu/etaxonomy/cdm/server/instance/DataSourcePropertyParser.java
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
package eu.etaxonomy.cdm.server.instance;
11

  
12
import java.io.File;
13
import java.io.IOException;
14
import java.util.ArrayList;
15
import java.util.HashSet;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Set;
19

  
20
import javax.xml.parsers.DocumentBuilder;
21
import javax.xml.parsers.DocumentBuilderFactory;
22
import javax.xml.parsers.ParserConfigurationException;
23

  
24
import org.apache.log4j.Logger;
25
import org.w3c.dom.Document;
26
import org.w3c.dom.NamedNodeMap;
27
import org.w3c.dom.Node;
28
import org.w3c.dom.NodeList;
29
import org.xml.sax.SAXException;
30

  
31

  
32
/**
33
 * @author a.kohlbecker
34
 * @date 30.03.2010
35
 *
36
 */
37
public class DataSourcePropertyParser {
38

  
39
    public static final Logger logger = Logger.getLogger(DataSourcePropertyParser.class);
40

  
41
    public static List<Configuration> parseDataSourceConfigs(File datasourcesFile){
42

  
43
        logger.info("loading bean definition file: " + datasourcesFile.getAbsolutePath());
44
        List<Configuration> configList = new ArrayList<Configuration>();
45
        Set<String> idSet = new HashSet<String>();
46
        try {
47
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
48
            Document doc = builder.parse(datasourcesFile);
49
            NodeList beanNodes  = doc.getElementsByTagName("bean");
50
            for(int i=0; i < beanNodes.getLength(); i++){
51
                Configuration conf = new Configuration();
52
                Node beanNode = beanNodes.item(i);
53
                // ATTRIBUTE_DATASOURCE_NAME
54
                NamedNodeMap namedNodeMap = beanNode.getAttributes();
55
                String beanId = namedNodeMap.getNamedItem("id").getNodeValue();
56

  
57

  
58
                conf.setInstanceName(beanId);
59
                // ATTRIBUTE_DATASOURCE_DRIVERCLASS
60
                String driverClass = getXMLNodeProperty(beanNode, "driverClass");
61

  
62
                if(driverClass == null || driverClass.isEmpty()){
63
                    // not a data source bean
64
                    continue;
65
                }
66

  
67
                conf.setDriverClass(driverClass);
68
                conf.setUsername(getXMLNodeProperty(beanNode, "username"));
69
                if(conf.getUsername() == null){
70
                    conf.setUsername(getXMLNodeProperty(beanNode, "user"));
71
                }
72
                conf.setPassword(getXMLNodeProperty(beanNode, "password"));
73

  
74
                conf.setDataSourceUrl(getXMLNodeProperty(beanNode, "url"));
75
                if(conf.getDataSourceUrl() == null){
76
                    conf.setDataSourceUrl(getXMLNodeProperty(beanNode, "jdbcUrl"));
77
                }
78

  
79
                if(idSet.add(conf.getInstanceName())) {
80
                    logger.debug("adding instanceName '"+ conf.getInstanceName() + "'");
81
                    configList.add(conf);
82
                } else {
83
                    logger.error("instance with name '"+ conf.getInstanceName() + "' alreaddy exists");
84
                }
85

  
86
            }
87

  
88
        } catch (SAXException e) {
89
            // TODO Auto-generated catch block
90
            e.printStackTrace();
91
        } catch (IOException e) {
92
            // TODO Auto-generated catch block
93
            e.printStackTrace();
94
        } catch (ParserConfigurationException e) {
95
            // TODO Auto-generated catch block
96
            e.printStackTrace();
97
        }
98
        return configList;
99

  
100
    }
101

  
102
    private static String getXMLNodeProperty(Node beanNode, String name){
103
        NodeList children = beanNode.getChildNodes();
104
        for(int i=0; i < children.getLength(); i++){
105
            Node p = children.item(i);
106
            if(p.getNodeName().equals("property")
107
                    && p.getAttributes().getNamedItem("name").getNodeValue().equals(name)){
108
                return p.getAttributes().getNamedItem("value").getNodeValue();
109
            }
110
        }
111
        return null;
112
    }
113

  
114

  
115

  
116
}
src/main/java/eu/etaxonomy/cdm/server/instance/InstanceManager.java
1
/**
2
 * Copyright (C) 2013 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.cdm.server.instance;
10

  
11
import static eu.etaxonomy.cdm.server.AssumedMemoryRequirements.HEAP_CDMSERVER;
12
import static eu.etaxonomy.cdm.server.AssumedMemoryRequirements.HEAP_PER_INSTANCE;
13
import static eu.etaxonomy.cdm.server.AssumedMemoryRequirements.MB;
14
import static eu.etaxonomy.cdm.server.AssumedMemoryRequirements.PERM_GEN_SPACE_CDMSERVER;
15
import static eu.etaxonomy.cdm.server.AssumedMemoryRequirements.PERM_GEN_SPACE_PER_INSTANCE;
16

  
17
import java.io.File;
18
import java.io.IOException;
19
import java.util.List;
20

  
21
import org.apache.commons.collections.map.ListOrderedMap;
22
import org.apache.log4j.Logger;
23
import org.eclipse.jetty.util.component.LifeCycle;
24

  
25
import eu.etaxonomy.cdm.server.Bootloader;
26
import eu.etaxonomy.cdm.server.JvmManager;
27

  
28
/**
29
 * Manager to load / reload list of instances the instance manager holds the
30
 * list of {@link CdmInstance}, the list can be updated, the instances are
31
 * identified by the bean id map<String,CdmInstance>
32
 *
33
 * The instance list is initially empty, all instances are usually started after
34
 * loading the list, see {@#loadDataSources()}
35
 *
36
 * @author a.kohlbecker
37
 * @date May 10, 2013
38
 */
39
public class InstanceManager implements LifeCycle.Listener {
40

  
41
	private static final Logger logger = Logger.getLogger(InstanceManager.class);
42

  
43
	boolean serverIsRunning = false;
44

  
45
	private final File datasourcesFile;
46
	private ListOrderedMap instances = new ListOrderedMap();
47

  
48
	private final boolean austostart = true;
49

  
50
	public InstanceManager(File configurationFile) {
51
		this.datasourcesFile = configurationFile;
52
	}
53

  
54
	/**
55
	 * this list of instances may contain removed
56
	 * instances.
57
	 * {@link #numOfConfiguredInstances()}
58
	 * @return the instances
59
	 */
60
	@SuppressWarnings("unchecked")
61
	public List<CdmInstance> getInstances() {
62
		return instances.valueList();
63
	}
64

  
65
	/**
66
	 * @return the number of existing instances, former instances which have been
67
	 * removed are not counted
68
	 */
69
	public int numOfConfiguredInstances(){
70
		int cnt=0;
71
		for(CdmInstance instance : getInstances()){
72
			if(instance.getStatus().equals(Status.removed)){
73
				continue;
74
			}
75
			cnt++;
76
		}
77
		return cnt;
78
	}
79

  
80
	/**
81
	 * loads and reloads the list of instances.
82
	 * After loading the configuration the required memory is checked
83
	 * <p>
84
	 * reload behavior:
85
	 * <ol>
86
	 * <li>newly added instances are created but are not started automatically</li>
87
	 * <li>removed instances are stopped, configuration and context are removed,
88
	 * state is set to Status.removed to indicate removal, removed instances can
89
	 * be re-added.</li>
90
	 * <li>the order of instances as defined in the config file is always retained
91
	 * </ol>
92
	 *
93
	 */
94
	synchronized public void reLoadInstanceConfigurations() {
95

  
96
		ListOrderedMap currentInstances = instances;
97
		ListOrderedMap updatedInstances = new ListOrderedMap();
98

  
99
		List<Configuration> configList = DataSourcePropertyParser.parseDataSourceConfigs(datasourcesFile);
100
		logger.info("cdm server instance names loaded: " + configList.toString());
101

  
102
		for (Configuration config : configList) {
103
			String key = config.getInstanceName();
104
			if(currentInstances.containsKey(key)){
105
				CdmInstance existingInstance = (CdmInstance)currentInstances.get(key);
106
				// already removed instances will not be re-added if they have been stopped successfully
107
				if(existingInstance.getStatus().equals(Status.removed) && existingInstance.getWebAppContext().isStopped()){
108
					updatedInstances.put(key, existingInstance);
109
					if ( !(existingInstance).getConfiguration().equals(config)) {
110
						// instance has changed: stop it
111
						try {
112
							// TODO change problems into messages + severity (notice, error)
113
							existingInstance.getWebAppContext().stop();
114
							existingInstance.getProblems().add("Reloaded with modified configuration and thus stopped");
115
						} catch (Exception e) {
116
							existingInstance.getProblems().add("Error while stopping modified instance: " + e.getMessage());
117
							logger.error(e, e);
118
						}
119
					}
120
				}
121
			} else {
122
				updatedInstances.put(key, new CdmInstance(config));
123
			}
124
		}
125

  
126
		// find removed instances
127
		for(Object keyOfExisting : currentInstances.keyList()){
128
			if(!updatedInstances.containsKey(keyOfExisting)){
129
				CdmInstance removedInstance = (CdmInstance)currentInstances.get(keyOfExisting);
130
				updatedInstances.put(keyOfExisting, removedInstance);
131
				try {
132
					removedInstance.setStatus(Status.removed);
133
					removedInstance.getWebAppContext().stop();
134
					removedInstance.getProblems().add("Removed from configuration and thus stopped");
135
				} catch (Exception e) {
136
					removedInstance.getProblems().add("Error while stopping removed instance: " + e.getMessage());
137
					logger.error(e, e);
138
				}
139
			}
140
		}
141

  
142
		instances = updatedInstances;
143

  
144
        verifyMemoryRequirements();
145

  
146
        if(serverIsRunning) {
147
        	addInstancesToServer(false);
148
        }
149
	}
150

  
151
	@Override
152
    public void lifeCycleFailure(LifeCycle event, Throwable cause) {
153
        logger.error("Jetty LifeCycleFailure", cause);
154
    }
155

  
156
    @Override
157
    public void lifeCycleStarted(LifeCycle event) {
158
    	serverIsRunning = true;
159
        logger.info("cdmserver has started, now adding CDM server contexts");
160
        	 addInstancesToServer(austostart);
161

  
162
    }
163

  
164
	private void addInstancesToServer(boolean austostart) {
165
		for (CdmInstance instance : getInstances()) {
166
			if (!instance.getStatus().equals(Status.removed)) {
167
				try {
168
					Bootloader.getBootloader().addCdmInstanceContext(instance);
169
				} catch (IOException e) {
170
					logger.error(e, e); // TODO better throw?
171
				}
172

  
173
				if (austostart) {
174
					try {
175
						instance.setStatus(Status.starting);
176
						instance.getWebAppContext().start();
177
						if (!instance.getStatus().equals(Status.error)) {
178
							instance.setStatus(Status.started);
179
						}
180
					} catch (Exception e) {
181
						logger.error("Could not start " + instance.getWebAppContext().getContextPath());
182
						instance.getProblems().add(e.getMessage());
183
						instance.setStatus(Status.error);
184
					}
185
				}
186
			}
187
		}
188
	}
189

  
190
    @Override
191
    public void lifeCycleStarting(LifeCycle event) {
192
    }
193

  
194
    @Override
195
    public void lifeCycleStopped(LifeCycle event) {
196
    	serverIsRunning = false;
197
    }
198

  
199
    @Override
200
    public void lifeCycleStopping(LifeCycle event) {
201
    	serverIsRunning = false;
202
    }
203

  
204

  
205

  
206
    /**
207
    *
208
    */
209
   private void verifyMemoryRequirements() {
210

  
211
       verifyMemoryRequirement("PermGenSpace", PERM_GEN_SPACE_CDMSERVER, PERM_GEN_SPACE_PER_INSTANCE, JvmManager.getPermGenSpaceUsage().getMax());
212
       verifyMemoryRequirement("HeapSpace", HEAP_CDMSERVER, HEAP_PER_INSTANCE, JvmManager.getHeapMemoryUsage().getMax());
213

  
214
   }
215
    private void verifyMemoryRequirement(String memoryName, long requiredSpaceServer, long requiredSpacePerInstance, long availableSpace) {
216

  
217

  
218
        long recommendedMinimumSpace = recommendedMinimumSpace(requiredSpaceServer, requiredSpacePerInstance, null);
219

  
220
        if(recommendedMinimumSpace > availableSpace){
221

  
222
            String message = memoryName + " ("
223
                + (availableSpace / MB)
224
                + "MB) insufficient for "
225
                + numOfConfiguredInstances()
226
                + " instances. Increase " + memoryName + " to "
227
                + (recommendedMinimumSpace / MB)
228
                + "MB";
229
                ;
230
            logger.error(message + " => disabling some instances!!!");
231

  
232
            // disabling some instances
233
            int i=0;
234
            for(CdmInstance instance : getInstances()){
235
                i++;
236
                if(recommendedMinimumSpace(requiredSpaceServer, requiredSpacePerInstance, i)  > availableSpace){
237
                    instance.setStatus(Status.disabled);
238
                    instance.getProblems().add("Disabled due to: " + message);
239
                }
240
            }
241
        }
242
    }
243

  
244
    /**
245
     * @param requiredServerSpace
246
     * @param requiredSpacePerIntance
247
     * @param numOfInstances may be null, the total number of instances found in
248
     *  the current configuration is used in this case.
249
     * @return
250
     */
251
    public long recommendedMinimumSpace(long requiredServerSpace, long requiredSpacePerIntance, Integer numOfInstances) {
252
        if(numOfInstances == null){
253
            numOfInstances = numOfConfiguredInstances();
254
        }
255
        return (numOfInstances * requiredSpacePerIntance) + requiredServerSpace;
256
    }
257

  
258

  
259

  
260
}
src/main/java/eu/etaxonomy/cdm/server/instance/Status.java
1
package eu.etaxonomy.cdm.server.instance;
2

  
3
public enum Status{
4
	uninitialized,
5
	initializing,
6
	starting,
7
	started,
8
	stopped,
9
	error,
10
	disabled,
11
	removed
12
}
src/main/webapp/index.jsp
3 3
<%@page import="eu.etaxonomy.cdm.server.Bootloader"%>
4 4
<%@page import="java.util.Set" %>
5 5
<%@page import="java.net.URL" %>
6
<%@page import="eu.etaxonomy.cdm.server.CdmInstanceProperties"%>
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff

Add picture from clipboard (Maximum size: 40 MB)