Save This Page
Home » org.apache.sling.launchpad.base-2.2.0-source-release » org.apache.sling.launchpad.base.app » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   package org.apache.sling.launchpad.base.app;
   18   
   19   import static org.apache.felix.framework.util.FelixConstants.LOG_LEVEL_PROP;
   20   
   21   import java.io.PrintStream;
   22   import java.text.DateFormat;
   23   import java.text.SimpleDateFormat;
   24   import java.util.Date;
   25   import java.util.HashMap;
   26   import java.util.Map;
   27   import java.util.Map.Entry;
   28   
   29   import org.apache.felix.framework.Logger;
   30   import org.apache.sling.launchpad.base.impl.ClassLoaderResourceProvider;
   31   import org.apache.sling.launchpad.base.impl.ResourceProvider;
   32   import org.apache.sling.launchpad.base.impl.Sling;
   33   import org.apache.sling.launchpad.base.shared.Launcher;
   34   import org.apache.sling.launchpad.base.shared.Notifiable;
   35   import org.apache.sling.launchpad.base.shared.SharedConstants;
   36   import org.osgi.framework.BundleException;
   37   
   38   /**
   39    * The <code>Main</code> class is a simple Java Application which interprests
   40    * the command line and creates the {@link Sling} launcher class and thus starts
   41    * the OSGi framework. In addition a shutdown thread is registered to ensure
   42    * proper shutdown on VM termination.
   43    * <p>
   44    * The supported command line options are:
   45    * <dl>
   46    * <dt>-l loglevel</dt>
   47    * <dd>Sets the initial loglevel as an integer in the range 0 to 4 or as one of
   48    * the well known level strings FATAL, ERROR, WARN, INFO or DEBUG. This option
   49    * overwrites the <code>org.apache.sling.osg.log.level</code> setting the
   50    * <code>sling.properties</code> file.</dd>
   51    * <dt>-f logfile</dt>
   52    * <dd>The log file, \"-\" for stdout (default logs/error.log). This option
   53    * overwrites the <code>org.apache.sling.osg.log.file</code> setting the
   54    * <code>sling.properties</code> file.</dd>
   55    * <dt>-c slinghome</dt>
   56    * <dd>The directory in which Sling locates its initial configuration file
   57    * <code>sling.properties</code> and where files of Sling itself such as the
   58    * Apache Felix bundle archive or the JCR repository files are stored (default
   59    * sling).</dd>
   60    * <dt>-a address</dt>
   61    * <dd>The interfact to bind to (use 0.0.0.0 for any). This option is not
   62    * implemented yet.</dd>
   63    * <dt>-p port</dt>
   64    * <dd>The port to listen (default 8080) to handle HTTP requests. This option
   65    * overwrites the <code>org.osgi.service.http.port</code> setting the
   66    * <code>sling.properties</code> file.</dd>
   67    * <dt>-h</dt>
   68    * <dd>Prints a simple usage message listing all available command line options.
   69    * </dd>
   70    * </dl>
   71    */
   72   public class MainDelegate implements Launcher {
   73   
   74       /** Mapping between log level numbers and names */
   75       private static final String[] logLevels = { "FATAL", "ERROR", "WARN",
   76           "INFO", "DEBUG" };
   77   
   78       /** The Sling configuration property name setting the initial log level */
   79       private static final String PROP_LOG_LEVEL = "org.apache.sling.commons.log.level";
   80   
   81       /** The Sling configuration property name setting the initial log file */
   82       private static final String PROP_LOG_FILE = "org.apache.sling.commons.log.file";
   83   
   84       /** Default log level setting if no set on command line (value is "INFO"). */
   85       private static final int DEFAULT_LOG_LEVEL = Logger.LOG_INFO;
   86   
   87       /**
   88        * The configuration property setting the port on which the HTTP service
   89        * listens
   90        */
   91       private static final String PROP_PORT = "org.osgi.service.http.port";
   92   
   93       /** The default port on which the HTTP service listens. */
   94       private static final String DEFAULT_PORT = "8080";
   95   
   96       private Notifiable notifiable;
   97   
   98       /** The parsed command line mapping (Sling) option name to option value */
   99       private Map<String, String> commandLine;
  100   
  101       private String slingHome;
  102   
  103       private Sling sling;
  104   
  105       public void setNotifiable(Notifiable notifiable) {
  106           this.notifiable = notifiable;
  107       }
  108   
  109       public void setCommandLine(Map<String, String> args) {
  110           commandLine = new HashMap<String, String>();
  111           commandLine.put(PROP_PORT, DEFAULT_PORT);
  112           parseCommandLine(args, commandLine);
  113       }
  114   
  115       public void setSlingHome(String slingHome) {
  116           this.slingHome = slingHome;
  117       }
  118   
  119       public boolean start() {
  120   
  121           Map<String, String> props = new HashMap<String, String>();
  122   
  123           // parse the command line (exit in case of failure)
  124           if (commandLine == null) {
  125               setCommandLine(new HashMap<String, String>());
  126           }
  127   
  128           // if sling.home was set on the command line, set it in the properties
  129           if (slingHome != null) {
  130               props.put(SharedConstants.SLING_HOME, slingHome);
  131           } else if (commandLine.containsKey(SharedConstants.SLING_HOME)) {
  132               props.put(SharedConstants.SLING_HOME,
  133                   commandLine.get(SharedConstants.SLING_HOME));
  134           }
  135   
  136           // set up and configure Felix Logger
  137           int logLevel;
  138           if (!commandLine.containsKey(PROP_LOG_LEVEL)) {
  139               logLevel = DEFAULT_LOG_LEVEL;
  140           } else {
  141               logLevel = toLogLevelInt(commandLine.get(PROP_LOG_LEVEL),
  142                   DEFAULT_LOG_LEVEL);
  143               commandLine.put(LOG_LEVEL_PROP, String.valueOf(logLevel));
  144           }
  145           Logger logger = new Logger();
  146   
  147           // Display port number on console, in case HttpService doesn't
  148           info("HTTP server port: " + commandLine.get(PROP_PORT), null);
  149   
  150           // prevent tons of needless WARN from the framework
  151           logger.setLogLevel(Logger.LOG_ERROR);
  152   
  153           try {
  154               ResourceProvider resProvider = new ClassLoaderResourceProvider(
  155                   getClass().getClassLoader());
  156   
  157               // creating the instance launches the framework and we are done here
  158               // ..
  159               sling = new Sling(notifiable, logger, resProvider, props) {
  160   
  161                   // overwrite the loadPropertiesOverride method to inject the
  162                   // command
  163                   // line arguments unconditionally. These will not be persisted
  164                   // in any
  165                   // properties file, though
  166                   protected void loadPropertiesOverride(
  167                           Map<String, String> properties) {
  168                       if (commandLine != null) {
  169                           properties.putAll(commandLine);
  170                       }
  171                   }
  172               };
  173   
  174               // we successfully started it
  175               return true;
  176   
  177           } catch (BundleException be) {
  178               error("Failed to Start OSGi framework", be);
  179           }
  180   
  181           // we failed to start
  182           return false;
  183       }
  184   
  185       public void stop() {
  186           if (sling != null) {
  187               sling.destroy();
  188               sling = null;
  189           }
  190       }
  191   
  192       /**
  193        * Parses the command line in <code>args</code> and sets appropriate Sling
  194        * configuration options in the <code>props</code> map.
  195        */
  196       private static void parseCommandLine(Map<String, String> args,
  197               Map<String, String> props) {
  198   
  199           for (Entry<String, String> arg : args.entrySet()) {
  200               if (arg.getKey().length() == 1) {
  201                   String value = arg.getValue();
  202                   switch (arg.getKey().charAt(0)) {
  203                       case 'l':
  204                           if (value == arg.getKey()) {
  205                               terminate("Missing log level value", 1);
  206                               continue;
  207                           }
  208                           try {
  209                               int logLevel = Integer.parseInt(value);
  210                               value = toLogLevel(logLevel);
  211                           } catch (NumberFormatException nfe) {
  212                               // might be a log level string
  213                               value = checkLogLevel(value);
  214                           }
  215                           if (value != null) {
  216                               props.put(PROP_LOG_LEVEL, value);
  217                           }
  218                           break;
  219   
  220                       case 'f':
  221                           if (value == arg.getKey()) {
  222                               terminate("Missing log file value", 1);
  223                               continue;
  224                           } else if ("-".equals(value)) {
  225                               value = "";
  226                           }
  227                           props.put(PROP_LOG_FILE, value);
  228                           break;
  229   
  230                       case 'c':
  231                           if (value == arg.getKey()) {
  232                               terminate("Missing directory value", 1);
  233                               continue;
  234                           }
  235                           props.put(SharedConstants.SLING_HOME, value);
  236                           break;
  237   
  238                       case 'p':
  239                           if (value == arg.getKey()) {
  240                               terminate("Missing port value", 1);
  241                               continue;
  242                           }
  243                           try {
  244                               // just to verify it is a number
  245                               Integer.parseInt(value);
  246                               props.put(PROP_PORT, value);
  247                           } catch (RuntimeException e) {
  248                               terminate("Bad port: " + value, 1);
  249                           }
  250                           break;
  251   
  252                       case 'a':
  253                           if (value == arg.getKey()) {
  254                               terminate("Missing address value", 1);
  255                               continue;
  256                           }
  257                           info("Setting the address to bind to is not supported, binding to 0.0.0.0", null);
  258                           break;
  259   
  260                       default:
  261                           terminate("Unrecognized option " + arg.getKey(), 1);
  262                           break;
  263                   }
  264               } else {
  265                   terminate("Unrecognized option " + arg.getKey(), 1);
  266               }
  267           }
  268       }
  269   
  270       /** Converts the loglevel code to a loglevel string name */
  271       private static String toLogLevel(int level) {
  272           if (level >= 0 && level < logLevels.length) {
  273               return logLevels[level];
  274           }
  275   
  276           terminate("Bad log level: " + level, 1);
  277           return null;
  278       }
  279   
  280       /**
  281        * Verifies the log level is one of the known values, returns null otherwise
  282        */
  283       private static String checkLogLevel(String level) {
  284           for (int i = 0; i < logLevels.length; i++) {
  285               if (logLevels[i].equalsIgnoreCase(level)) {
  286                   return logLevels[i];
  287               }
  288           }
  289   
  290           terminate("Bad log level: " + level, 1);
  291           return null;
  292       }
  293   
  294       /** Return the log level code for the string */
  295       private static int toLogLevelInt(String level, int defaultLevel) {
  296           for (int i = 0; i < logLevels.length; i++) {
  297               if (logLevels[i].equalsIgnoreCase(level)) {
  298                   return i;
  299               }
  300           }
  301   
  302           return defaultLevel;
  303       }
  304   
  305       // ---------- console logging
  306   
  307       /** prints a simple usage plus optional error message and exists with code */
  308       private static void terminate(String message, int code) {
  309           if (message != null) {
  310               error(message + " (use -h for more information)", null);
  311           }
  312   
  313           System.exit(code);
  314       }
  315   
  316       // emit an informational message to standard out
  317       static void info(String message, Throwable t) {
  318           log(System.out, "*INFO*", message, t);
  319       }
  320   
  321       // emit an error message to standard err
  322       static void error(String message, Throwable t) {
  323           log(System.err, "*ERROR*", message, t);
  324       }
  325   
  326       private static final DateFormat fmt = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss.SSS ");
  327   
  328       // helper method to format the message on the correct output channel
  329       // the throwable if not-null is also prefixed line by line with the prefix
  330       private static void log(PrintStream out, String prefix, String message,
  331               Throwable t) {
  332   
  333           final StringBuilder linePrefixBuilder = new StringBuilder();
  334           synchronized (fmt) {
  335               linePrefixBuilder.append(fmt.format(new Date()));
  336           }
  337           linePrefixBuilder.append(prefix);
  338           linePrefixBuilder.append(" [");
  339           linePrefixBuilder.append(Thread.currentThread().getName());
  340           linePrefixBuilder.append("] ");
  341           final String linePrefix = linePrefixBuilder.toString();
  342   
  343           out.print(linePrefix);
  344           out.println(message);
  345           if (t != null) {
  346               t.printStackTrace(new PrintStream(out) {
  347                   @Override
  348                   public void println(String x) {
  349                       synchronized (this) {
  350                           print(linePrefix);
  351                           super.println(x);
  352                           flush();
  353                       }
  354                   }
  355               });
  356           }
  357       }
  358   }

Save This Page
Home » org.apache.sling.launchpad.base-2.2.0-source-release » org.apache.sling.launchpad.base.app » [javadoc | source]