package org.nutz.mvc;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Enumeration;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.impl.NutIoc;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.combo.ComboIocLoader;
import org.nutz.lang.Mirror;
import org.nutz.lang.Streams;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.resource.Scans;
/**
* <p>
* 定义全局Ioc容器,并实现IocProvider接口,以便与@IocBy注解的融合.
* </p>
* <p>
* <b>本实现使用ComboIocLoader作为加载器,所以允许加载其他人员IocLoader定义</b>
* </p>
* <p>
* 基本配置流程
* </p>
* <p>
* 1. 在web.xml声明本监听器
* </p>
* <p>
* 2. 在web.xml中声明一个param-name叫nutz-iocby,内容是传统ComboIocLoader的参数,用逗号分隔
* </p>
* <p>
* 2. 或者在/WEB-INF下放一个nutz.properties, 内容是nutz-iocby=XXXXXXXX
* </p>
* <p>
* 3. 在MainModule中声明@IocBy(type=NutMvcListener.class)
* </p>
*
* @author wendal(wendal1985@gmail.com)
*
*/
public class NutMvcListener implements ServletContextListener, IocProvider {
public static String PROP_LOCATION = "nutz-properties-location";
public static String IOCBY = "iocby";
protected ServletContext sc;
protected PropertiesProxy pp;
private static final Log log = Logs.get();
protected static Ioc ioc;
/**
* 返回全局Ioc对象,如果未经初始化, 这里就会抛出异常
*/
public static Ioc ioc() {
if (ioc == null)
throw new IllegalArgumentException("NutMvcListener NOT init!!! check your web.xml!!");
return ioc;
}
public void contextInitialized(ServletContextEvent event) {
sc = event.getServletContext();
Scans.me().init(sc);
findConfig();
initIoc();
// TODO 其他可配置项.
}
/**
* 首先,载入需要的配置信息, 分别从nutz.properties和ServletContext的上下文获取.
* <p/>
* 子类可以覆盖这个方法实现从任意方式加载配置
*/
protected void findConfig() {
String propLocation = sc.getInitParameter(PROP_LOCATION);
if (Strings.isBlank(propLocation)) {
propLocation = "nutz.properties";
}
PropertiesProxy pp = new PropertiesProxy();
Enumeration<String> params = sc.getInitParameterNames();
while (params.hasMoreElements()) {
String name = (String) params.nextElement();
if (name.startsWith("nutz-")) {
pp.put(name, sc.getInitParameter(name).trim());
}
}
// 先找找classpath
InputStream in = getClass().getClassLoader().getResourceAsStream("/" + propLocation);
if (in == null) {
in = sc.getResourceAsStream("/WEB-INF/" + propLocation);
}
if (in == null) {
log.debug(propLocation + " not found");
} else {
pp = new PropertiesProxy(in);
Streams.safeClose(in);
}
this.pp = pp;
}
/**
* 初始化Ioc容器,使用ComboIocLoader作为配置方式
*/
protected void initIoc() {
String key = "nutz-" + IOCBY;
String iocby = pp.get(key);
if (Strings.isBlank(iocby)) {
throw new RuntimeException(key + " not found nutz.ini or context-param !!");
}
String[] args = Strings.splitIgnoreBlank(iocby);
for (int i = 0; i < args.length; i++) {
args[i] = args[i].trim();
}
log.info("init Ioc by args=" + Arrays.toString(args));
try {
ioc = new NutIoc(new ComboIocLoader(args));
}
catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* 容器销毁时,检查Ioc是否已经关闭,没有的话就关闭之.
*/
public void contextDestroyed(ServletContextEvent event) {
if (ioc() != null) {
Ioc ioc = ioc();
if (ioc instanceof NutIoc) {
boolean deposed = (Boolean) Mirror.me(ioc).getValue(ioc, "deposed");
if (!deposed)
ioc.depose();
}
}
}
/**
* 这里与IocBy结合起来. 注意,这个实现会忽略IocBy的args参数.
*/
public Ioc create(NutConfig config, String[] args) {
if (args != null && args.length > 0) {
if (log != null)
log.warn("args ignore : " + Arrays.toString(args));
}
return ioc();
}
}