// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package net.sourceforge.eclipsejetty.starter.common;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import net.sourceforge.eclipsejetty.starter.console.Console;
import net.sourceforge.eclipsejetty.starter.util.Utils;
import net.sourceforge.eclipsejetty.starter.util.service.GlobalServiceResolver;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Abstract base class for the Jetty launcher
*
* @author Manfred Hantschel
*/
public abstract class AbstractJettyLauncherMain
{
public static final String CONFIGURATION_KEY = "jetty.launcher.configuration";
public static final String HIDE_LAUNCH_INFO_KEY = "jetty.launcher.hideLaunchInfo";
public static final String DISABLE_CONSOLE_KEY = "jetty.launcher.disableConsole";
/**
* Launches the server. This method has to be called by the main method of the implementations for the various Jetty
* version.
*
* @param args the arguments
* @throws Exception on occasion
*/
protected void launch(String[] args) throws Exception
{
long millis = System.currentTimeMillis();
boolean showInfo = System.getProperty(HIDE_LAUNCH_INFO_KEY) == null;
boolean consoleEnabled = System.getProperty(DISABLE_CONSOLE_KEY) == null;
if (showInfo)
{
printLogo(System.out);
}
String configurationFileDef = System.getProperty(CONFIGURATION_KEY);
if (configurationFileDef == null)
{
throw new IOException(String.format("-D%s missing", CONFIGURATION_KEY));
}
File[] configurationFiles = getConfigurationFiles(configurationFileDef);
ServerAdapter adapter = createAdapter(configurationFiles, showInfo);
configure(System.out, adapter, configurationFiles, showInfo);
if (showInfo)
{
adapter.info(System.out);
}
initConsole(consoleEnabled, adapter);
adapter.start();
if (showInfo)
{
printStartupTime(System.out, millis, consoleEnabled);
}
}
/**
* Initializes the console, if enabled.
*
* @param consoleEnabled true if enabled
* @param adapter the server adapter
*/
private void initConsole(boolean consoleEnabled, ServerAdapter adapter)
{
if (consoleEnabled)
{
try
{
Class.forName("net.sourceforge.eclipsejetty.starter.console.Console");
GlobalServiceResolver serviceResolver = GlobalServiceResolver.INSTANCE;
serviceResolver.register(adapter);
Console console = Console.INSTANCE;
console.initialize(serviceResolver);
console.start();
}
catch (ClassNotFoundException e)
{
// ignore
}
}
}
protected abstract ServerAdapter createAdapter(File[] configurationFiles, boolean showInfo) throws Exception;
protected abstract void printLogo(PrintStream out);
protected void configure(PrintStream out, ServerAdapter adapter, File[] configurationFiles, boolean showInfo)
throws Exception
{
for (int i = 0; i < configurationFiles.length; i += 1)
{
File configurationFile = configurationFiles[i];
if (showInfo)
{
out.println(String.format("%18s%s", (i == 0) ? "Configuration: " : Utils.EMPTY,
configurationFile.getAbsolutePath()));
}
Class<?> type = determineClass(configurationFile);
FileInputStream in = new FileInputStream(configurationFile);
try
{
configure(in, type, adapter);
}
finally
{
in.close();
}
}
}
protected abstract void configure(FileInputStream in, Class<?> type, ServerAdapter adapter) throws Exception;
protected static File[] getConfigurationFiles(String definitionList) throws IOException
{
String[] definitions = definitionList.split(File.pathSeparator);
List<File> files = new ArrayList<File>();
for (String definition : definitions)
{
if (definition.trim().length() <= 0)
{
continue;
}
File file = new File(definition.trim());
files.add(file);
if (!file.canRead())
{
throw new IOException(String.format("Cannot read configuration file: %s", file));
}
}
return files.toArray(new File[files.size()]);
}
protected static Class<?> determineClass(File file) throws IOException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setExpandEntityReferences(false);
try
{
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
}
catch (ParserConfigurationException e1)
{
// ignore
}
DocumentBuilder builder;
try
{
builder = factory.newDocumentBuilder();
}
catch (ParserConfigurationException e)
{
throw new IOException(String.format("Failed to configure parser: %s", e.getMessage()));
}
Document document;
try
{
document = builder.parse(new InputSource(new FileInputStream(file)));
}
catch (SAXException e)
{
throw new IOException(String.format("Failed to parse %s: %s", file, e.getMessage()));
}
catch (IOException e)
{
throw new IOException(String.format("Failed to read %s: %s", file, e.getMessage()));
}
NodeList nodeList = document.getElementsByTagName("Configure");
if (nodeList.getLength() < 1)
{
throw new IOException(String.format("Failed to find <Configure> element in %s", file));
}
Node node = nodeList.item(0);
NamedNodeMap attributes = node.getAttributes();
if (attributes == null)
{
throw new IOException(String.format("Failed to class argument in <Configure> element in %s", file));
}
Node item = attributes.getNamedItem("class");
if (item == null)
{
throw new IOException(String.format("Failed to class argument in <Configure> element in %s", file));
}
String value = item.getNodeValue().trim();
try
{
return Class.forName(value);
}
catch (ClassNotFoundException e)
{
throw new IOException(String.format("Unknown class %s in <Configure> element in %s", value, file));
}
}
protected void printStartupTime(PrintStream out, long millis, boolean consoleEnabled)
{
Runtime runtime = Runtime.getRuntime();
System.gc();
double seconds = ((double) System.currentTimeMillis() - millis) / 1000d;
long maxMemory = runtime.maxMemory();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
String duration = String.format("Jetty startup finished in %s.", Utils.formatSeconds(seconds));
String console = (consoleEnabled) ? "Console available: type \"help\"." : Utils.EMPTY;
String memory =
String.format("Used memory: %s of %s (%s maximum)", Utils.formatBytes(totalMemory - freeMemory),
Utils.formatBytes(totalMemory), Utils.formatBytes(maxMemory));
String line = Utils.repeat("-", Math.max(duration.length(), Math.max(memory.length(), console.length())));
out.println(line);
out.println(duration);
out.println(memory);
if (console.length() > 0)
{
out.println(console);
}
out.println(line);
}
}