/*
* This file is part of Mockey, a tool for testing application
* interactions over HTTP, with a focus on testing web services,
* specifically web applications that consume XML, JSON, and HTML.
*
* Copyright (C) 2009-2010 Authors:
*
* chad.lafontaine (chad.lafontaine AT gmail DOT com)
* neil.cronin (neil AT rackle DOT com)
* lorin.kobashigawa (lkb AT kgawa DOT com)
* rob.meyer (rob AT bigdis DOT com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package com.mockey.ui;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import com.mockey.model.ApiDocAttribute;
import com.mockey.model.ApiDocFieldValue;
import com.mockey.model.ApiDocRequest;
import com.mockey.model.ApiDocResponse;
import com.mockey.model.ApiDocService;
import com.mockey.model.ConflictInfo;
import com.mockey.model.HttpStatusCodeStore;
import com.mockey.model.Service;
import com.mockey.model.ServicePlan;
import com.mockey.model.Url;
import com.mockey.plugin.PluginStore;
import com.mockey.runner.BSC;
import com.mockey.storage.IApiStorage;
import com.mockey.storage.IApiStorageInMemory;
import com.mockey.storage.IMockeyStorage;
import com.mockey.storage.StorageRegistry;
import com.mockey.storage.xml.MockeyXmlFileManager;
public class HomeServlet extends HttpServlet {
private static final long serialVersionUID = -5485332140449853235L;
private static IMockeyStorage store = StorageRegistry.MockeyStorage;
private static Logger logger = Logger.getLogger(HomeServlet.class);
private IApiStorage apiStore = IApiStorageInMemory.getInstance();
private static final String API_CONFIGURATION_PARAMETER_ACTION_VALUE_DELETE = "deleteAllServices";
private static final String SUCCESS = "success";
private static final String FAIL = "fail";
/**
* Loads up the HTTP API Documentation in memory for this service. The HTTP
* API information to describe this servlet's REQUEST and RESPONSE messaging
* is displayed to the end user via the Service API help page.
*/
public void init() throws ServletException {
// Load up plugin store with at least one Sample inspectors
PluginStore pluginStore = PluginStore.getInstance();
pluginStore.initializeOrUpdateStore();
// *****************************
// THIS SERVICE API DESCRIPTION CONTRACT
// *****************************
// This information is used in the API JSP document, used to describe
// how to make setting changes from a head-less client.
if (apiStore.getApiDocServiceByName("Initialization") == null) {
ApiDocService apiDocService = new ApiDocService();
apiDocService.setName("Initialization");
apiDocService.setServicePath("/home");
apiDocService
.setDescription("If you need to initialize Mockey with a definitions file, then this API may serve your needs. ");
// *****************************
// REQUEST DEFINITION
// *****************************
ApiDocRequest apiDocRequest = new ApiDocRequest();
// Parameter - 'action'
ApiDocAttribute reqAttributeAction = new ApiDocAttribute();
reqAttributeAction.setFieldName(BSC.ACTION);
reqAttributeAction.addFieldValues(new ApiDocFieldValue(API_CONFIGURATION_PARAMETER_ACTION_VALUE_DELETE,
"Delete all configurations, history, settings, etc., and start with a clean Mockey. "));
reqAttributeAction.addFieldValues(new ApiDocFieldValue(BSC.INIT,
"Will delete everything and configure Mockey with the defined file. "));
apiDocRequest.addAttribute(reqAttributeAction);
// Parameter - 'file'
ApiDocAttribute reqAttributeFile = new ApiDocAttribute();
reqAttributeFile.setFieldName(BSC.FILE);
reqAttributeFile.addFieldValues(new ApiDocFieldValue("[string]",
"Relative path to the service definitions configuration file. Required if 'action' is 'init'"));
reqAttributeFile.setExample("../some_file.xml or /Users/someuser/Work/some_file.xml");
apiDocRequest.addAttribute(reqAttributeFile);
// Parameter - 'type'
ApiDocAttribute reqAttributeType = new ApiDocAttribute();
reqAttributeType.setFieldName(BSC.TYPE);
reqAttributeType
.addFieldValues(new ApiDocFieldValue("json",
"Response will be in JSON. Any other value for 'type' is undefined and you may experience a 302 or get HTML back."));
apiDocRequest.addAttribute(reqAttributeType);
apiDocService.setApiRequest(apiDocRequest);
// Parameter - 'transientState'
ApiDocAttribute reqAttributeState = new ApiDocAttribute();
reqAttributeState.setFieldName(BSC.TRANSIENT);
reqAttributeState
.addFieldValues(new ApiDocFieldValue("boolean", "Read only mode? Also known as transient."));
apiDocRequest.addAttribute(reqAttributeState);
apiDocService.setApiRequest(apiDocRequest);
// *****************************
// RESPONSE DEFINITION
// *****************************
ApiDocResponse apiResponse = new ApiDocResponse();
// Building a JSON RESPONSE example
try {
JSONObject jsonResponseObject = new JSONObject();
JSONObject jsonResultObject = new JSONObject();
jsonResultObject
.put(SUCCESS,
"Some informative coaching message. If success isn't a value, then maybe you have a 'fail' message.");
jsonResultObject.put("file", "Some file name");
jsonResponseObject.put("result", jsonResultObject);
apiResponse.setExample(jsonResponseObject.toString());
} catch (Exception e) {
logger.error("Unabel to build a sample JSON message. ", e);
}
// Response attribute 'file'
ApiDocAttribute resAttributeFile = new ApiDocAttribute();
resAttributeFile.setFieldName(BSC.FILE);
resAttributeFile.setFieldDescription("Name of file used to initialize Mockey.");
apiResponse.addAttribute(resAttributeFile);
// Response attribute 'success'
ApiDocAttribute resAttributeSuccess = new ApiDocAttribute();
resAttributeSuccess.setFieldName(SUCCESS);
resAttributeSuccess
.setFieldDescription("Successfully initialized or deleted service definitions. You get 'fail' or 'success', not both.");
apiResponse.addAttribute(resAttributeSuccess);
ApiDocAttribute resAttributeFail = new ApiDocAttribute();
resAttributeFail.setFieldName(FAIL);
resAttributeFail
.setFieldDescription("Failed to initialize or delete service definitions. You get 'fail' or 'success', not both.");
apiResponse.addAttribute(resAttributeFail);
apiDocService.setApiResponse(apiResponse);
apiStore.saveOrUpdateService(apiDocService);
}
}
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter(BSC.ACTION);
String type = req.getParameter(BSC.TYPE);
// FILTER
// ***********
String filterTagParameter = req.getParameter(BSC.FILTERTAG);
if (filterTagParameter != null) {
store.setGlobalStateSystemFilterTag(filterTagParameter);
}
if (action != null && "init".equals(action)) {
JSONObject jsonResultObject = new JSONObject();
// Load with a definitions file.
String fileName = req.getParameter("file");
// Or with a URL
String fileUrl = req.getParameter(BSC.URL);
Boolean transientState = new Boolean(true);
try {
transientState = new Boolean(req.getParameter(BSC.TRANSIENT));
store.setReadOnlyMode(transientState);
logger.debug("In memory-mode (i.e. do not write to file system)? " + transientState);
} catch (Exception e) {
}
InputStream fstream = null;
try {
if (fileUrl != null) {
// or, from a URL, then retrieve an InputStream from a URL
fstream = new URL(fileUrl).openStream();
} else if (fileName != null) {
File f = new File(fileName);
if (f.exists()) {
fstream = new FileInputStream(f);
} else {
logger.info("Filename '" + fileName + "' does not exist. doing nothing.");
jsonResultObject.put(FAIL, fileName + " does not exist. doing nothing.");
}
}
if (fstream != null) {
// DELETE SECOND
MockeyXmlFileManager reader = MockeyXmlFileManager.getInstance();
String inputAsString = reader.getFileContentAsString(fstream);
store.deleteEverything();
reader.loadConfigurationWithXmlDef(inputAsString, null);
logger.info("Loaded definitions from " + fileName);
jsonResultObject.put(SUCCESS, "Loaded definitions from " + fileName);
jsonResultObject.put(BSC.FILE, fileName);
}
} catch (Exception e) {
logger.debug("Unable to load service definitions with name: '" + fileName + "' or URL: " + fileUrl, e);
try {
jsonResultObject.put(FAIL, "Unable to load service definitions with filename: '" + fileName
+ "' or URL: " + fileUrl);
} catch (Exception ef) {
logger.error("Unable to produce a JSON response.", e);
}
} finally {
if (fstream != null) {
try {
fstream.close();
} catch (Exception e) {
}
}
}
// OK, return JSON or HTML?
if (type != null && type.trim().equalsIgnoreCase("json")) {
resp.setContentType("application/json;");
PrintWriter out = resp.getWriter();
JSONObject jsonResponseObject = new JSONObject();
try {
jsonResponseObject.put("result", jsonResultObject);
} catch (JSONException e) {
logger.error("Unable to produce a JSON result.", e);
}
out.println(jsonResponseObject.toString());
return;
} else {
String contextRoot = req.getContextPath();
resp.sendRedirect(Url.getContextAwarePath("/home", contextRoot));
return;
}
} else if (action != null && "deleteAllServices".equals(action)) {
// Flush - clean slate.
store.deleteEverything();
if (type != null && type.trim().equalsIgnoreCase("json")) {
resp.setContentType("application/json;");
PrintWriter out = resp.getWriter();
JSONObject jsonResponseObject = new JSONObject();
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put(SUCCESS, "All is deleted. You have a clean slate. Enjoy.");
jsonResponseObject.put("result", jsonObject);
} catch (JSONException e) {
logger.error("Unable to produce a JSON result.", e);
}
out.println(jsonResponseObject.toString());
return;
} else {
String contextRoot = req.getContextPath();
resp.sendRedirect(Url.getContextAwarePath("/home", contextRoot));
return;
}
}
// If a Service Plan ID was passed in, then we need to
// highlight the Services (provide a visual cue) to the
// user for which Services are included in the plan.
String servicePlanId = req.getParameter("plan_id");
if (servicePlanId != null) {
try {
ServicePlan sp = store.getServicePlanById(new Long(servicePlanId));
req.setAttribute("servicePlan", sp);
} catch (Exception e) {
logger.debug("Service Plan with ID '" + servicePlanId + "' does not exist.", e);
}
}
String filterTagArg = store.getGlobalStateSystemFilterTag();
FilterHelper filterHelper = new FilterHelper();
List<Service> filteredServiceList = filterHelper.getFilteredServices(filterTagArg, store);
ConflictHelper conflictHelper = new ConflictHelper();
ConflictInfo conflictInfo = conflictHelper.getConflictInfo(filteredServiceList);
req.setAttribute("services", filteredServiceList);
req.setAttribute("conflictInfo", conflictInfo);
req.setAttribute("plans", filterHelper.getFilteredServicePlans(filterTagArg, store));
req.setAttribute("filterTag", filterTagArg);
if (store.getDefaultServicePlanIdAsLong() != null) {
req.setAttribute("defaultServicePlanId", store.getDefaultServicePlanId());
} else {
req.setAttribute("defaultServicePlanId", "");
}
req.setAttribute("httpRespCodeList", HttpStatusCodeStore.getInstance().getCodeEntryList());
RequestDispatcher dispatch = req.getRequestDispatcher("home.jsp");
dispatch.forward(req, resp);
}
}