admin pages secured
[cdm-server.git] / src / main / java / eu / etaxonomy / cdm / server / Bootloader.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 static eu.etaxonomy.cdm.server.CommandOptions.DATASOURCES_FILE;
14 import static eu.etaxonomy.cdm.server.CommandOptions.HELP;
15 import static eu.etaxonomy.cdm.server.CommandOptions.HTTP_PORT;
16 import static eu.etaxonomy.cdm.server.CommandOptions.JMX;
17 import static eu.etaxonomy.cdm.server.CommandOptions.WEBAPP;
18 import static eu.etaxonomy.cdm.server.CommandOptions.WIN32SERVICE;
19
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.OutputStream;
26 import java.lang.management.ManagementFactory;
27 import java.lang.reflect.InvocationTargetException;
28 import java.net.URL;
29 import java.sql.Connection;
30 import java.sql.SQLException;
31 import java.util.List;
32 import java.util.Set;
33
34 import javax.naming.NamingException;
35 import javax.sql.DataSource;
36
37 import org.apache.commons.cli.CommandLine;
38 import org.apache.commons.cli.CommandLineParser;
39 import org.apache.commons.cli.GnuParser;
40 import org.apache.commons.cli.HelpFormatter;
41 import org.apache.commons.cli.ParseException;
42 import org.apache.commons.io.FileUtils;
43 import org.apache.log4j.Logger;
44 import org.apache.log4j.PatternLayout;
45 import org.apache.log4j.RollingFileAppender;
46 import org.eclipse.jetty.jmx.MBeanContainer;
47 import org.eclipse.jetty.security.HashLoginService;
48 import org.eclipse.jetty.server.Server;
49 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
50 import org.eclipse.jetty.server.handler.ContextHandler.Context;
51 import org.eclipse.jetty.util.component.LifeCycle;
52 import org.eclipse.jetty.util.component.LifeCycle.Listener;
53 import org.eclipse.jetty.util.log.Log;
54 import org.eclipse.jetty.webapp.WebAppClassLoader;
55 import org.eclipse.jetty.webapp.WebAppContext;
56
57 import eu.etaxonomy.cdm.server.CdmInstanceProperties.Status;
58 import eu.etaxonomy.cdm.server.win32service.Win32Service;
59
60
61 /**
62 * A bootstrap class for starting Jetty Runner using an embedded war.
63 *
64 * Recommended start options for the java virtual machine:
65 * <pre>
66 * -Xmx1024M
67 *
68 * -XX:PermSize=128m
69 * -XX:MaxPermSize=192m
70 *
71 * -XX:+UseConcMarkSweepGC
72 * -XX:+CMSClassUnloadingEnabled
73 * -XX:+CMSPermGenSweepingEnabled
74 * </pre>
75 *
76 * @version $Revision$
77 */
78 public final class Bootloader {
79 //private static final String DEFAULT_WARFILE = "target/";
80
81 /**
82 * @author a.kohlbecker
83 * @date 03.02.2011
84 *
85 */
86 private class WebAppContextListener implements Listener {
87
88 WebAppContext cdmWebappContext;
89 /**
90 * @param cdmWebappContext
91 */
92 public WebAppContextListener(WebAppContext cdmWebappContext) {
93 this.cdmWebappContext = cdmWebappContext;
94 }
95
96 @Override
97 public void lifeCycleStopping(LifeCycle event) {
98 logger.error("lifeCycleStopping");
99 }
100
101 @Override
102 public void lifeCycleStopped(LifeCycle event) {
103 logger.error("lifeCycleStopped");
104
105 }
106
107 @Override
108 public void lifeCycleStarting(LifeCycle event) {
109 logger.error("lifeCycleStarting");
110 }
111
112 @SuppressWarnings("unchecked")
113 @Override
114 public void lifeCycleStarted(LifeCycle event) {
115 logger.error("lifeCycleStarted");
116
117 List<String> messages = getServletContextAttribute(cdmWebappContext, ATTRIBUTE_ERROR_MESSAGES, List.class);
118 String dataSourceName = getServletContextAttribute(cdmWebappContext, ATTRIBUTE_DATASOURCE_NAME, String.class);
119
120 if(messages != null && dataSourceName != null){
121 CdmInstanceProperties configAndStatus = findConfigAndStatusFor(dataSourceName);
122 configAndStatus.getProblems().addAll(messages);
123 configAndStatus.setStatus(Status.error);
124 try {
125 logger.warn("Stopping context '" + dataSourceName + "' due to errors reported in ServletContext");
126 cdmWebappContext.stop();
127 } catch (Exception e) {
128 logger.error(e);
129 }
130 }
131 }
132
133
134 @Override
135 public void lifeCycleFailure(LifeCycle event, Throwable cause) {
136 logger.error("lifeCycleFailure");
137 }
138 }
139
140 private static final Logger logger = Logger.getLogger(Bootloader.class);
141
142 private static final String DATASOURCE_BEANDEF_FILE = "datasources.xml";
143 private static final String REALM_PROPERTIES_FILE = "cdm-server-realm.properties";
144
145 private static final String USERHOME_CDM_LIBRARY_PATH = System.getProperty("user.home")+File.separator+".cdmLibrary"+File.separator;
146 private static final String TMP_PATH = USERHOME_CDM_LIBRARY_PATH + "server" + File.separator;
147 private static final String LOG_PATH = USERHOME_CDM_LIBRARY_PATH + "log" + File.separator;
148
149 private static final String APPLICATION_NAME = "CDM Server";
150 private static final String WAR_POSTFIX = ".war";
151
152 private static final String CDM_WEBAPP_WAR_NAME = "cdmserver";
153 private static final String DEFAULT_WEBAPP_WAR_NAME = "default-webapp";
154 private static final File DEFAULT_WEBAPP_TEMP_FOLDER = new File(TMP_PATH + DEFAULT_WEBAPP_WAR_NAME);
155 private static final File CDM_WEBAPP_TEMP_FOLDER = new File(TMP_PATH + CDM_WEBAPP_WAR_NAME);
156
157 private static final String ATTRIBUTE_JDBC_JNDI_NAME = "cdm.jdbcJndiName";
158 private static final String ATTRIBUTE_DATASOURCE_NAME = "cdm.datasource";
159 private static final String ATTRIBUTE_CDM_LOGFILE = "cdm.logfile";
160 /**
161 * same as in eu.etaxonomy.cdm.remote.config.DataSourceConfigurer
162 */
163 private static final String ATTRIBUTE_ERROR_MESSAGES = "cdm.errorMessages";
164
165
166 // memory requirements
167 private static final long MB = 1024 * 1024;
168 private static final long PERM_GEN_SPACE_PER_INSTANCE = 64 * MB;
169 private static final long HEAP_PER_INSTANCE = 300 * MB;
170
171 private static final int KB = 1024;
172
173
174 private Set<CdmInstanceProperties> configAndStatusSet = null;
175
176 public Set<CdmInstanceProperties> getConfigAndStatus() {
177 return configAndStatusSet;
178 }
179
180 private File webappFile = null;
181 private File defaultWebAppFile = null;
182
183 private Server server = null;
184 private ContextHandlerCollection contexts = new ContextHandlerCollection();
185
186 private CommandLine cmdLine;
187
188 /* thread save singleton implementation */
189
190 private static Bootloader instance = new Bootloader();
191
192 private Bootloader() {}
193
194 public synchronized static Bootloader getBootloader(){
195 return instance;
196 }
197
198 /* end of singleton implementation */
199
200 private Set<CdmInstanceProperties> loadDataSources(){
201 if(configAndStatusSet == null){
202 File datasourcesFile = new File(USERHOME_CDM_LIBRARY_PATH, DATASOURCE_BEANDEF_FILE);
203 configAndStatusSet = DataSourcePropertyParser.parseDataSourceConfigs(datasourcesFile);
204 logger.info("cdm server instance names loaded: "+ configAndStatusSet.toString());
205 }
206 return configAndStatusSet;
207 }
208
209 public int writeStreamTo(final InputStream input, final OutputStream output, int bufferSize) throws IOException {
210 int available = Math.min(input.available(), 256 * KB);
211 byte[] buffer = new byte[Math.max(bufferSize, available)];
212 int answer = 0;
213 int count = input.read(buffer);
214 while (count >= 0) {
215 output.write(buffer, 0, count);
216 answer += count;
217 count = input.read(buffer);
218 }
219 return answer;
220 }
221
222 private boolean bindJndiDataSource(CdmInstanceProperties conf) {
223 try {
224 Class<DataSource> dsCass = (Class<DataSource>) Thread.currentThread().getContextClassLoader().loadClass("com.mchange.v2.c3p0.ComboPooledDataSource");
225 DataSource datasource = dsCass.newInstance();
226 dsCass.getMethod("setDriverClass", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getDriverClass()});
227 dsCass.getMethod("setJdbcUrl", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getUrl()});
228 dsCass.getMethod("setUser", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getUsername()});
229 dsCass.getMethod("setPassword", new Class[] {String.class}).invoke(datasource, new Object[] {conf.getPassword()});
230
231 Connection connection = null;
232 String sqlerror = null;
233 try {
234 connection = datasource.getConnection();
235 connection.close();
236 } catch (SQLException e) {
237 sqlerror = e.getMessage() + "["+ e.getSQLState() + "]";
238 conf.getProblems().add(sqlerror);
239 if(connection != null){
240 try {connection.close();} catch (SQLException e1) { /* IGNORE */ }
241 }
242 logger.error(conf.toString() + " has problem : "+ sqlerror );
243 }
244
245 if(!conf.hasProblems()){
246 logger.info("binding jndi datasource at " + conf.getJdbcJndiName() + " with "+conf.getUsername() +"@"+ conf.getUrl());
247 org.eclipse.jetty.plus.jndi.Resource jdbcResource = new org.eclipse.jetty.plus.jndi.Resource(conf.getJdbcJndiName(), datasource);
248 return true;
249 }
250
251 } catch (IllegalArgumentException e) {
252 logger.error(e);
253 e.printStackTrace();
254 } catch (SecurityException e) {
255 logger.error(e);
256 } catch (ClassNotFoundException e) {
257 logger.error(e);
258 } catch (InstantiationException e) {
259 logger.error(e);
260 } catch (IllegalAccessException e) {
261 logger.error(e);
262 } catch (InvocationTargetException e) {
263 logger.error(e);
264 } catch (NoSuchMethodException e) {
265 logger.error(e);
266 } catch (NamingException e) {
267 logger.error(e);
268 }
269 return false;
270 }
271
272 private void parseCommandOptions(String[] args) throws ParseException {
273 CommandLineParser parser = new GnuParser();
274 cmdLine = parser.parse( CommandOptions.getOptions(), args );
275
276 // print the help message
277 if(cmdLine.hasOption(HELP.getOpt())){
278 HelpFormatter formatter = new HelpFormatter();
279 formatter.printHelp( "java .. ", CommandOptions.getOptions() );
280 System.exit(0);
281 }
282 }
283
284
285 private File extractWar(String warName) throws IOException, FileNotFoundException {
286 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
287 String warFileName = warName + WAR_POSTFIX;
288
289 // 1. find in classpath
290 URL resource = classLoader.getResource(warFileName);
291 if (resource == null) {
292 logger.error("Could not find the " + warFileName + " on classpath!");
293
294 File pomxml = new File("pom.xml");
295 if(pomxml.exists()){
296 // 2. try finding in target folder of maven project
297 File warFile = new File("target" + File.separator + warFileName);
298 logger.debug("looging for war file at " + warFile.getAbsolutePath());
299 if (warFile.canRead()) {
300 resource = warFile.toURI().toURL();
301 } else {
302 logger.error("Also could not find the " + warFileName + " in maven project, try excuting 'mvn install'");
303 }
304 }
305 }
306
307 if (resource == null) {
308 // no way finding the war file :-(
309 System.exit(1);
310 }
311
312
313 File warFile = new File(TMP_PATH, warName + "-" + WAR_POSTFIX);
314 logger.info("Extracting " + warFileName + " to " + warFile + " ...");
315
316 writeStreamTo(resource.openStream(), new FileOutputStream(warFile), 8 * KB);
317
318 logger.info("Extracted " + warFileName);
319 return warFile;
320 }
321
322
323 /**
324 * MAIN METHOD
325 *
326 * @param args
327 * @throws Exception
328 */
329 public static void main(String[] args) throws Exception {
330
331 Bootloader bootloader = Bootloader.getBootloader();
332
333 bootloader.parseCommandOptions(args);
334
335 bootloader.startServer();
336 }
337
338 private void startServer() throws IOException,
339 FileNotFoundException, Exception, InterruptedException {
340
341
342 //assure LOG_PATH exists
343 File logPath = new File(LOG_PATH);
344 if(!logPath.exists()){
345 FileUtils.forceMkdir(new File(LOG_PATH));
346 }
347
348 //append logger
349 configureFileLogger();
350
351 logger.info("Starting "+APPLICATION_NAME);
352 logger.info("Using " + System.getProperty("user.home") + " as home directory. Can be specified by -Duser.home=<FOLDER>");
353
354 //assure TMP_PATH exists and clean it up
355 File tempDir = new File(TMP_PATH);
356 if(!tempDir.exists() && !tempDir.mkdirs()){
357 logger.error("Error creating temporary directory for webapplications " + tempDir.getAbsolutePath());
358 System.exit(-1);
359 } else {
360 if(FileUtils.deleteQuietly(tempDir)){
361 tempDir.mkdirs();
362 logger.info("Old webapplications successfully cleared");
363 }
364 }
365 tempDir = null;
366
367
368 // WARFILE
369 if(cmdLine.hasOption(WEBAPP.getOpt())){
370 webappFile = new File(cmdLine.getOptionValue(WEBAPP.getOpt()));
371 if(webappFile.isDirectory()){
372 logger.info("using user defined web application folder: " + webappFile.getAbsolutePath());
373 } else {
374 logger.info("using user defined warfile: " + webappFile.getAbsolutePath());
375 }
376 if(isRunningFromSource()){
377 //FIXME check if all local paths are valid !!!!
378 defaultWebAppFile = new File("./src/main/webapp");
379
380 } else {
381 defaultWebAppFile = extractWar(DEFAULT_WEBAPP_WAR_NAME);
382 }
383 } else {
384 webappFile = extractWar(CDM_WEBAPP_WAR_NAME);
385 defaultWebAppFile = extractWar(DEFAULT_WEBAPP_WAR_NAME);
386 }
387
388 // HTTP Port
389 int httpPort = 8080;
390 if(cmdLine.hasOption(HTTP_PORT.getOpt())){
391 try {
392 httpPort = Integer.parseInt(cmdLine.getOptionValue(HTTP_PORT.getOpt()));
393 logger.info(HTTP_PORT.getOpt()+" set to "+cmdLine.getOptionValue(HTTP_PORT.getOpt()));
394 } catch (NumberFormatException e) {
395 logger.error("Supplied portnumber is not an integer");
396 System.exit(-1);
397 }
398 }
399
400 if(cmdLine.hasOption(DATASOURCES_FILE.getOpt())){
401 logger.error(DATASOURCES_FILE.getOpt() + " NOT JET IMPLEMENTED!!!");
402 }
403
404 loadDataSources();
405
406 verifyMemoryRequirements();
407
408
409 server = new Server(httpPort);
410
411 // JMX support
412 if(cmdLine.hasOption(JMX.getOpt())){
413 logger.info("adding JMX support ...");
414 MBeanContainer mBeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
415 server.getContainer().addEventListener(mBeanContainer);
416 mBeanContainer.addBean(Log.getLog());
417 mBeanContainer.start();
418 }
419
420 if(cmdLine.hasOption(WIN32SERVICE.getOpt())){
421 Win32Service win32Service = new Win32Service();
422 win32Service.setServer(server);
423 server.setStopAtShutdown(true);
424 server.addBean(win32Service);
425 }
426
427 // add servelet contexts
428
429
430 //
431 // 1. default context
432 //
433 logger.info("preparing default WebAppContext");
434 WebAppContext defaultWebappContext = new WebAppContext();
435
436 setWebApp(defaultWebappContext, defaultWebAppFile);
437 defaultWebappContext.setContextPath("/");
438 defaultWebappContext.setTempDirectory(DEFAULT_WEBAPP_TEMP_FOLDER);
439
440 // configure security context
441 // see for reference * http://docs.codehaus.org/display/JETTY/Realms
442 // * http://wiki.eclipse.org/Jetty/Starting/Porting_to_Jetty_7
443 HashLoginService loginService = new HashLoginService();
444 loginService.setConfig(USERHOME_CDM_LIBRARY_PATH + REALM_PROPERTIES_FILE);
445 defaultWebappContext.getSecurityHandler().setLoginService(loginService);
446
447 // Important:
448 // the defaultWebappContext MUST USE the super classloader
449 // otherwise the status page (index.jsp) might not work
450 defaultWebappContext.setClassLoader(this.getClass().getClassLoader());
451 contexts.addHandler(defaultWebappContext);
452
453 //
454 // 2. cdm server contexts
455 //
456 server.addLifeCycleListener(new LifeCycle.Listener(){
457
458 @Override
459 public void lifeCycleFailure(LifeCycle event, Throwable cause) {
460 logger.error("Jetty LifeCycleFailure", cause);
461 }
462
463 @Override
464 public void lifeCycleStarted(LifeCycle event) {
465 logger.info("cdmserver has started, now adding CDM server contexts");
466 try {
467 addCdmServerContexts(true);
468 } catch (IOException e1) {
469 logger.error(e1);
470 }
471 }
472
473 @Override
474 public void lifeCycleStarting(LifeCycle event) {
475 }
476
477 @Override
478 public void lifeCycleStopped(LifeCycle event) {
479 }
480
481 @Override
482 public void lifeCycleStopping(LifeCycle event) {
483 }
484
485 });
486
487
488 logger.info("setting contexts ...");
489 server.setHandler(contexts);
490 logger.info("starting jetty ...");
491 // try {
492
493 server.start();
494
495 // } catch(org.springframework.beans.BeansException e){
496 // Throwable rootCause = null;
497 // while(e.getCause() != null){
498 // rootCause = e.getCause();
499 // }
500 // if(rootCause != null && rootCause.getClass().getSimpleName().equals("InvalidCdmVersionException")){
501 //
502 // logger.error("rootCause ----------->" + rootCause.getMessage());
503 //// for(CdmInstanceProperties props : configAndStatus){
504 //// if(props.getDataSourceName())
505 //// }
506 // }
507 // }
508
509 if(cmdLine.hasOption(WIN32SERVICE.getOpt())){
510 logger.info("jetty has started as win32 service");
511 } else {
512 server.join();
513 logger.info(APPLICATION_NAME+" stopped.");
514 System.exit(0);
515 }
516 }
517
518 /**
519 *
520 */
521 private void verifyMemoryRequirements() {
522
523 verifyMemoryRequirement("PermGenSpace", PERM_GEN_SPACE_PER_INSTANCE, JvmManager.getPermGenSpaceUsage().getMax());
524 verifyMemoryRequirement("HeapSpace", HEAP_PER_INSTANCE, JvmManager.getHeapMemoryUsage().getMax());
525
526 }
527
528 private void verifyMemoryRequirement(String memoryName, long requiredSpacePerIntance, long availableSpace) {
529
530
531 long requiredSpace = configAndStatusSet.size() * requiredSpacePerIntance;
532
533 if(requiredSpace > availableSpace){
534
535 String message = memoryName + " ("
536 + (availableSpace / MB)
537 + "MB) insufficient for "
538 + configAndStatusSet.size()
539 + " instances. Increase " + memoryName + " by "
540 + ((requiredSpace - availableSpace)/MB)
541 + "MB";
542 ;
543 logger.error(message + " => disabling some instances!!!");
544
545 // disabling some instances
546 int i=0;
547 for(CdmInstanceProperties instanceProps : configAndStatusSet){
548 i++;
549 if(i * requiredSpacePerIntance > availableSpace){
550 instanceProps.setStatus(Status.disabled);
551 instanceProps.getProblems().add("Disbled due to: " + message);
552 }
553 }
554 }
555 }
556
557 /**
558 * Configures and adds a {@link RollingFileAppender} to the root logger
559 *
560 * The log files of the cdm-remote instances are configured by the
561 * {@link eu.etaxonomy.cdm.remote.config.LoggingConfigurer}
562 */
563 private void configureFileLogger() {
564
565 PatternLayout layout = new PatternLayout("%d %p [%c] - %m%n");
566 try {
567 String logFile = LOG_PATH + File.separator + "cdmserver.log";
568 RollingFileAppender appender = new RollingFileAppender(layout, logFile);
569 appender.setMaxBackupIndex(3);
570 appender.setMaxFileSize("2MB");
571 Logger.getRootLogger().addAppender(appender);
572 logger.info("logging to :" + logFile);
573 } catch (IOException e) {
574 logger.error("Creating RollingFileAppender failed:", e);
575 }
576 }
577
578 private void addCdmServerContexts(boolean austostart) throws IOException {
579
580 for(CdmInstanceProperties conf : configAndStatusSet){
581
582 if(!conf.isEnabled()){
583 logger.info(conf.getDataSourceName() + " is disabled => skipping");
584 continue;
585 }
586 conf.setStatus(CdmInstanceProperties.Status.initializing);
587 logger.info("preparing WebAppContext for '"+ conf.getDataSourceName() + "'");
588 WebAppContext cdmWebappContext = new WebAppContext();
589
590 cdmWebappContext.setContextPath("/"+conf.getDataSourceName());
591 cdmWebappContext.setTempDirectory(CDM_WEBAPP_TEMP_FOLDER);
592
593 if(!bindJndiDataSource(conf)){
594 // a problem with the datasource occurred skip this webapp
595 cdmWebappContext = null;
596 logger.error("a problem with the datasource occurred -> skipping /" + conf.getDataSourceName());
597 conf.setStatus(CdmInstanceProperties.Status.error);
598 continue;
599 }
600
601 cdmWebappContext.setAttribute(ATTRIBUTE_DATASOURCE_NAME, conf.getDataSourceName());
602 cdmWebappContext.setAttribute(ATTRIBUTE_JDBC_JNDI_NAME, conf.getJdbcJndiName());
603 setWebApp(cdmWebappContext, webappFile);
604
605 cdmWebappContext.setAttribute(ATTRIBUTE_CDM_LOGFILE,
606 LOG_PATH + File.separator + "cdm-"
607 + conf.getDataSourceName() + ".log");
608
609 if(webappFile.isDirectory() && isRunningFromSource()){
610
611 /*
612 * when running the webapp from {projectpath} src/main/webapp we
613 * must assure that each web application is using it's own
614 * classloader thus we tell the WebAppClassLoader where the
615 * dependencies of the webapplication can be found. Otherwise
616 * the system classloader would load these resources.
617 */
618 logger.info("Running webapp from source folder, thus adding java.class.path to WebAppClassLoader");
619
620 WebAppClassLoader classLoader = new WebAppClassLoader(cdmWebappContext);
621
622 String classPath = System.getProperty("java.class.path");
623 classLoader.addClassPath(classPath);
624 cdmWebappContext.setClassLoader(classLoader);
625 }
626
627 cdmWebappContext.addLifeCycleListener(new WebAppContextListener(cdmWebappContext));
628 contexts.addHandler(cdmWebappContext);
629
630 if(austostart){
631 try {
632 conf.setStatus(CdmInstanceProperties.Status.starting);
633 cdmWebappContext.start();
634 if(!conf.getStatus().equals(Status.error)){
635 conf.setStatus(CdmInstanceProperties.Status.started);
636 }
637 } catch (Exception e) {
638 logger.error("Could not start " + cdmWebappContext.getContextPath());
639 conf.setStatus(CdmInstanceProperties.Status.error);
640 }
641 }
642
643 }
644 }
645
646 /**
647 * @param context
648 * @param webApplicationResource
649 */
650 private void setWebApp(WebAppContext context, File webApplicationResource) {
651 if(webApplicationResource.isDirectory()){
652 context.setResourceBase(webApplicationResource.getAbsolutePath());
653 logger.debug("setting directory " + webApplicationResource.getAbsolutePath() + " as webapplication");
654 } else {
655 context.setWar(webApplicationResource.getAbsolutePath());
656 logger.debug("setting war file " + webApplicationResource.getAbsolutePath() + " as webapplication");
657 }
658 }
659
660 /**
661 * @return
662 */
663 private boolean isRunningFromSource() {
664 String webappPathNormalized = webappFile.getAbsolutePath().replace('\\', '/');
665 return webappPathNormalized.endsWith("src/main/webapp") || webappPathNormalized.endsWith("cdmlib-remote/target/cdmserver");
666 }
667
668 /**
669 * @param dataSourceName
670 * @return
671 */
672 private CdmInstanceProperties findConfigAndStatusFor(String dataSourceName){
673 for(CdmInstanceProperties props : configAndStatusSet){
674 if(props.getDataSourceName().equals(dataSourceName)){
675 return props;
676 }
677 }
678 return null;
679 }
680
681 /**
682 * @param <T>
683 * @param webAppContext
684 * @param attributeName
685 * @param type
686 * @return
687 */
688 @SuppressWarnings("unchecked")
689 private <T> T getServletContextAttribute(WebAppContext webAppContext, String attributeName, Class<T> type) {
690
691 Context servletContext = webAppContext.getServletContext();
692 Object value = servletContext.getAttribute(attributeName);
693 if( value != null && type.isAssignableFrom(value.getClass())){
694
695 }
696 return (T) value;
697 }
698 }