/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* 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 org.seasar.framework.container.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.seasar.framework.aop.impl.PointcutImpl;
import org.seasar.framework.container.ArgDef;
import org.seasar.framework.container.ArgDefAware;
import org.seasar.framework.container.AspectDef;
import org.seasar.framework.container.ComponentDef;
import org.seasar.framework.container.ContainerNotRegisteredRuntimeException;
import org.seasar.framework.container.Expression;
import org.seasar.framework.container.MethodDef;
import org.seasar.framework.container.PropertyDef;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
import org.seasar.framework.container.impl.ArgDefImpl;
import org.seasar.framework.container.util.SmartDeployUtil;
import org.seasar.framework.env.Env;
import org.seasar.framework.util.StringUtil;
import org.seasar.framework.util.URLUtil;
/**
* {@link S2Container}用の {@link HttpServlet}です。
*
* @author higa
*
*/
public class S2ContainerServlet extends HttpServlet {
private static final long serialVersionUID = 407266935204779128L;
/**
* 初期化パラメータの設定パスのキーです。
*/
public static final String CONFIG_PATH_KEY = "configPath";
/**
* 初期化パラメータのデバッグのキーです。
*/
public static final String DEBUG_KEY = "debug";
/**
* queryStringのコマンドのキーです。
*/
public static final String COMMAND = "command";
/**
* queryStringの再起動のキーです。
*/
public static final String RESTART = "restart";
/**
* queryStringの一覧のキーです。
*/
public static final String LIST = "list";
/**
* パスです。
*/
public static final String PATH = "path";
private static final String MODE_BEGIN = "<strong><font color='#DC143C'>";
private static final String MODE_END = "</font></strong>";
private static S2ContainerServlet instance;
private boolean debug;
/**
* {@link S2ContainerServlet}を作成します。
*/
public S2ContainerServlet() {
instance = this;
}
/**
* {@link S2ContainerServlet}を返します。
*
* @return {@link S2ContainerServlet}
*/
public static S2ContainerServlet getInstance() {
return instance;
}
/**
* インスタンスをクリアします。
*/
public static void clearInstance() {
instance = null;
}
public void init() {
String configPath = null;
String debugStr = null;
ServletConfig servletConfig = getServletConfig();
if (servletConfig != null) {
configPath = servletConfig.getInitParameter(CONFIG_PATH_KEY);
debugStr = servletConfig.getInitParameter(DEBUG_KEY);
}
if (!StringUtil.isEmpty(debugStr)) {
debug = Boolean.valueOf(debugStr).booleanValue();
}
initializeContainer(configPath);
}
/**
* {@link org.seasar.framework.container.S2Container}を初期化します。
*
* @param configPath
*/
protected void initializeContainer(String configPath) {
SingletonS2ContainerInitializer initializer = new SingletonS2ContainerInitializer();
initializer.setConfigPath(configPath);
initializer.setApplication(getServletContext());
initializer.initialize();
}
public void destroy() {
S2ContainerDestroyer.destroy();
}
/**
* {@link S2Container}を返します。
*
* @return {@link S2Container}
*/
public static S2Container getContainer() {
return SingletonS2ContainerFactory.getContainer();
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String command = request.getParameter(COMMAND);
if (debug && command != null && RESTART.equalsIgnoreCase(command)) {
destroy();
init();
response.setContentType("text/plain; charset=UTF-8");
response.getWriter().write("S2ContainerServlet is restarted.");
} else if (debug && LIST.equalsIgnoreCase(command)) {
response.setContentType("text/html; charset=UTF-8");
list(request, response);
} else {
response.setContentType("text/plain; charset=UTF-8");
response.getWriter().write("S2ContainerServlet is running.");
}
}
/**
* {@link S2Container}の中身({@link ComponentDef})を表示します。
*
* @param request
* @param response
* @throws IOException
*/
protected void list(final HttpServletRequest request,
final HttpServletResponse response) throws IOException {
final PrintWriter out = response.getWriter();
final String path = request.getParameter(PATH);
final S2Container container = getContainer(path);
if (container == null) {
out.write("S2Container[" + escape(path) + "] is not found.");
return;
}
out
.write("<html><head><title>Seasar2 Component List</title></head><body>");
try {
out.write("<h1>S2Container</h1>");
printSmartDeploy(container, out);
out.write("<ul>");
try {
out.write("<li>path : <code>" + escape(container.getPath())
+ "</code></li>");
final String nameSpace = container.getNamespace();
if (!StringUtil.isEmpty(nameSpace)) {
out.write("<li>namespace : <code>" + escape(nameSpace)
+ "</code></li>");
}
final String envValue = Env.getValue();
if (!StringUtil.isEmpty(envValue)) {
out.write("<li>env : <code>" + escape(envValue)
+ "</code></li>");
}
} finally {
out.write("</ul>");
}
listInclude(container, request, out);
listComponent(container, out);
} finally {
out.write("</body></html>");
}
}
/**
* {@link S2Container}を返します。
*
* @param path
* @return {@link S2Container}
*/
protected S2Container getContainer(final String path) {
final S2Container root = SingletonS2ContainerFactory.getContainer();
try {
return StringUtil.isEmpty(path) ? root : root.getDescendant(path);
} catch (final ContainerNotRegisteredRuntimeException e) {
return null;
}
}
private void printSmartDeploy(final S2Container container,
final PrintWriter out) {
out.write("<p>S2Container is working under ");
try {
if (SmartDeployUtil.isHotdeployMode(container)) {
out.write(MODE_BEGIN + "HOT deploy" + MODE_END);
} else if (SmartDeployUtil.isWarmdeployMode(container)) {
out.write(MODE_BEGIN + "WARM deploy" + MODE_END);
} else if (SmartDeployUtil.isCooldeployMode(container)) {
out.write(MODE_BEGIN + "COOL deploy" + MODE_END);
} else {
out.write("normal");
}
} finally {
out.write(" mode.</p>");
}
}
private void listInclude(final S2Container container,
final HttpServletRequest request, final PrintWriter out)
throws IOException {
if (container.getChildSize() == 0) {
return;
}
out.write("<h2>Includes</h2>");
out.write("<p><ul>");
try {
final String requestUri = request.getRequestURI();
final String queryString = "?" + COMMAND + "=" + LIST + "&" + PATH
+ "=";
for (int i = 0; i < container.getChildSize(); ++i) {
final S2Container child = container.getChild(i);
final String path = child.getPath();
out.write("<li><a href='" + requestUri + queryString
+ URLUtil.encode(path, "UTF-8") + "'><code>" + path
+ "</code></a></li>");
}
} finally {
out.write("</ul></p>");
}
}
private void listComponent(final S2Container container,
final PrintWriter out) throws IOException {
if (container.getComponentDefSize() == 0) {
return;
}
out.write("<h2>Components</h2>");
out.write("<p><ul>");
try {
for (int i = 0; i < container.getComponentDefSize(); ++i) {
final ComponentDef cd = container.getComponentDef(i);
printComponent(cd, out);
}
} finally {
out.write("</ul></p>");
}
}
private void printComponent(final ComponentDef cd, final PrintWriter out)
throws IOException {
final String name = cd.getComponentName();
final Class clazz = cd.getComponentClass();
out.write("<li style='list-style-type: square'><code><strong>"
+ (name != null ? escape(name) : "-") + " ["
+ (clazz != null ? escape(clazz.getName()) : "-")
+ "]</strong></code>");
out.write("<ul>");
out.write("<li style='list-style-type: circle'>instance : <code>"
+ escape(cd.getInstanceDef().getName()) + "</code></li>");
out.write("<li style='list-style-type: circle'>autoBinding : <code>"
+ escape(cd.getAutoBindingDef().getName()) + "</code></li>");
Expression expression = cd.getExpression();
final String expr = (expression != null) ? expression.toString() : "";
if (!StringUtil.isEmpty(expr)) {
out.write("<li style='list-style-type: circle'>ognl : <code>"
+ escape(expr) + "</code></li>");
}
printArg(cd, out);
printAspect(cd, out);
printProperty(cd, out);
printInitMethod(cd, out);
printDestroyMethod(cd, out);
try {
final Object component = cd.getComponent();
out
.write("<li style='list-style-type: circle'>toString : <pre style='border-style: solid; border-width: 1'>"
+ escape(component.toString()) + "</pre></li>");
} catch (final Exception ignore) {
}
out.write("</ul>");
}
private void printArg(final ArgDefAware cd, final PrintWriter out)
throws IOException {
for (int i = 0; i < cd.getArgDefSize(); ++i) {
out.write("<li style='list-style-type: circle'>arg<ul>");
final ArgDef ad = cd.getArgDef(i);
Expression expression = ad.getExpression();
final String expr = (expression != null) ? expression.toString()
: "";
if (!StringUtil.isEmpty(expr)) {
out.write("<li style='list-style-type: circle'>ognl : <code>"
+ escape(expr) + "</code></li>");
}
final ComponentDef child = getChildComponentDef(ad);
if (child != null) {
printComponent(child, out);
}
out.write("</ul></li>");
}
}
private void printAspect(final ComponentDef cd, final PrintWriter out)
throws IOException {
for (int i = 0; i < cd.getAspectDefSize(); ++i) {
out.write("<li style='list-style-type: circle'>aspect<ul>");
final AspectDef ad = cd.getAspectDef(i);
final PointcutImpl pc = (PointcutImpl) ad.getPointcut();
if (pc != null) {
final String[] pointCuts = pc.getMethodNames();
if (pointCuts != null && pointCuts.length > 0) {
out
.write("<li style='list-style-type: circle'>pointcut<ul>");
for (int j = 0; j < pointCuts.length; ++j) {
out.write("<li style='list-style-type: circle'><code>"
+ escape(pointCuts[j]) + "</code></li>");
}
out.write("</ul></li>");
}
}
Expression expression = ad.getExpression();
final String expr = (expression != null) ? expression.toString()
: "";
if (!StringUtil.isEmpty(expr)) {
out.write("<li style='list-style-type: circle'>ognl : <code>"
+ escape(expr) + "</code></li>");
}
final ComponentDef child = getChildComponentDef(ad);
if (child != null) {
printComponent(child, out);
}
out.write("</ul></li>");
}
}
private void printProperty(final ComponentDef cd, final PrintWriter out)
throws IOException {
for (int i = 0; i < cd.getPropertyDefSize(); ++i) {
out.write("<li style='list-style-type: circle'>property<ul>");
final PropertyDef pd = cd.getPropertyDef(i);
out.write("<li style='list-style-type: circle'>name : <code>"
+ escape(pd.getPropertyName()) + "</code></li>");
Expression expression = pd.getExpression();
final String expr = (expression != null) ? expression.toString()
: "";
if (!StringUtil.isEmpty(expr)) {
out.write("<li style='list-style-type: circle'>ognl : <code>"
+ escape(expr) + "</code></li>");
}
final ComponentDef child = getChildComponentDef(pd);
if (child != null) {
printComponent(child, out);
}
out.write("</ul></li>");
}
}
private void printInitMethod(final ComponentDef cd, final PrintWriter out)
throws IOException {
for (int i = 0; i < cd.getInitMethodDefSize(); ++i) {
out.write("<li style='list-style-type: circle'>initMethod<ul>");
printMethod(cd.getInitMethodDef(i), out);
out.write("</ul></li>");
}
}
private void printDestroyMethod(final ComponentDef cd, final PrintWriter out)
throws IOException {
for (int i = 0; i < cd.getDestroyMethodDefSize(); ++i) {
out.write("<li style='list-style-type: circle'>destroyMethod<ul>");
printMethod(cd.getDestroyMethodDef(i), out);
out.write("</ul></li>");
}
}
private void printMethod(final MethodDef md, final PrintWriter out)
throws IOException {
out.write("<li style='list-style-type: circle'>name : <code>"
+ escape(md.getMethodName()) + "</code></li>");
Expression expression = md.getExpression();
final String expr = (expression != null) ? expression.toString() : "";
if (!StringUtil.isEmpty(expr)) {
out.write("<li style='list-style-type: circle'>ognl : <code>"
+ escape(expr) + "</code></li>");
}
final ComponentDef child = getChildComponentDef(md);
if (child != null) {
printComponent(child, out);
}
}
private ComponentDef getChildComponentDef(final Object o) {
try {
final Field f = ArgDefImpl.class
.getDeclaredField("childComponentDef");
f.setAccessible(true);
return (ComponentDef) f.get(o);
} catch (final Exception e) {
return null;
}
}
private String escape(final String text) {
if (text == null) {
return "null";
}
final StringBuffer buf = new StringBuffer(text.length() * 4);
for (int i = 0; i < text.length(); ++i) {
final char ch = text.charAt(i);
switch (ch) {
case '<':
buf.append("<");
break;
case '>':
buf.append(">");
break;
case '&':
buf.append("&");
break;
case '"':
buf.append(""");
break;
default:
buf.append(ch);
break;
}
}
return new String(buf);
}
}