0001: package org.enhydra.server;
0002:
0003: import java.io.File;
0004: import java.util.ArrayList;
0005: import java.util.Date;
0006: import java.util.Enumeration;
0007: import java.util.HashMap;
0008: import java.util.Hashtable;
0009: import java.util.Iterator;
0010:
0011: import javax.servlet.Servlet;
0012:
0013: import org.enhydra.server.conf.EnhydraServerXML;
0014: import org.enhydra.server.util.PathUtil;
0015: import org.enhydra.server.util.UnpackWar;
0016:
0017: import com.lutris.appserver.server.Application;
0018: import com.lutris.appserver.server.httpPresentation.servlet.HttpPresentationServlet;
0019: import com.lutris.appserver.server.session.MemoryPersistence;
0020: import com.lutris.logging.LogChannel;
0021: import com.lutris.logging.Logger;
0022: import com.lutris.util.Config;
0023:
0024: /**
0025: * <p>Description:
0026: * Class EnhydraServer use singleton pattern to provide
0027: * all necessary data about registered (started) Enhydra applications.
0028: * All application register itself on startup and unregister when shutdown.
0029: * Admin application use this class to display applications info.
0030: * Admin application should get instance of this class first, then calls
0031: * public methods. Example:</p>
0032: * <code>
0033: * <p> EnhydraServer enhydraServer = EnhydraServer.getInstance();</p>
0034: * <p> SessionsInfo sessInfo = enhydraServer.getSessionsInfo();</p>
0035: * <p> String activeSessions = sessInfo.getActiveSessions();</p>
0036: * ...
0037: * </code>
0038: *
0039: *
0040: * <p>Copyright: Copyright (c) 2002</p>
0041: * <p>Company: www.together.at </p>
0042: * @author Damir Milovic, damir@uns.ns.ac.yu
0043: * @version 1.0
0044: * @see <a href="SessionsInfo.html">SessionsInfo</a>
0045: */
0046: public class EnhydraServer {
0047: /**
0048: * Public static variables
0049: */
0050: // Strings used in config file names
0051: public static final String APPS_DIR = "apps";
0052: public static final String SERVER = "Server";
0053: public static final String APPLICATION = "Application";
0054: public static final String CONF_FILE = "ConfFile";
0055: public static final String DEFAULT_CONF_FILE = "web.xml";
0056: public static final String CONF_FILE_CLASS = "ConfFileClass"; // TJ 08.11.2003
0057: public static final String DEFAULT_CONF_FILE_CLASS = "org.enhydra.util.XMLConfigFile"; // TJ 08.11.2003
0058:
0059: public static final String LOG_CLASS = "LogClassName"; // SM 08.11.2003
0060: public static final String DEFAULT_LOG_CLASS = "com.lutris.logging.StandardLogger"; // SM 08.11.2003
0061:
0062: public static final String SERVLET = "Servlet";
0063: public static final String CLASS_NAME = "ClassName";
0064: public static final String DOC_ROOT = "DocRoot";
0065: public static final String DESCRIPTION = "Description";
0066: public static final String RUNNING = "Running";
0067: public static final String CLASS_PATH = "ClassPath";
0068: public static final String INIT_ARGS = "InitArgs";
0069: public static final String URL = "Url";
0070: public static final String CONNECTION = "Connection";
0071: public static final String ENABLED = "Enabled";
0072: public static final String APP_CLASS = "AppClass";
0073: public static final String PRESENTATION_PREFIX = "PresentationPrefix";
0074: public static final String AUTO_RELOAD = "AutoReload";
0075: public static final String SESSION_MANAGER = "SessionManager";
0076: public static final String SESSION_MANAGER_KEY = "org.enhydra.session.manager";
0077: // private static final String sysConLoggerName = "sysOut";
0078:
0079: /**
0080: * attributes in <application> tag in EnhydraServer.xml configuration file.
0081: */
0082: protected static final String APP_URLPATH = "URLPath"; //path to context root
0083: protected static final String APP_CONTEXTPATH = "contextPath"; //context prefix for web application
0084: protected static final String APP_NAME = "name";
0085: protected static final String APP_DESCRIPTION = "description";
0086: protected static final String APP_RUNNING = "running";
0087: protected static final String APP_CONNECTIONS = "connections"; //Enabled connection ports
0088: /**
0089: * Singleton reference
0090: */
0091: private static EnhydraServer enhydraServer = null;
0092: /**
0093: * Where to find conf files
0094: */
0095: private static String appsDir = null;
0096: /**
0097: * All available application names
0098: */
0099: //private String appNames[];
0100: /**
0101: * All available applications (started or stopped) (key=appName, value=appInfo)
0102: */
0103: private Hashtable apps;
0104: /**
0105: * List of connection port numbers added by EnhydraServer
0106: */
0107: private ArrayList connectionPorts;
0108: /**
0109: * interface
0110: */
0111: private ApplicationServer applicationServer;
0112: /**
0113: * Hard coded EnhydraServer config file
0114: */
0115: private EnhydraServerXML serverConfig;
0116: /**
0117: * Flag that indicate is EnhydraServer started
0118: */
0119: private static boolean started = false;
0120: /**
0121: * Debug level
0122: */
0123: // private int debug = 0;
0124: // private static Logger standardLogger;
0125: private static LogChannel logChannel = null;
0126:
0127: private EnhydraServer() {
0128: // if there is no initialized root logger in log4j -> initialize root
0129: // with NullAppender
0130:
0131: //SINISA 25.11
0132:
0133: /* if (server == null) {
0134: fatalErr("No server section specified in config file "
0135: + configFileName);
0136: }
0137: // Very first thing is to establish the central logging object.
0138: String logClassName = null;
0139:
0140: try {
0141: logClassName = server.getString(LOG_CLASS);
0142: } catch (ConfigException e) {}
0143: if (logClassName == null) {
0144: logClassName = LOG_TYPE_STANDARD;
0145: }
0146:
0147: /*
0148: * Done bootstrapping. From here on out we may use logging.
0149: */
0150:
0151: // try {
0152: // standardLogger = (Logger) Class.forName(logClassName).getConstructor(new Class[] {Boolean.TYPE}).newInstance(new Object[] {new Boolean(true)});
0153: // standardLogger.configure(server);
0154: // } catch (Exception e) {
0155: // fatalErr("Cannot set default logger for " + configFileName,
0156: // e);
0157: // }
0158: if (Logger.getCentralLogger() != null)
0159: logChannel = Logger.getCentralLogger()
0160: .getChannel("Enhydra");
0161:
0162: /* if (!Logger.getRootLogger().getAllAppenders().hasMoreElements()) {
0163: LoggerRepository logRepository = Logger.getRootLogger().getLoggerRepository();
0164: // set level for log error:
0165: logRepository.setThreshold(Level.ERROR);
0166: NullAppender nullAppender = new NullAppender();
0167: Logger.getRootLogger().addAppender(nullAppender);
0168: }
0169:
0170: loggerSys = Logger.getLogger(sysConLoggerName);
0171: ConsoleAppender conAppender = new ConsoleAppender(
0172: new PatternLayout("%d{ISO8601}: [%t] %C{1}, %p, %c: %m%n") );
0173: loggerSys.addAppender(conAppender);
0174: loggerSys.setLevel(Level.ERROR);// FIXME: change to INFO for distribution
0175: // "enhydra" logger will be configured from conf file
0176: logger = Logger.getLogger("enhydra");
0177: */}
0178:
0179: /**
0180: * Init Enhydra Server
0181: */
0182: private void init() {
0183:
0184: // loggerSys.debug("init()");
0185: logChannel.write(Logger.DEBUG, "init()");
0186: apps = new Hashtable();
0187: applicationServer = null;
0188: connectionPorts = new ArrayList(0);
0189: }
0190:
0191: /**
0192: * Enhydra applications (HttpPresentationServlet) call this method to obtain
0193: * EnhydraServer instance.
0194: * @return One and only instance (singleton pattern) of this class.
0195: */
0196: public static EnhydraServer getInstance() {
0197: if (enhydraServer == null) {
0198: enhydraServer = new EnhydraServer();
0199: enhydraServer.init();
0200: }
0201: return enhydraServer;
0202: }
0203:
0204: /**
0205: * This method is responsible starting applications
0206: * defined in <code>EnhydraServer.conf</code> file.
0207: * ApplicationServer call this method when all necessary application server
0208: * initialization are done and <code>ApplicationServer</code> reference is setted.
0209: */
0210: public synchronized void startup() {
0211: logChannel.write(Logger.INFO, "Startup Enhydraserver ...");
0212: try {
0213: String home = System.getProperty("enhydra.home");
0214: //If appsDir not set, try from System property.
0215: if (appsDir == null) {
0216:
0217: File appsDirFile = new File(home, APPS_DIR);
0218: appsDir = appsDirFile.getAbsolutePath();
0219: }
0220: logChannel.write(Logger.DEBUG, "conf dir=" + appsDir);
0221: // Read config file 'EnhydraServer.xml'
0222: File cFile = new File(home, "conf/EnhydraServer.xml");
0223: serverConfig = new EnhydraServerXML(cFile.getAbsolutePath());
0224:
0225: // add enhydra loggers from conf file
0226: // todo: configure logger from separate xml file 17.03.2003
0227: // PropertyConfigurator.configure(confDir+"EnhydraServer.conf");
0228: // logger.debug("Logger configured");
0229: // loggerSys.addAppender(logger.getAppender("enhydraAppender"));
0230:
0231: } catch (Exception e) {
0232: logChannel.write(Logger.ALERT,
0233: "Fail to startup EnhydraServer", e);
0234: return;
0235: }
0236:
0237: if (applicationServer == null) {
0238: logChannel
0239: .write(Logger.ERROR,
0240: "Can't startup EnhydraServer, applicationServer = null");
0241: return;
0242: }
0243: if (started) {
0244: logChannel.write(Logger.WARNING,
0245: "EnhydraServer already started");
0246: return;
0247: }
0248:
0249: try {
0250:
0251: // Create AppInfo, put into hashtable and start application if running = true.
0252:
0253: //17.03.2003 String[] appNames = null;
0254: HashMap[] appsHash = serverConfig.getApplications();
0255:
0256: String[] appNames = new String[appsHash.length];
0257: for (int i = 0; i < appsHash.length; i++) {
0258: appNames[i] = (String) appsHash[i].get(APP_NAME);
0259: }
0260: if (appNames != null) {
0261: for (int i = 0; i < appNames.length; i++) {
0262: // Create AppInfo
0263: AppInfo appInfo = new AppInfo(appNames[i],
0264: appsHash[i]);
0265: apps.put(appNames[i], appInfo);
0266: logChannel.write(Logger.INFO, "add Application "
0267: + i + ":" + appNames[i]);
0268: if (appInfo.isRunning()) {
0269: appInfo.setRunning(false); //must cheat startApplication() method on startup
0270: startApplication(appNames[i]); //startApplication() will call appInfo.setRunning(true);
0271: }
0272: }
0273: }
0274: } catch (Exception e) {
0275: logChannel.write(Logger.ERROR, "... at startup():", e);
0276: return;
0277: }
0278: started = true;
0279: logChannel.write(Logger.INFO,
0280: "EnhydraServer is startup successfuly");
0281: }
0282:
0283: /**
0284: * Enhydra Application (HttpPresentationServlet) register itself on startup.
0285: * @param servlet only HttpPresentationServlet is currently supported.
0286: */
0287: public void register(Servlet servlet) {//FIXME should be synchronized?
0288: if (servlet == null) {
0289: logChannel.write(Logger.ERROR,
0290: "Unable to register application, servlet = NULL");
0291: return;
0292: }
0293: AppInfo appInfo = null;
0294: // Check is already registered?
0295: // If application is already registered by ApplicationServer,
0296: // just need to proceed Application interface, else make new appInfo
0297: try {
0298:
0299: AppInfo appInfoTemp = new AppInfo(servlet);
0300: String appName = appInfoTemp.getName();
0301: File urlPathTemp = new File(appInfoTemp.getUrlPath());
0302: if (apps.containsKey(appName)) {
0303: appInfo = ((AppInfo) apps.get(appName));
0304: // Check urlPath (if urlPaths are difrerent it is not the same application)
0305: if (!urlPathTemp.equals(new File(appInfo.getUrlPath())))
0306: appInfo = null;
0307: }
0308: //try to find equal url path in other appInfos
0309: //(maybe user change app name in EnhydraServer.conf)
0310: if (appInfo == null) {
0311: Enumeration keys = apps.keys();
0312: while (keys.hasMoreElements() && (appInfo == null)) {
0313: appInfo = ((AppInfo) apps.get((String) keys
0314: .nextElement()));
0315: if (!urlPathTemp.equals(new File(appInfo
0316: .getUrlPath())))
0317: appInfo = null;
0318: }
0319: }
0320: //if appInfo found just set Application reference
0321: if (appInfo != null) {
0322: appInfo.setApplication(appInfoTemp.getApplication());
0323: } else {
0324: // ApplicationServer didn't register this application
0325: // this is a case when application server is unknown, and/or application is
0326: // autostarted with application server (Servlet Container).
0327: // In that case just put appInfo into apps hashtable, don't add
0328: // application into EnhydraServer config
0329: appInfo = appInfoTemp;
0330: appInfo
0331: .setDescription("Auto registered Enhydra application.");
0332: apps.put(appName, appInfo);
0333: }
0334: if (!appInfo.isRunning()) {
0335: appInfo.setRunning(true);
0336: appInfo.setStarted(new Date());
0337: }
0338: logChannel.write(Logger.INFO, "Application " + appName
0339: + " successfuly registered");
0340: } catch (Exception e) {
0341: logChannel.write(Logger.ERROR, "in register() ", e);
0342: }
0343: return;
0344: }
0345:
0346: /**
0347: * Enhydra Application unregister itself when stop.
0348: * @param servlet usualy HttpPresentationServlet.
0349: */
0350: public void unRegister(Servlet servlet) {
0351: if (servlet instanceof HttpPresentationServlet) {
0352:
0353: String appName = ((HttpPresentationServlet) servlet)
0354: .getApplication().getName();
0355: if (appName != null) {
0356: if (apps.containsKey(appName)) {
0357: ((AppInfo) apps.get(appName)).setRunning(false);
0358: logChannel.write(Logger.INFO, "Application "
0359: + appName + " successfuly unregistered");
0360: }
0361: }
0362: }
0363: }
0364:
0365: /**
0366: * Set path to default Applications context root path.
0367: * Application context url can be relative against this path.
0368: * @param dir absolute path to directory, where are application context reside.
0369: */
0370: public static void setAppsfDir(String dir) {
0371: appsDir = dir;
0372: }
0373:
0374: /**
0375: * Get path to default Applications context root path.
0376: * @return absolute path to directory, where are application context reside.
0377: */
0378: public String getAppsDir() {
0379: return appsDir;
0380: }
0381:
0382: // Methods for reading application data -------------------------------------
0383:
0384: /**
0385: * @see <a href="AppInfo.html">AppInfo</a>
0386: * @param appName application name.
0387: * @return AppInfo contains all necessary application data.
0388: */
0389: public AppInfo getAppInfo(String appName) {
0390: AppInfo appInfo = (AppInfo) apps.get(appName);
0391: if (appInfo == null) {
0392: logChannel.write(Logger.WARNING,
0393: "EnhydraServer: Can't get AppInfo," + appName
0394: + " not registered");
0395: return null;
0396: }
0397:
0398: return appInfo;
0399: }
0400:
0401: /**
0402: * @see <a href="PresentationInfo.html">PresentationInfo</a>
0403: * @param appName - application name
0404: * @return PresentationInfo - JavaBean with getter methods
0405: */
0406: public PresentationInfo getPresentationInfo(String appName) {
0407: PresentationInfo presInfo = null;
0408: Config config = null;
0409: AppInfo appInfo = null;
0410: Application app = null;
0411: try {
0412: if (apps.containsKey(appName)) {
0413:
0414: appInfo = (AppInfo) apps.get(appName);
0415: app = appInfo.getApplication();
0416: config = (Config) appInfo.getConfig();
0417: if (config != null)
0418: if (config.containsKey("PresentationManager"))
0419: config = (Config) config
0420: .getSection("PresentationManager");
0421: presInfo = new PresentationInfo(app, config);
0422: } else
0423: logChannel.write(Logger.WARNING,
0424: "Can't get PresentationInfo, " + appName
0425: + " don't exist!");
0426: } catch (Exception e) {
0427: //FIXME maintain exceptions
0428: logChannel.write(Logger.ERROR,
0429: "Exception in getPresentationInfo", e);
0430: }
0431: return presInfo;
0432: }
0433:
0434: /**
0435: * @see <a href="SessionsInfo.html">SessionsInfo</a>
0436: * @param appName - application name
0437: * @return SessionInfo - JavaBean with getter methods
0438: */
0439: public SessionsInfo getSessionsInfo(String appName) {
0440: SessionsInfo sessInfo = null;
0441: Config config = null;
0442: AppInfo appInfo = null;
0443: Application app = null;
0444: try {
0445: if (apps.containsKey(appName)) {
0446:
0447: appInfo = (AppInfo) apps.get(appName);
0448: app = appInfo.getApplication();
0449: config = (Config) appInfo.getConfig();
0450: if (config != null)
0451: if (config.containsKey("SessionManager"))
0452: config = (Config) config
0453: .getSection("SessionManager");
0454: sessInfo = new SessionsInfo(app, config);
0455: } else
0456: logChannel.write(Logger.ERROR,
0457: "Can't get SessionInfo, " + appName
0458: + " don't exist!");
0459: } catch (Exception e) {
0460: //FIXME maintain exceptions
0461: logChannel.write(Logger.ERROR,
0462: "Exception in getSessionInfo()", e);
0463: }
0464: return sessInfo;
0465: }
0466:
0467: /**
0468: * @see <a href="SessionEdit.html">SessionEdit</a>
0469: * @param appName applicatin name
0470: * @return SessionEdit class for editing SessionManager parameters in conf file.
0471: */
0472: public SessionEdit getSessionEdit(String appName) {
0473: AppInfo appInfo = null;
0474: SessionEdit sessEdit = null;
0475: Config config = null;
0476: try {
0477: if (apps.containsKey(appName)) {
0478: appInfo = (AppInfo) apps.get(appName);
0479: config = (Config) appInfo.getConfig();
0480: sessEdit = new SessionEdit(config);
0481: } else
0482: logChannel.write(Logger.WARNING,
0483: "Can't get SessionEdit, " + appName
0484: + " don't exist!");
0485: } catch (Exception e) {
0486: //FIXME maintain exceptions
0487: logChannel.write(Logger.ERROR,
0488: "Exception in getSessionEdit", e);
0489: }
0490: return sessEdit;
0491: }
0492:
0493: /**
0494: * @see <a href="DatabaseInfo.html">SessionsInfo</a>
0495: * @param appName - application name.
0496: * @return DatabaseInfo - JavaBean with getter methods.
0497: */
0498: public DatabaseInfo getDatabaseInfo(String appName) {
0499: DatabaseInfo dbInfo = null;
0500: Config config = null;
0501: AppInfo appInfo = null;
0502: Application app = null;
0503: try {
0504: if (apps.containsKey(appName)) {
0505:
0506: appInfo = (AppInfo) apps.get(appName);
0507: app = appInfo.getApplication();
0508: config = (Config) appInfo.getConfig();
0509: if (config != null)
0510: // VR if ( config.containsKey("DatabaseManager")) config = (Config) config.getSection("DatabaseManager");
0511: dbInfo = new DatabaseInfo(app, config);
0512: } else
0513: logChannel.write(Logger.ERROR,
0514: "Can't get DatabaseInfo, " + appName
0515: + " don't exist!");
0516: } catch (Exception e) {
0517: //FIXME maintain exceptions
0518: logChannel.write(Logger.ERROR,
0519: "Exception in getDatabaseInfo", e);
0520: }
0521: return dbInfo;
0522: }
0523:
0524: /**
0525: * Gets instasnce of DatabaseEdit class which is used in edditing of database
0526: * parameters in configuration file of the application.
0527: * @param appName the applicatin name.
0528: * @return instasnce of DatabaseEdit class.
0529: */
0530: public DatabaseEdit getDatabaseEdit(String appName) {
0531: AppInfo appInfo = null;
0532: DatabaseEdit databaseEdit = null;
0533: Config config = null;
0534: try {
0535: if (apps.containsKey(appName)) {
0536: appInfo = (AppInfo) apps.get(appName);
0537: config = (Config) appInfo.getConfig();
0538: databaseEdit = new DatabaseEdit(config);
0539: } else
0540: logChannel.write(Logger.ERROR,
0541: "Can't get DatabaseEdit, " + appName
0542: + " don't exist!");
0543: } catch (Exception e) {
0544: //FIXME maintain exceptions
0545: logChannel.write(Logger.ERROR,
0546: "Exception in getDatabaseEdit", e);
0547: }
0548: return databaseEdit;
0549: }
0550:
0551: /**
0552: *
0553: * @return instance of class that implements ApplicationServer
0554: */
0555: public ApplicationServer getApplicationServer() {
0556: if (applicationServer == null)
0557: logChannel
0558: .write(Logger.WARNING, "ApplicationServer = null");
0559: return applicationServer;
0560: }
0561:
0562: /**
0563: * Implementation of ApplicationServer interface are responsible
0564: * to set reference on himself.
0565: * @param appServ Implementation of ApplicationServer.
0566: */
0567: public void setApplicationServer(ApplicationServer appServ) {
0568: applicationServer = appServ;
0569: }
0570:
0571: //17.03.2003
0572: /**
0573: * Update EnhydraServer.xml document without save.
0574: * @param appInfo application need to update
0575: */
0576: private void updateServerConfig(AppInfo appInfo) {
0577: HashMap appHash = new HashMap();
0578: //Required attributes
0579: appHash.put(APP_CONTEXTPATH, appInfo.getContextPath());
0580: //Make relative URLPath if path is inside apps dir
0581: appHash.put(APP_URLPATH, PathUtil.makeRelativePath(appsDir,
0582: appInfo.getUrlPath()));
0583: appHash.put(APP_NAME, appInfo.getName());
0584: if (appInfo.isRunning()) {
0585: appHash.put(APP_RUNNING, "true");
0586: } else {
0587: appHash.put(APP_RUNNING, "false");
0588: }
0589: appHash.put(APP_DESCRIPTION, appInfo.getDescription());
0590: int[] conns = appInfo.getConnections();
0591: String connections = "";
0592: StringBuffer connectionsBuffer = new StringBuffer(connections);
0593: if (conns != null) {
0594: for (int i = 0; i < conns.length; i++) {
0595: if (i == 0) {
0596: connectionsBuffer = new StringBuffer(Integer
0597: .toString(conns[i]));
0598: } else {
0599: connectionsBuffer.append(","
0600: + Integer.toString(conns[i]));
0601: }
0602: }
0603: }
0604: connections = connectionsBuffer.toString();
0605: appHash.put(APP_CONNECTIONS, connections);
0606: //Update
0607: if (serverConfig.getApplication(appInfo.getContextPath()) != null) {
0608: serverConfig.removeApplication(appInfo.getContextPath());
0609: }
0610: serverConfig.addApplication(appHash);
0611: }
0612:
0613: /**
0614: * Save state of EnhydraServer into xml config file
0615: * @return TRUE if OK, else FALSE.
0616: */
0617: public boolean saveState() {
0618: boolean isOK = true;
0619: logChannel.write(Logger.WARNING,
0620: "Saving current EnhydraServer config state ...");
0621: try {
0622: //17.03.2003
0623: // ConfigFileInterface confFile = serverConfig.getConfigFile();
0624: // confFile.write();
0625: serverConfig.saveDocument();
0626: } catch (Exception e) {
0627: logChannel.write(Logger.WARNING,
0628: "Can't write EnhydraServer.conf file", e);
0629: isOK = false;
0630: }
0631: return isOK;
0632: }
0633:
0634: /**
0635: * Start application.
0636: * @param appName application name.
0637: * @return OK if application successfuly started, else FALSE.
0638: */
0639: public boolean startApplication(String appName) {
0640:
0641: AppInfo appInfo = (AppInfo) apps.get(appName);
0642: logChannel.write(Logger.INFO, "Starting " + appName
0643: + " at context path =" + appInfo.getContextPath()
0644: + ", URL path = " + appInfo.getUrlPath());
0645: /* Alex
0646: * if (appInfo == null){
0647: logChannel.write(Logger.INFO,"Can't start application, invalid application name: "+appName);
0648: return false;
0649: }*/
0650: if (appInfo.isRunning()) {
0651: logChannel.write(Logger.WARNING,
0652: "Can't start application : " + appName
0653: + ", already started");
0654: return false;
0655: }
0656: if (applicationServer == null) {
0657: logChannel
0658: .write(Logger.ERROR,
0659: "Can't start application, Unknown Application Server");
0660: return false;
0661: }
0662: if (!applicationServer.startApp(appName)) {
0663: logChannel
0664: .write(Logger.ERROR,
0665: "Can't start application, ApplicationServer.startApp() FAIL");
0666: return false;
0667: }
0668: // if all OK, change AppInfo and config file but not save.
0669: try {
0670: appInfo.getWebAppXML().reloadDocument(); //reload web.xml (maybe is manualy changed) 21.03.2003
0671: appInfo.setRunning(true);
0672: appInfo.setStarted(new Date());
0673: /** Next line is for standard Web applications,
0674: * Enhydra application will register itself anyway.
0675: */
0676: //startedApps.put(appName,appInfo);
0677: //ConfigFileInterface confFile = serverConfig.getConfigFile();
0678: //17.03.2003
0679: //serverConfig.set("Application."+appName+".Running",new Boolean(true));
0680: //update serverConfig (EnhydraServer.xml)
0681: updateServerConfig(appInfo);
0682: } catch (Exception e) {
0683: logChannel
0684: .write(
0685: Logger.WARNING,
0686: "Application started but fail to change EnhydraServer.conf",
0687: e);
0688: }
0689:
0690: return true;
0691: }
0692:
0693: /**
0694: * Shutdown application.
0695: * @param appName application name.
0696: * @return OK if application successfuly stopped, else FALSE.
0697: */
0698: public boolean stopApplication(String appName) {
0699: // FIXME ...
0700: AppInfo appInfo = (AppInfo) apps.get(appName);
0701: if (appInfo == null) {
0702: logChannel.write(Logger.ERROR,
0703: "Can't stop application, invalid application name: "
0704: + appName);
0705: return false;
0706: }
0707: if (!appInfo.isRunning()) {
0708: logChannel.write(Logger.ERROR, "Can't stop application : "
0709: + appName + ", not started");
0710: return false;
0711: }
0712: if (applicationServer == null) {
0713: logChannel
0714: .write(Logger.ERROR,
0715: "Can't stop application, Unknown Application Server");
0716: return false;
0717: }
0718: if (!applicationServer.stopApp(appName)) {
0719: logChannel
0720: .write(Logger.ERROR,
0721: "Can't stop application, ApplicationServer.stopApp() FAIL");
0722: return false;
0723: }
0724: //If everything OK, remove it from startedApps
0725: //if(startedApps.containsKey(appName)) startedApps.remove(appName);
0726: try {
0727: appInfo.setRunning(false);
0728: appInfo.setStarted(null);//Remove old Date
0729: //serverConfig.set("Application."+appName+".Running",new Boolean(false));
0730: updateServerConfig(appInfo);
0731: } catch (Exception e) {
0732: logChannel
0733: .write(
0734: Logger.WARNING,
0735: "Application stopped but fail to change EnhydraServer.conf",
0736: e);
0737: }
0738: return true;
0739: }
0740:
0741: /**
0742: * Shutdown application server
0743: */
0744: public void stopApplicationServer() {
0745: if (applicationServer == null)
0746: logChannel
0747: .write(Logger.ERROR,
0748: "Can't shutdown application server, applicationServer = null");
0749: else {
0750: applicationServer.stop();
0751: logChannel.write(Logger.INFO, applicationServer.getName()
0752: + " stopped");
0753: }
0754: }
0755:
0756: /**
0757: * Shutdown EnhydraServer, including all applications and connections.
0758: */
0759: public synchronized void shutdown() {
0760: logChannel.write(Logger.INFO, "Shuting down EnhydraServer...");
0761: //Stop all applications started by EnhydraServer
0762: Enumeration enumApps = apps.keys();
0763: String appName;
0764: AppInfo appInfo;
0765: while (enumApps.hasMoreElements()) {
0766: appName = (String) enumApps.nextElement();
0767: appInfo = (AppInfo) apps.get(appName);
0768: if (appInfo.isRunning())
0769: stopApplication(appName);
0770: }
0771: // Do not remove 07.04.2003 //Remove all connection added to ApplicationServer by EnhydraServer
0772: // String port;
0773: // while(!connectionPorts.isEmpty()){
0774: // port = (String)connectionPorts.remove(0);
0775: // removeConnection(port);
0776: // }
0777: logChannel.write(Logger.INFO, "EnhydraServer is shutdown !");
0778: MemoryPersistence.shutdown(); //Clean sessions from memory
0779: apps = new Hashtable();
0780: connectionPorts = new ArrayList(0);
0781: started = false;
0782: }
0783:
0784: /**
0785: * Add (create) connection to application server.
0786: * Admin Presentation should first check available types, before call this method.
0787: * @param type Connection type ("http","ajp",..) depends on Application Server.
0788: * @param port Port nubber.
0789: * @return TRUE if connection added successfuly.
0790: */
0791: public boolean addConnection(String type, String port) {
0792: if (applicationServer == null) {
0793: logChannel.write(Logger.WARNING,
0794: "Can't add connection, applicationServer = null !");
0795: return false;
0796: }
0797:
0798: if (applicationServer.addConnection(type, port)) {
0799: connectionPorts.add(port);
0800: logChannel.write(Logger.INFO, "Connection (" + port + ","
0801: + type + ") added.");
0802: return true;
0803: }
0804: return false;
0805: }
0806:
0807: /**
0808: * Add (create) connection to application server.
0809: * @param type Connection type ("http","ajp","https"..) depends on Application Server.
0810: * @param port Port nubber.
0811: * @param password for "https" required.
0812: * @param pathToKeyStoreFile absolute path to KeyStore file for "https" required.
0813: * @return
0814: */
0815: public boolean addConnection(String type, String port,
0816: String password, String pathToKeyStoreFile) {
0817: if (applicationServer == null) {
0818: logChannel.write(Logger.WARNING,
0819: "Can't add connection, applicationServer = null !");
0820: return false;
0821: }
0822: if (applicationServer.addConnection(type, port, password,
0823: pathToKeyStoreFile)) {
0824: connectionPorts.add(port);
0825: logChannel.write(Logger.INFO, "Connection (" + port + ","
0826: + type + ") added.");
0827: return true;
0828: }
0829: return false;
0830: }
0831:
0832: public boolean removeConnection(String port) {
0833: if (applicationServer == null) {
0834: logChannel
0835: .write(Logger.WARNING,
0836: "Can't remove connection, applicationServer = null !");
0837: return false;
0838: }
0839: if (applicationServer.removeConnection(port)) {
0840: try {
0841: connectionPorts.remove(port);
0842: //13.03.2003 no more Server.Connection in config
0843: // serverConfig.remove("Server.Connection.Port"+port);
0844: // logger.info("Connection "+port+" removed.");
0845: } catch (Exception e) {
0846: logChannel.write(Logger.WARNING,
0847: "Fail to remove connection from config!", e);
0848: }
0849: return true;
0850: }
0851: return false;
0852: }
0853:
0854: /**
0855: * Enable connection to the application on port number.
0856: * @param appName application name.
0857: * @param portNumber port number of corresponding connection.
0858: * @return TRUE if connection successfuly enabled, else FALSE.
0859: */
0860: public boolean enableConnection(String appName, String portNumber) {
0861: //String enabledConns[];
0862: //String enabledConnsNew[];
0863: //String connsKey = "Application."+appName+".Connections";
0864: AppInfo appInfo = ((AppInfo) apps.get(appName));
0865: int enablePort = Integer.parseInt(portNumber);
0866: int[] connections = appInfo.getConnections();
0867: int[] newConnections = null;
0868: if (connections == null) {
0869: newConnections = new int[1];
0870: newConnections[0] = enablePort;
0871: } else {
0872: newConnections = new int[connections.length + 1];
0873: newConnections[0] = enablePort;
0874: for (int i = 0; i < connections.length; i++) {
0875: if (connections[i] == enablePort) {
0876: logChannel
0877: .write(
0878: Logger.DEBUG,
0879: "Connection on port: "
0880: + portNumber
0881: + "allready enabled for application "
0882: + appName);
0883: return false;
0884: }
0885: newConnections[i + 1] = connections[i];
0886: }
0887: }
0888: appInfo.setConnections(newConnections);
0889: updateServerConfig(appInfo);
0890: logChannel.write(Logger.INFO, "Connection on port: "
0891: + portNumber + " enabled for application " + appName);
0892: return true;
0893: }
0894:
0895: /**
0896: * Disable connection to the application on port number.
0897: * @param appName application name.
0898: * @param portNumber port number of corresponding connection.
0899: * @return TRUE if connection successfuly disabled, else FALSE.
0900: */
0901: public boolean disableConnection(String appName, String portNumber) {
0902: //String enabledConns[];
0903: //String enabledConnsNew[];
0904: //String connsKey = "Application."+appName+".Connections";
0905: ArrayList enabledConnsList = new ArrayList(0);
0906: AppInfo appInfo = ((AppInfo) apps.get(appName));
0907: int disablePort = Integer.parseInt(portNumber);
0908: int[] connections = appInfo.getConnections();
0909:
0910: if (connections != null) {
0911: for (int i = 0; i < connections.length; i++) {
0912: if (connections[i] != disablePort) {
0913: enabledConnsList.add(Integer
0914: .toString(connections[i]));
0915: }
0916: }
0917: }
0918: Object[] objs = enabledConnsList.toArray();
0919: connections = new int[objs.length];
0920: //Object[] --> int[], new connections
0921: for (int i = 0; i < objs.length; i++) {
0922: connections[i] = Integer.parseInt((String) objs[i]);
0923: }
0924: appInfo.setConnections(connections);
0925: updateServerConfig(appInfo);
0926: logChannel.write(Logger.INFO, "Connection on port: "
0927: + portNumber + " disabled for application " + appName);
0928: return true;
0929: }
0930:
0931: /**
0932: * Method used by EnhydraPortFilter, provides list of enabled ports
0933: * for given application name.
0934: * @param appName Application name.
0935: * @return Array of enabled port numbers .
0936: */
0937: public String[] getEnabledConnections(String appName) {
0938: AppInfo appInfo = ((AppInfo) apps.get(appName));
0939:
0940: String[] enabledPorts = null;
0941: int[] connections = appInfo.getConnections();
0942: if (connections != null) {
0943: enabledPorts = new String[connections.length];
0944: for (int i = 0; i < connections.length; i++) {
0945: enabledPorts[i] = Integer.toString(connections[i]);
0946: }
0947: }
0948: return enabledPorts;
0949: }
0950:
0951: /**
0952: * This method should be call for editing application config file.
0953: * @param appName application name
0954: * @return application Config object.
0955: * @see com.lutris.util.Config
0956: */
0957: public Config getAppConfig(String appName) {
0958: AppInfo ai = (AppInfo) apps.get(appName);
0959: if (ai == null) {
0960: logChannel.write(Logger.WARNING, "Application " + appName
0961: + " not available!");
0962: return null;
0963: }
0964: return ai.getConfig();
0965: }
0966:
0967: /**
0968: * @return names of all available applications
0969: */
0970: public String[] getAppNames() {
0971: // Get application names
0972: String[] appNames = null;
0973: try {
0974: //appNames = serverConfig.getSection("Application").keys();
0975: Enumeration enumKeys = apps.keys();
0976: if (enumKeys != null) {
0977: appNames = new String[apps.size()];
0978: for (int i = 0; enumKeys.hasMoreElements(); i++) {
0979: appNames[i] = (String) enumKeys.nextElement();
0980: }
0981: }
0982: } catch (Exception e) {
0983: logChannel.write(Logger.ERROR, "Exception in getAppNames",
0984: e);
0985: }
0986: return appNames;
0987: }
0988:
0989: public EnhydraServerXML getConfig() {
0990: return serverConfig;
0991: }
0992:
0993: /**
0994: * Adds new application to Enhydra server
0995: * @param appName application name.
0996: * @param contextPath context path ( e.g. '/myapp')
0997: * @param urlPath url path file (application root directory or path to war file).
0998: * If path is relative it is resolved against <code>%ENHYDRA_HOME/apps</code> directory.
0999: * @param description application description not required.
1000: * @return <code>true</code> if application added successfuly, else <code>false</code>.
1001: */
1002:
1003: public boolean addApplication(String appName, String contextPath,
1004: String urlFilePath, String description) {
1005: String message = null;
1006: HashMap appHash = new HashMap();
1007: String urlPath = null;
1008: urlFilePath = PathUtil.makeAbsolutePath(getAppsDir(),
1009: urlFilePath);
1010:
1011: File urlFile = new File(urlFilePath);
1012: if (appName == null) {
1013: logChannel
1014: .write(Logger.ERROR,
1015: "Couldn't add application, application name = null");
1016: return false;
1017: }
1018: appName = appName.trim(); //cut redutant spaces
1019: if (appName.equals("")) {
1020: logChannel
1021: .write(Logger.ERROR,
1022: "Couldn't add application, application name = \"\"");
1023: return false;
1024: }
1025: //Check is file exist
1026: if (!urlFile.exists()) {
1027: logChannel.write(Logger.ERROR, "Couldn't add " + appName
1028: + ". URL Path file:'" + urlFilePath
1029: + "' don't exist!");
1030: return false;
1031: }
1032: if (urlFile.isDirectory()) {
1033: urlPath = urlFilePath;
1034: //chech is application with one of given parameters allready exist
1035: if (!checkApplication(appName, contextPath, urlPath)) {
1036: return false;
1037: }
1038: } else if (urlFile.isFile()) {
1039: // make urlPath from file name (just cut '.war');
1040: String fileName = urlFile.getName();
1041: urlPath = fileName.substring(0, fileName.length() - 4);
1042: //chech is application with one of given parameters allready exist before unpack
1043: if (!checkApplication(appName, contextPath, urlPath)) {
1044: return false;
1045: }
1046: //Unpack war to apps directory
1047: UnpackWar unpack = new UnpackWar(urlFilePath, PathUtil
1048: .makeAbsolutePath(getAppsDir(), urlPath));
1049: try {
1050: unpack.execute();
1051: } catch (Exception e) {
1052: logChannel.write(Logger.ERROR, "Couldn't add "
1053: + appName + "!", e);
1054: return false;
1055: }
1056: }
1057:
1058: if (!contextPath.startsWith("/")) {
1059: logChannel.write(Logger.ERROR, "Couldn't add " + appName
1060: + ". Context path must start with '/'!");
1061: return false; //exception
1062: } else {
1063: appHash.put(APP_CONTEXTPATH, contextPath);
1064: }
1065:
1066: if (apps.get(appName) != null) {
1067: message = "Couldn't add " + appName + ". Application "
1068: + appName + " already exist!";
1069: logChannel.write(Logger.WARNING, message);
1070: return false;
1071: } else {
1072: appHash.put(APP_NAME, appName);
1073: }
1074: appHash.put(APP_URLPATH, urlPath);
1075: appHash.put(APP_DESCRIPTION, description);
1076: appHash.put(APP_RUNNING, "false");
1077:
1078: try {
1079: AppInfo appInfo = new AppInfo(appName, appHash);
1080: apps.put(appName, appInfo);
1081: updateServerConfig(appInfo);
1082: } catch (Exception e) {
1083: logChannel.write(Logger.ERROR,
1084: "ERROR in EnhydraServer.addApplication", e);
1085: return false;
1086: }
1087:
1088: return true;
1089: }
1090:
1091: /**
1092: * Check application parameters allready exist.
1093: * @param appName application name.
1094: * @param contextPath context path.
1095: * @param urlPath url path file.
1096: * @return <code>true</code> if application don't exist, otherwise <code>false</code>.
1097: */
1098: private boolean checkApplication(String appName,
1099: String contextPath, String urlPath) {
1100: Iterator iter = apps.values().iterator();
1101: AppInfo appInfo = null;
1102: String message = null;
1103: boolean notExist = true;
1104: while (iter.hasNext()) {
1105: appInfo = (AppInfo) iter.next();
1106: // check name
1107: if (appInfo.getName().equalsIgnoreCase(appName)) {
1108: message = "Application name '" + appName
1109: + "' allready exist!";
1110: notExist = false;
1111: break;
1112: }
1113: // check context path
1114: if (appInfo.getContextPath().equalsIgnoreCase(contextPath)) {
1115: message = "Application contextPath '" + appName
1116: + "' allready exist!";
1117: notExist = false;
1118: break;
1119: }
1120: // check url path, compare absolute paths
1121: urlPath = PathUtil.makeAbsolutePath(getAppsDir(), urlPath);
1122: if (PathUtil.makeAbsolutePath(getAppsDir(),
1123: appInfo.getUrlPath()).equalsIgnoreCase(urlPath)) {
1124: message = "Application urlPath '" + urlPath
1125: + "' allready exist!";
1126: notExist = false;
1127: break;
1128: }
1129: }
1130: if (!notExist) {
1131: logChannel.write(Logger.ERROR, message);
1132: }
1133: return notExist;
1134: }
1135:
1136: /**
1137: * Remove application from Enhydra Server.
1138: * @param appName application name.
1139: * @return true if application removing was successful.
1140: */
1141: public boolean removeApplication(String appName) {
1142: if (!apps.containsKey(appName)) {
1143: logChannel.write(Logger.WARNING, "in removeApplication(): "
1144: + appName + " don't exist!");
1145: return false;
1146: }
1147: AppInfo appInfo = (AppInfo) apps.get(appName);
1148: if (appInfo.isRunning()) {
1149: if (!stopApplication(appName)) {
1150: return false;
1151: }
1152: }
1153:
1154: apps.remove(appName);
1155: // remove from config file
1156: serverConfig.removeApplication(appInfo.getContextPath());
1157:
1158: logChannel.write(Logger.INFO, "Application " + appName
1159: + " removed successfuly.");
1160: return true;
1161: }
1162:
1163: /**
1164: * AdminGui should call this method to check is EnhydraServer started
1165: * @return true if EnhydraServer started
1166: */
1167: public boolean isStarted() {
1168: return started;
1169: }
1170: }
|