/** * */ package com.dianping.pigeon.console.servlet; import java.io.IOException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.springframework.aop.support.AopUtils; import com.dianping.pigeon.config.ConfigManager; import com.dianping.pigeon.config.ConfigManagerLoader; import com.dianping.pigeon.console.Utils; import com.dianping.pigeon.console.domain.Service; import com.dianping.pigeon.console.domain.ServiceMethod; import com.dianping.pigeon.console.status.checker.GlobalStatusChecker; import com.dianping.pigeon.console.status.checker.ProviderStatusChecker; import com.dianping.pigeon.console.status.checker.StatusChecker; import com.dianping.pigeon.log.Logger; import com.dianping.pigeon.log.LoggerLoader; import com.dianping.pigeon.registry.RegistryManager; import com.dianping.pigeon.remoting.ServiceFactory; import com.dianping.pigeon.remoting.common.util.ServiceConfigUtils; import com.dianping.pigeon.remoting.invoker.config.InvokerConfig; import com.dianping.pigeon.remoting.provider.ProviderBootStrap; import com.dianping.pigeon.remoting.provider.Server; import com.dianping.pigeon.remoting.provider.config.ProviderConfig; import com.dianping.pigeon.remoting.provider.config.ServerConfig; import com.dianping.pigeon.remoting.provider.publish.ServicePublisher; import com.dianping.pigeon.util.RandomUtils; import freemarker.cache.ClassTemplateLoader; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; /** * @author sean.wang * @since Jul 16, 2012 */ public class ServiceServlet extends HttpServlet { private static final long serialVersionUID = -2703014417332812558L; private Set<String> ingoreMethods = new HashSet<String>(); protected int port; protected ServerConfig serverConfig; protected Object model; protected final Logger logger = LoggerLoader.getLogger(this.getClass()); protected static ConfigManager configManager = ConfigManagerLoader.getConfigManager(); private static final StatusChecker providerStatusChecker = new ProviderStatusChecker(); protected static boolean isValidate = configManager.getBooleanValue("pigeon.console.invoke.validation", false); protected static boolean directInvoke = configManager.getBooleanValue("pigeon.console.invoke.direct", false); protected static String token; static { if (StringUtils.isBlank(System.getProperty("org.freemarker.loggerLibrary"))) { System.setProperty("org.freemarker.loggerLibrary", "SLF4J"); } } { Method[] objectMethodArray = Object.class.getMethods(); for (Method method : objectMethodArray) { ingoreMethods.add(method.getName() + ":" + Arrays.toString(method.getParameterTypes())); } } private final Configuration cfg = new Configuration(); { cfg.setObjectWrapper(new DefaultObjectWrapper()); ClassTemplateLoader templateLoader = new ClassTemplateLoader(ServiceServlet.class, "/"); cfg.setTemplateLoader(templateLoader); } public ServiceServlet(ServerConfig serverConfig, int port) { this.serverConfig = serverConfig; this.port = port; } public static String getToken() { return token; } public static void setToken(String token) { ServiceServlet.token = token; } public Map<String, ProviderConfig<?>> getServiceProviders() { return ServiceFactory.getAllServiceProviders(); } public Map<InvokerConfig<?>, Object> getInvokerConfigs() { return ServiceFactory.getAllServiceInvokers(); } protected boolean initServicePage(HttpServletRequest request, HttpServletResponse response) throws IOException { ServicePage page = new ServicePage(); Collection<Server> servers = ProviderBootStrap.getServersMap().values(); StringBuilder ports = new StringBuilder(); for (Server server : servers) { if (server.isStarted()) { ports.append(server.getPort()).append("/"); } } if (ports.length() > 0) { ports.deleteCharAt(ports.length() - 1); page.setPort(ports.toString()); } page.setHttpPort(this.port); Map<String, ProviderConfig<?>> serviceProviders = getServiceProviders(); for (Entry<String, ProviderConfig<?>> entry : serviceProviders.entrySet()) { String serviceName = entry.getKey(); ProviderConfig<?> providerConfig = entry.getValue(); Service s = new Service(); s.setName(serviceName); Class<?> beanClass = AopUtils.getTargetClass(providerConfig.getService()); s.setType(beanClass); s.setPublished(providerConfig.isPublished() + ""); Map<String, Method> allMethods = new HashMap<String, Method>(); Method[] methods = ServiceConfigUtils.getServiceInterface(beanClass).getMethods(); for (Method method : methods) { String key = method.getName() + ":" + Arrays.toString(method.getParameterTypes()); if (!ingoreMethods.contains(key)) { allMethods.put(key, method); } } for (Entry<String, Method> methodEntry : allMethods.entrySet()) { Method method = methodEntry.getValue(); s.addMethod(new ServiceMethod(method.getName(), method.getParameterTypes(), method.getReturnType())); } if (configManager.getBooleanValue("pigeon.provider.token.enable", false)) { s.setToken("true"); } page.addService(s); } page.setOnline("" + GlobalStatusChecker.isOnline()); setStatus(page, serviceProviders.isEmpty()); String direct = request.getParameter("direct"); if (direct == null) { direct = directInvoke + ""; } page.setDirect(direct); page.setEnvironment(configManager.getEnv()); page.setGroup(configManager.getGroup()); page.setServiceWeights(ServicePublisher.getServerWeight()); page.setRegistry(RegistryManager.getInstance().getRegistry().getStatistics()); page.setAppName(configManager.getAppName()); page.setStartTime(ProviderBootStrap.getStartTime() + ""); page.setValidate("" + isValidate); String governorAddr = configManager.getStringValue("pigeon.governor.address"); if (StringUtils.isNotBlank(governorAddr)) { page.setGovernorUrl(governorAddr + "/services/" + configManager.getAppName()); } this.model = page; return true; } private void setStatus(ServicePage page, boolean isClientSide) { String error = providerStatusChecker.checkError(); if (!StringUtils.isBlank(error)) { page.setError(error); page.setStatus("error"); } if (isClientSide) {// client-side page.setPublished("none"); } else {// server-side int publishedCount = 0; int unpublishedCount = 0; Map<String, ProviderConfig<?>> services = ServicePublisher.getAllServiceProviders(); for (Entry<String, ProviderConfig<?>> entry : services.entrySet()) { ProviderConfig<?> providerConfig = entry.getValue(); if (providerConfig.isPublished()) { publishedCount++; } else { unpublishedCount++; } } if (publishedCount > 0 && unpublishedCount == 0) { page.setPublished("true"); } else { page.setPublished("false"); } } // set status if (!"error".equals(page.getStatus())) { page.setStatus("ok"); } } public String getView() { return "Service.ftl"; } public String getContentType() { return "text/html; charset=UTF-8"; } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(getContentType()); response.setStatus(HttpServletResponse.SC_OK); generateView(request, response); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } protected void generateView(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Template temp = cfg.getTemplate(getView()); boolean result = initServicePage(request, response); if (result) { try { temp.process(this.model, response.getWriter()); } catch (TemplateException e) { throw new ServletException(e); } if (isValidate) { String token = RandomUtils.newRandomString(6); setToken(token); logger.warn("current verification code:" + token + ", from " + Utils.getIpAddr(request)); } } } }