Java tutorial
/*! * * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * 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 Lesser General Public License for more details. * * * Copyright (c) 2002-2018 Hitachi Vantara. All rights reserved. * */ package org.pentaho.platform.web.servlet; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import org.dom4j.tree.DefaultElement; import org.pentaho.platform.api.engine.IActionParameter; import org.pentaho.platform.api.engine.IActionSequence; import org.pentaho.platform.api.engine.IMessageFormatter; import org.pentaho.platform.api.engine.IParameterProvider; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.engine.IRuntimeContext; import org.pentaho.platform.api.engine.IUserRoleListService; import org.pentaho.platform.api.repository2.unified.RepositoryFilePermission; import org.pentaho.platform.api.util.XmlParseException; import org.pentaho.platform.engine.core.output.SimpleOutputHandler; import org.pentaho.platform.engine.core.solution.ActionInfo; import org.pentaho.platform.engine.core.solution.SimpleParameterProvider; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.ActionSequenceJCRHelper; import org.pentaho.platform.engine.services.SoapHelper; import org.pentaho.platform.engine.services.solution.PentahoEntityResolver; import org.pentaho.platform.uifoundation.chart.ChartDefinition; import org.pentaho.platform.uifoundation.chart.ChartHelper; import org.pentaho.platform.util.messages.LocaleHelper; import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper; import org.pentaho.platform.web.http.request.HttpRequestParameterProvider; import org.pentaho.platform.web.http.request.HttpWebServiceRequestHandler; import org.pentaho.platform.web.http.session.HttpSessionParameterProvider; import org.pentaho.platform.web.servlet.messages.Messages; import org.pentaho.reporting.libraries.base.util.StringUtils; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Servlet Class * * web.servlet name="ViewAction" display-name="Name for ViewAction" description="Description for ViewAction" * web.servlet-mapping url-pattern="/ViewAction" web.servlet-init-param name="A parameter" value="A value" */ public class HttpWebService extends ServletBase { /** * */ private static final long serialVersionUID = -2011812808062152707L; private static final Log logger = LogFactory.getLog(HttpWebService.class); @Override public Log getLogger() { return HttpWebService.logger; } /** * */ public HttpWebService() { super(); } public String getPayloadAsString(final HttpServletRequest request) throws IOException { BufferedReader reader = request.getReader(); if (reader != null) { return IOUtils.toString(reader); } else { return null; } } public void doGetFixMe(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { // // System Entry/Exit point handled by the doGet method. // try { String actionPath = request.getParameter("path"); //$NON-NLS-1$ String solutionName = actionPath.substring(0, actionPath.indexOf('/', 1)); String actionName = actionPath.substring(actionPath.lastIndexOf('/')); String actionSeqPath = ActionInfo.buildSolutionPath(solutionName, actionPath, actionName); String component = request.getParameter("component"); //$NON-NLS-1$ String content = getPayloadAsString(request); IParameterProvider parameterProvider = null; HashMap parameters = new HashMap(); if ((content != null) && (content.length() > 0)) { Document doc = XmlDom4JHelper.getDocFromString(content, new PentahoEntityResolver()); List parameterNodes = doc.selectNodes("//SOAP-ENV:Body/*/*"); //$NON-NLS-1$ for (int i = 0; i < parameterNodes.size(); i++) { Node parameterNode = (Node) parameterNodes.get(i); String parameterName = parameterNode.getName(); String parameterValue = parameterNode.getText(); // String type = parameterNode.selectSingleNode( "@type" ); // if( "xml-data".equalsIgnoreCase( ) ) if ("action".equals(parameterName)) { //$NON-NLS-1$ ActionInfo info = ActionInfo.parseActionString(parameterValue); solutionName = info.getSolutionName(); actionPath = info.getPath(); actionName = info.getActionName(); } else if ("component".equals(parameterName)) { //$NON-NLS-1$ component = parameterValue; } else { parameters.put(parameterName, parameterValue); } } parameterProvider = new SimpleParameterProvider(parameters); } else { parameterProvider = new HttpRequestParameterProvider(request); } response.setContentType("text/xml"); //$NON-NLS-1$ response.setCharacterEncoding(LocaleHelper.getSystemEncoding()); // PentahoHttpSession userSession = new PentahoHttpSession( // request.getRemoteUser(), request.getSession(), // request.getLocale() ); IPentahoSession userSession = getPentahoSession(request); String instanceId = request.getParameter("instance-id"); //$NON-NLS-1$ String processId = this.getClass().getName(); OutputStream contentStream = new ByteArrayOutputStream(); SimpleOutputHandler outputHandler = new SimpleOutputHandler(contentStream, false); // send the header of the message to prevent time-outs while we are // working OutputStream outputStream = response.getOutputStream(); if ((component == null) || "action".equals(component)) { //$NON-NLS-1$ // assume this is an action sequence execute HttpWebServiceRequestHandler requestHandler = new HttpWebServiceRequestHandler(userSession, null, outputHandler, parameterProvider, null); requestHandler.setParameterProvider(IParameterProvider.SCOPE_SESSION, new HttpSessionParameterProvider(userSession)); requestHandler.setInstanceId(instanceId); requestHandler.setProcessId(processId); requestHandler.setActionPath(actionSeqPath); if (ServletBase.debug) { debug(Messages.getInstance().getString("HttpWebService.DEBUG_WEB_SERVICE_START")); //$NON-NLS-1$ } IRuntimeContext runtime = null; try { runtime = requestHandler.handleActionRequest(0, 0); Document responseDoc = SoapHelper.createSoapResponseDocument(runtime, outputHandler, contentStream, requestHandler.getMessages()); XmlDom4JHelper.saveDom(responseDoc, outputStream, PentahoSystem.getSystemSetting("web-service-encoding", "utf-8"), true); } finally { if (runtime != null) { runtime.dispose(); } } } else if ("dial".equals(component)) { //$NON-NLS-1$ doDial(solutionName, actionPath, actionName, parameterProvider, outputStream, userSession); } else if ("chart".equals(component)) { //$NON-NLS-1$ doChart(actionPath, parameterProvider, outputStream, userSession); } else if ("xaction-parameter".equals(component)) { //$NON-NLS-1$ doParameter(solutionName, actionPath, actionName, parameterProvider, outputStream, userSession, response); } } catch (Throwable t) { error(Messages.getInstance().getErrorString("HttpWebService.ERROR_0001_ERROR_DURING_WEB_SERVICE"), t); //$NON-NLS-1$ } if (ServletBase.debug) { debug(Messages.getInstance().getString("HttpWebService.DEBUG_WEB_SERVICE_END")); //$NON-NLS-1$ } } @Override protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } private void doParameter(final String solutionName, final String actionPath, final String actionName, final IParameterProvider parameterProvider, final OutputStream outputStream, final IPentahoSession userSession, final HttpServletResponse response) throws IOException { final IActionSequence actionSequence = new ActionSequenceJCRHelper().getActionSequence( ActionInfo.buildSolutionPath(solutionName, actionPath, actionName), PentahoSystem.loggingLevel, RepositoryFilePermission.READ); if (actionSequence == null) { logger.debug(Messages.getInstance().getString("HttpWebService.ERROR_0002_NOTFOUND", solutionName, actionPath, actionName)); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } final Document document = DocumentHelper.createDocument(); try { final Element parametersElement = document.addElement("parameters"); // noinspection unchecked final Map<String, IActionParameter> params = actionSequence .getInputDefinitionsForParameterProvider(IParameterProvider.SCOPE_REQUEST); for (final Map.Entry<String, IActionParameter> entry : params.entrySet()) { final String paramName = entry.getKey(); final IActionParameter paramDef = entry.getValue(); final String value = paramDef.getStringValue(); final Class type; // yes, the actual type-code uses equals-ignore-case and thus allows the user // to specify type information in a random case. sTrInG is equal to STRING is equal to the value // defined as constant (string) if (IActionParameter.TYPE_LIST.equalsIgnoreCase(paramDef.getType())) { type = String[].class; } else { type = String.class; } final String label = paramDef.getSelectionDisplayName(); final String[] values; if (StringUtils.isEmpty(value)) { values = new String[0]; } else { values = new String[] { value }; } createParameterElement(parametersElement, paramName, type, label, "user", "parameters", values); } // built in parameters: solution, path, action, prompt, instance-id createParameterElement(parametersElement, "solution", String.class, null, "system", "system", new String[] { solutionName }); createParameterElement(parametersElement, "path", String.class, null, "system", "system", new String[] { actionPath }); createParameterElement(parametersElement, "action", String.class, null, "system", "system", new String[] { actionName }); createParameterElement(parametersElement, "prompt", String.class, null, "system", "system", new String[] { "yes", "no" }); createParameterElement(parametersElement, "instance-id", String.class, null, "system", "system", new String[] { parameterProvider.getStringParameter("instance-id", null) }); } catch (Exception e) { logger.warn(Messages.getInstance().getString("HttpWebService.ERROR_0003_UNEXPECTED"), e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } // no close, as far as I know tomcat does not like it that much .. final XMLWriter writer = new XMLWriter(outputStream, OutputFormat.createPrettyPrint()); writer.write(document); writer.flush(); } private Element createParameterElement(final Element parametersElement, final String paramName, final Class type, final String label, final String role, final String group, final String[] values) { final Element parameterElement = parametersElement.addElement("parameter"); parameterElement.addAttribute("name", paramName); parameterElement.addAttribute("type", type.getName()); if (StringUtils.isEmpty(label) == false) { final Element labelAttr = parameterElement.addElement("attribute"); labelAttr.addAttribute("namespace", "http://reporting.pentaho.org/namespaces/engine/parameter-attributes/core"); labelAttr.addAttribute("name", "label"); labelAttr.addAttribute("value", label); } final Element roleAttr = parameterElement.addElement("attribute"); roleAttr.addAttribute("namespace", "http://reporting.pentaho.org/namespaces/engine/parameter-attributes/core"); roleAttr.addAttribute("name", "role"); roleAttr.addAttribute("value", role); final Element paramGroupAttr = parameterElement.addElement("attribute"); paramGroupAttr.addAttribute("namespace", "http://reporting.pentaho.org/namespaces/engine/parameter-attributes/core"); paramGroupAttr.addAttribute("name", "parameter-group"); paramGroupAttr.addAttribute("value", group); final Element paramGroupLabelAttr = parameterElement.addElement("attribute"); paramGroupLabelAttr.addAttribute("namespace", "http://reporting.pentaho.org/namespaces/engine/parameter-attributes/core"); paramGroupLabelAttr.addAttribute("name", "parameter-group-label"); paramGroupLabelAttr.addAttribute("value", lookupParameterGroupLabel(group)); if (values.length > 0) { final Element valuesElement = parameterElement.addElement("values"); for (final String value : values) { final Element valueAttr = valuesElement.addElement("value"); valueAttr.addAttribute("type", String.class.getName()); valueAttr.addAttribute("value", value); valueAttr.addAttribute("selected", String.valueOf(values.length == 1)); } } return parameterElement; } private String lookupParameterGroupLabel(final String group) { if ("system".equals(group)) { return Messages.getInstance().getString("HttpWebService.PARAMETER_GROUP_SYSTEM"); } return Messages.getInstance().getString("HttpWebService.PARAMETER_GROUP_USER"); } @SuppressWarnings("deprecation") protected void doDial(final String solutionName, final String actionPath, final String actionName, final IParameterProvider parameterProvider, final OutputStream outputStream, final IPentahoSession userSession) { ArrayList messages = new ArrayList(); StringBuffer buffer = new StringBuffer(); boolean ok = ChartHelper.doDial(solutionName, actionPath, actionName, parameterProvider, buffer, userSession, messages, this); if (!ok) { PentahoSystem.get(IMessageFormatter.class, userSession).formatErrorMessage("text/html", Messages.getInstance().getString("Widget.ERROR_0001_COULD_NOT_CREATE_WIDGET"), messages, buffer); //$NON-NLS-1$ //$NON-NLS-2$ } try { XmlDom4JHelper.saveDom(SoapHelper.createSoapResponseDocument(buffer.toString()), outputStream, PentahoSystem.getSystemSetting("web-service-encoding", "utf-8"), true); } catch (IOException e) { // not much we can do here... } } protected void doChart(final String actionPath, final IParameterProvider parameterProvider, final OutputStream outputStream, final IPentahoSession userSession) { String chartTypeStr = parameterProvider.getStringParameter("chart-type", ""); //$NON-NLS-1$ //$NON-NLS-2$ if (ChartDefinition.PIE_CHART_STR.equals(chartTypeStr)) { doPieChart(actionPath, parameterProvider, outputStream, userSession); } else { doOtherChart(actionPath, parameterProvider, outputStream, userSession); } } @SuppressWarnings("deprecation") protected void doPieChart(final String actionPath, final IParameterProvider parameterProvider, final OutputStream outputStream, final IPentahoSession userSession) { ArrayList messages = new ArrayList(); StringBuffer buffer = new StringBuffer(); boolean ok = ChartHelper.doPieChart(actionPath, parameterProvider, buffer, userSession, messages, this); if (!ok) { PentahoSystem.get(IMessageFormatter.class, userSession).formatErrorMessage("text/html", Messages.getInstance().getString("Widget.ERROR_0001_COULD_NOT_CREATE_WIDGET"), messages, buffer); //$NON-NLS-1$ //$NON-NLS-2$ } try { XmlDom4JHelper.saveDom(SoapHelper.createSoapResponseDocument(buffer.toString()), outputStream, PentahoSystem.getSystemSetting("web-service-encoding", "utf-8"), true); } catch (IOException e) { // not much we can do here... } } protected void doOtherChart(final String actionPath, final IParameterProvider parameterProvider, final OutputStream outputStream, final IPentahoSession userSession) { ArrayList messages = new ArrayList(); StringBuffer buffer = new StringBuffer(); boolean ok = ChartHelper.doChart(actionPath, parameterProvider, buffer, userSession, messages, this); if (!ok) { PentahoSystem.get(IMessageFormatter.class, userSession).formatErrorMessage("text/html", Messages.getInstance().getString("Widget.ERROR_0001_COULD_NOT_CREATE_WIDGET"), messages, buffer); //$NON-NLS-1$ //$NON-NLS-2$ } try { XmlDom4JHelper.saveDom(SoapHelper.createSoapResponseDocument(buffer.toString()), outputStream, PentahoSystem.getSystemSetting("web-service-encoding", "utf-8"), true); } catch (IOException e) { // not much we can do here... } } // // FIXME: Copied straight from something else - make this nice // /** * <ol> * <li>Make sure this request has required parameters either on query string or in body of post.</li> * <li>Make calls into <code>UserDetailsRoleListService</code> instance for users and roles.</li> * <li>Make static call into <code>PentahoAclEntry</code> for ACLs.</li> * <li>Construct SOAP response.</li> * </ol> */ @Override public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { PentahoSystem.systemEntryPoint(); try { if (!isSecurityDetailsRequest(request)) { if (HttpWebService.logger.isDebugEnabled()) { HttpWebService.logger.debug( Messages.getInstance().getString("HttpWebService.DEBUG_MISSING_ACTION_PARAMETER")); //$NON-NLS-1$ } doGetFixMe(request, response); return; } String responseEncoding = PentahoSystem.getSystemSetting("web-service-encoding", "utf-8"); response.setContentType("text/xml"); //$NON-NLS-1$ response.setCharacterEncoding(responseEncoding); String details = getDetailsParameter(request); if ("users".equalsIgnoreCase(details)) { //$NON-NLS-1$ Document usersDoc = getUsers(); Document aclsDoc = getACLs(); XmlDom4JHelper.saveDom(SoapHelper.createSoapResponseDocument(new Document[] { usersDoc, aclsDoc }), response.getOutputStream(), responseEncoding, true); } else if ("roles".equalsIgnoreCase(details)) { //$NON-NLS-1$ Document rolesDoc = getRoles(); Document aclsDoc = getACLs(); XmlDom4JHelper.saveDom(SoapHelper.createSoapResponseDocument(new Document[] { rolesDoc, aclsDoc }), response.getOutputStream(), responseEncoding, true); } else if ("acls".equalsIgnoreCase(details)) { //$NON-NLS-1$ Document aclsDoc = getACLs(); XmlDom4JHelper.saveDom(SoapHelper.createSoapResponseDocument(aclsDoc), response.getOutputStream(), responseEncoding, true); } else { if (!"all".equalsIgnoreCase(details)) { //$NON-NLS-1$ if (HttpWebService.logger.isWarnEnabled()) { HttpWebService.logger.warn( Messages.getInstance().getString("HttpWebService.WARN_MISSING_DETAILS_PARAMETER")); //$NON-NLS-1$ } } Document usersDoc = getUsers(); Document rolesDoc = getRoles(); Document aclsDoc = getACLs(); XmlDom4JHelper.saveDom( SoapHelper.createSoapResponseDocument(new Document[] { usersDoc, rolesDoc, aclsDoc }), response.getOutputStream(), responseEncoding, true); } } finally { PentahoSystem.systemExitPoint(); } } /** * Returns true if the required parameter is either in the query string or body. */ protected boolean isSecurityDetailsRequest(final HttpServletRequest request) { return hasActionInQueryString(request) || hasActionInBody(request); } /** * Returns parameter named <code>details</code> either from query string or body. This parameter specifies how much * information the caller wants returned. */ protected String getDetailsParameter(final HttpServletRequest request) { // check query string first String details = request.getParameter("details"); //$NON-NLS-1$ if (null != details) { return details; } // now check body String payload; try { payload = getPayloadAsString(request); } catch (IOException e) { if (HttpWebService.logger.isErrorEnabled()) { HttpWebService.logger.error(e); } return null; } if ((null != payload) && (payload.length() > 0)) { Map parameters = getParameterMapFromPayload(payload); Object obj = parameters.get("details"); //$NON-NLS-1$ if (null != obj) { return obj.toString(); } } return null; } /** * Returns true if required parameter is in body of request. */ protected boolean hasActionInBody(final HttpServletRequest request) { String payload; try { payload = getPayloadAsString(request); } catch (IOException e) { if (HttpWebService.logger.isErrorEnabled()) { HttpWebService.logger.error(e); } return false; } if ((null != payload) && (payload.length() > 0)) { Map parameters = getParameterMapFromPayload(payload); Object obj = parameters.get("action"); //$NON-NLS-1$ if ((null != obj) && obj.toString().equalsIgnoreCase("securitydetails")) { //$NON-NLS-1$ return true; } } return false; } /** * Returns true if required parameter named <code>action</code> is in query string. */ protected boolean hasActionInQueryString(final HttpServletRequest request) { String action = request.getParameter("action"); //$NON-NLS-1$ if (("securitydetails").equalsIgnoreCase(action)) { //$NON-NLS-1$ return true; } else { return false; } } protected Map getParameterMapFromPayload(final String xml) { Map parameters = new HashMap(); Document doc = null; try { doc = XmlDom4JHelper.getDocFromString(xml, new PentahoEntityResolver()); } catch (XmlParseException e) { error(Messages.getInstance().getErrorString("HttpWebService.ERROR_0001_ERROR_DURING_WEB_SERVICE"), e); //$NON-NLS-1$ return parameters; } List parameterNodes = doc.selectNodes("//SOAP-ENV:Body/*/*"); //$NON-NLS-1$ for (int i = 0; i < parameterNodes.size(); i++) { Node parameterNode = (Node) parameterNodes.get(i); String parameterName = parameterNode.getName(); String parameterValue = parameterNode.getText(); parameters.put(parameterName, parameterValue); } return parameters; } /** * Returns XML for list of users. */ protected Document getUsers() throws ServletException, IOException { IUserRoleListService service = PentahoSystem.get(IUserRoleListService.class); Element rootElement = new DefaultElement("users"); Document doc = DocumentHelper.createDocument(rootElement); if (service != null) { List users = service.getAllUsers(); for (Iterator usersIterator = users.iterator(); usersIterator.hasNext();) { String username = usersIterator.next().toString(); if ((null != username) && (username.length() > 0)) { rootElement.addElement("user").addCDATA(username); } } } return doc; } /** * Returns XML for list of roles. */ protected Document getRoles() throws ServletException, IOException { IUserRoleListService service = PentahoSystem.get(IUserRoleListService.class); Element rootElement = new DefaultElement("roles"); Document doc = DocumentHelper.createDocument(rootElement); if (service != null) { List roles = service.getAllRoles(); for (Iterator rolesIterator = roles.iterator(); rolesIterator.hasNext();) { String roleName = rolesIterator.next().toString(); if ((null != roleName) && (roleName.length() > 0)) { rootElement.addElement("role").addCDATA(roleName); } } } return doc; } /** * Returns XML for list of ACLs. */ protected Document getACLs() throws ServletException, IOException { Map validPermissionsNameMap = /*PentahoAclEntry.getValidPermissionsNameMap( IPentahoAclEntry.PERMISSIONS_LIST_ALL );*/ new HashMap<String, String>(); Element rootElement = new DefaultElement("acls"); Document doc = DocumentHelper.createDocument(rootElement); if (validPermissionsNameMap != null) { Set aclsKeySet = validPermissionsNameMap.keySet(); for (Iterator aclsIterator = aclsKeySet.iterator(); aclsIterator.hasNext();) { String aclName = aclsIterator.next().toString(); String aclMask = null != validPermissionsNameMap.get(aclName) ? validPermissionsNameMap.get(aclName).toString() : null; if ((null != aclName) && (aclName.length() > 0) && (null != aclMask) && (aclMask.length() > 0)) { Element aclElement = rootElement.addElement("acl"); aclElement.addElement("name").addCDATA(aclName); aclElement.addElement("mask").setText(aclMask); } } } return doc; } }