/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * 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 *******************************************************************************/ package org.ebayopensource.turmeric.runtime.spf.pipeline; import static org.ebayopensource.turmeric.runtime.common.types.SOAConstants.*; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; 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.ebayopensource.turmeric.runtime.common.exceptions.ServiceException; import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager; import org.ebayopensource.turmeric.runtime.common.pipeline.Transport; import org.ebayopensource.turmeric.runtime.spf.impl.internal.config.InitializerConfigManager; import org.ebayopensource.turmeric.runtime.spf.impl.internal.service.ServerServiceDesc; import org.ebayopensource.turmeric.runtime.spf.impl.pipeline.ServerMessageContextBuilder; import org.ebayopensource.turmeric.runtime.spf.impl.transport.http.HTTPServerUtils; import org.ebayopensource.turmeric.runtime.spf.impl.transport.http.HTTPServletResponseTransport; import org.ebayopensource.turmeric.runtime.spf.impl.transport.http.ISOATransportRequest; import org.ebayopensource.turmeric.runtime.spf.impl.transport.http.SOAServerTransportRequest; import com.ebay.kernel.configuration.ConfigurationContext; import com.ebay.kernel.logger.LoggerInitHelper; import com.ebay.kernel.memtrace.MemTrace; /** * This is the entry point for all services in the synchronous world. * * This servlet provides a minimal amount of "glue" to the server-side framework. A request * message is constructed using the input stream, and a response message and containing * MessageContext are also constructed. This information is submitted to the * ServerMessageProcessor which manages the interface to the message protocol processor as well * as all pipeline operation. * * The standard servlet methods for both HTTP GET and HTTP POST handling are implemented. * * The servlet initializer reads an optional parameter from the servlet's web.xml entry. * This can be used to narrow the service support to one specific service (administrative name). * * @author smalladi, ichernyshev */ public class SPFServlet extends HttpServlet { /** * serial version UID. */ static final long serialVersionUID = 835486766282112209L; private String m_serviceAdminName; private String m_urlMatchExpression; private static final Logger LOGGER = LogManager.getInstance(SPFServlet.class); /* * * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } /** * Called by the server (via the service method) to allow a servlet to handle a DELETE request. * * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } /** * Called by the server (via the service method) to allow a servlet to handle a PUT request. * * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } /* * Called by the server (via the service method) to allow a servlet to handle a POST request. * * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String cmdName = "SOA_Unknown"; MemTrace.getInstance().startCommandTracing(); try { Transport responseTransport = new HTTPServletResponseTransport(req, resp); ISOATransportRequest soaRequest = SOAServerTransportRequest.createRequest(req); HTTPServerUtils serverUtils = new HTTPServerUtils(soaRequest, m_serviceAdminName, m_urlMatchExpression); RequestMetaContext reqMetaCtx = serverUtils.getReqMetaCtx(); PseudoOperation pseudoOp = PseudoOperationHelper.getPseudoOp(reqMetaCtx); if (pseudoOp != null) { cmdName = "SOA_Pseudo_" + pseudoOp.getClass().getSimpleName(); ResponseMetaContext respMetaCtx = new ResponseMetaContext(resp.getOutputStream()); // TODO: avoid exposing internal's ServerServiceDesc here ServerServiceDesc serviceDesc = serverUtils.getServiceResolver().lookupServiceDesc(); pseudoOp.preinvoke(serviceDesc, reqMetaCtx, respMetaCtx); resp.setContentType(respMetaCtx.getContentType()); pseudoOp.invoke(serviceDesc, reqMetaCtx, respMetaCtx); return; } ServerMessageContextBuilder builder = serverUtils.createMessageContext(responseTransport); cmdName = new StringBuilder().append("SOA_").append(builder.getServiceId().getAdminName()). append(".").append(builder.getOperationDesc().getName()).toString(); builder.processCall(); } catch (Throwable e) { LogManager.getInstance(SPFServlet.class). log(Level.SEVERE,"Unexpected error in SPFServlet: " + e.toString(), e); throw new ServletException(e); } finally { MemTrace.getInstance().stopCommandTracing(cmdName); } } /* * A convenience method which can be overridden. * so that there's no need to call <code>super.init(config)</code> * * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) */ @Override public void init(ServletConfig config) throws ServletException { try { initInternal(config); } catch (ServletException e) { reportFailure(e); throw e; } catch (RuntimeException e) { reportFailure(e); throw e; } catch (Error e) { reportFailure(e); throw e; } } private void reportFailure(Throwable error) throws ServletException { try { ConfigurationContext configContext = ConfigurationContext.getInstance(); if (!configContext.getInitSuccess() || configContext.getInitErrMsg() != null) { // already have failure, don't add more return; } configContext.setInitSuccess(false); configContext.setInitErrMsg("SOA initialization failure: " + error.toString()); } catch (Exception e) { e.printStackTrace(); // KEEPME } } private void initInternal(ServletConfig config) throws ServletException { System.out.println("Initializing SPFServlet"); //KEEPME String logInit = config.getInitParameter(SERVLET_PARAM_LOGGER_INIT); // Only initialize logging if needed. if((logInit == null) || ("true".equalsIgnoreCase(logInit))) { String loggerConfigName = config.getInitParameter(SERVLET_PARAM_LOGGER_RESOURCE_NAME); if(loggerConfigName == null) { // Initialize MicroKernel logger using defaults. LoggerInitHelper.initLogger(); } else { // Initialize MicroKernel logger defined configuration. com.ebay.kernel.logger.Logger.initLogProperties(loggerConfigName); } } try { ServerMessageContextBuilder.init(); } catch (ServiceException e) { throw new ServletException(e); } // Servlet param name will be changed to SOA_ADMIN_NAME in 2.4 m_serviceAdminName = config.getInitParameter(SERVLET_PARAM_ADMIN_NAME); if(m_serviceAdminName == null) { m_serviceAdminName = config.getInitParameter(SERVLET_PARAM_SERVICE_NAME); } if (m_serviceAdminName != null) { try { ServerMessageContextBuilder.validateServiceName(m_serviceAdminName); } catch (ServiceException e) { throw new ServletException("Unable to load servlet for " + m_serviceAdminName, e); } callInitializers(config); } getUrlMappingExpression(config); System.out.println("Initializing SPFServlet - DONE"); //KEEPME } private void callInitializers(ServletConfig config) throws ServletException { String noInitializer = config.getInitParameter(NO_INITIALIZER_PARAM_NAME); if (Boolean.valueOf(noInitializer).booleanValue()) { final String logMsg = "Initializers blocked for " + m_serviceAdminName + " service's servlet"; if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(logMsg); } log(logMsg); return; } try { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Calling initializers for service " + m_serviceAdminName); } InitializerConfigManager.getInstance().callInitializers(m_serviceAdminName); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error calling initializers for service " + m_serviceAdminName, e); } } private void getUrlMappingExpression(ServletConfig config) throws ServletException { String urlMatch = config.getInitParameter(SERVLET_PARAM_URL_MATCH_EXPRESSION); if (urlMatch != null) { if (m_serviceAdminName != null) { StringBuilder error = new StringBuilder(); error.append("Unable to load servlet for ").append(m_serviceAdminName); error.append(". Init param conflict: Expecting either "); error.append(SERVLET_PARAM_SERVICE_NAME).append(" / ").append(SERVLET_PARAM_ADMIN_NAME); error.append(" or ").append(SERVLET_PARAM_URL_MATCH_EXPRESSION); throw new ServletException(error.toString()); } boolean invalidInput = false; if (urlMatch.startsWith("query[")) { if (!urlMatch.endsWith("]") || urlMatch.length() < 8) { invalidInput = true; } } else if (urlMatch.equals("queryop")) { // } else if (urlMatch.startsWith("path[")) { if (!urlMatch.endsWith("]") || urlMatch.length() < 7) { invalidInput = true; } String indexval = urlMatch.substring(5, urlMatch.length()-1); try { Integer.valueOf(indexval); } catch (NumberFormatException e) { invalidInput = true; } } else { invalidInput = true; } if (invalidInput) { StringBuilder error = new StringBuilder(); error.append("Unable to load servlet for ").append(m_serviceAdminName); error.append(". I. Init param format error: "); error.append(SERVLET_PARAM_URL_MATCH_EXPRESSION).append("=").append(urlMatch); throw new ServletException(error.toString()); } m_urlMatchExpression = urlMatch; } } }