/**
* Copyright (C) Zhang,Yuexiang (xfeep)
*
*/
package nginx.clojure.tomcat8;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Map;
import nginx.clojure.MiniConstants;
import nginx.clojure.NginxClojureRT;
import nginx.clojure.bridge.NginxBridge;
import nginx.clojure.java.NginxJavaRequest;
import org.apache.catalina.Globals;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Server;
import org.apache.catalina.Service;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.security.SecurityClassLoad;
import org.apache.catalina.startup.Bootstrap;
import org.apache.catalina.startup.Catalina;
import org.apache.coyote.http11.NginxDirectProtocol;
import org.apache.coyote.http11.NginxEndpoint;
import org.apache.tomcat.util.digester.Digester;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;
public class NginxTomcatBridge extends Catalina implements NginxBridge {
protected NginxDirectProtocol nginxDirectProtocol;
protected static final org.apache.juli.logging.Log log =
org.apache.juli.logging.LogFactory.getLog( NginxTomcatBridge.class );
protected boolean ignoreNginxFilter = false;
protected boolean dispatch = false;
protected ClassLoader bootLoader;
protected void initWithoutStartServer() {
initDirs();
// Before digester - it may be needed
initNaming();
// Create and execute our Digester
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail", file), e);
}
}
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream(getConfigFile());
inputSource = new InputSource
(getClass().getClassLoader()
.getResource(getConfigFile()).toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail",
getConfigFile()), e);
}
}
}
// This should be included in catalina.jar
// Alternative: don't bother with xml, just create it manually.
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream("server-embed.xml");
inputSource = new InputSource
(getClass().getClassLoader()
.getResource("server-embed.xml").toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail",
"server-embed.xml"), e);
}
}
}
if (inputStream == null || inputSource == null) {
if (file == null) {
log.warn(sm.getString("catalina.configFail",
getConfigFile() + "] or [server-embed.xml]"));
} else {
log.warn(sm.getString("catalina.configFail",
file.getAbsolutePath()));
if (file.exists() && !file.canRead()) {
log.warn("Permissions incorrect, read permission is not allowed on the file.");
}
}
return;
}
try {
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);
} catch (SAXParseException spe) {
log.warn("Catalina.start using " + getConfigFile() + ": " +
spe.getMessage());
return;
} catch (Exception e) {
log.warn("Catalina.start using " + getConfigFile() + ": " , e);
return;
} finally {
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
getServer().setCatalina(this);
getServer().setCatalinaHome(new File(Bootstrap.getCatalinaHome()));
getServer().setCatalinaBase(new File(Bootstrap.getCatalinaBase()));
// Stream redirection
initStreams();
}
@Override
public void boot(Map<String, String> properties, ClassLoader loader) {
if (nginxDirectProtocol != null) {
return;
}
bootLoader = loader;
long t1 = System.nanoTime();
/**
* Hack for tomcat TomcatURLStreamHandlerFactory which uses
* URL.setURLStreamHandlerFactory(this);
* to register URLStreamHandlerFactory. But if we have two tomcat instances it will fail.
*/
try {
Field urlFactory = URL.class.getDeclaredField("factory");
Object base = NginxClojureRT.UNSAFE.staticFieldBase(urlFactory);
NginxClojureRT.UNSAFE.putObject(base, NginxClojureRT.UNSAFE.staticFieldOffset(urlFactory), null);
} catch (Throwable e) {
e.printStackTrace();
}
String tomcatHome = System.getProperty(Globals.CATALINA_HOME_PROP);
if (tomcatHome == null) {
NginxClojureRT.getLog().error("system." + Globals.CATALINA_HOME_PROP + " should be set!");
return;
}
org.apache.juli.logging.Log log=
org.apache.juli.logging.LogFactory.getLog( Catalina.class );
log.info("tomcatHome=" + tomcatHome + ", conf=" + this.configFile);
try {
ClassLoader catalinaLoader = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(catalinaLoader);
SecurityClassLoad.securityClassLoad(catalinaLoader);
this.initWithoutStartServer();
Field protocolHandlerField = Connector.class.getDeclaredField("protocolHandler");
protocolHandlerField.setAccessible(true);
Connector httpConnector = null;
Service httpService = null;
Server server = this.getServer();
for (Service s : server.findServices()) {
for (Connector c : s.findConnectors()) {
if (c.getProtocol().equals("HTTP/1.1")) {
httpConnector = c;
httpService = s;
nginxDirectProtocol = new NginxDirectProtocol();
nginxDirectProtocol.setAdapter(c.getProtocolHandler().getAdapter());
c.setProtocol(NginxDirectProtocol.class.getName());
protocolHandlerField.set(c, nginxDirectProtocol);
}else {
s.removeConnector(c);
}
}
}
try {
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
}
}
this.start();
nginxDirectProtocol = (NginxDirectProtocol) httpConnector.getProtocolHandler();
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
}
String ignoreNginxFilterStr = properties.get("ignoreNginxFilter");
if (ignoreNginxFilterStr != null) {
ignoreNginxFilter = Boolean.parseBoolean(ignoreNginxFilterStr);
}
String dispatchStr = properties.get("dispatch");
if (dispatchStr != null) {
dispatch = Boolean.parseBoolean(dispatchStr);
}
} catch (Throwable t) {
NginxClojureRT.getLog().error("can not start tomcat server", t);
return;
}
}
@Override
public ClassLoader getClassLoader() {
return bootLoader;
}
int i = 0;
@Override
public Object[] handle(NginxJavaRequest req) throws IOException {
NginxEndpoint nginxEndpoint = nginxDirectProtocol.getEndpoint();
req.get(MiniConstants.BODY);
req.get(MiniConstants.REMOTE_ADDR);
nginxEndpoint.accept(req, ignoreNginxFilter, dispatch);
return null;
}
}