001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2002-2005 Julian Hyde 008// Copyright (C) 2005-2009 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.web.servlet; 012 013import mondrian.olap.*; 014import mondrian.spi.CatalogLocator; 015import mondrian.spi.impl.ServletContextCatalogLocator; 016import mondrian.web.taglib.ResultCache; 017 018import org.eigenbase.xom.StringEscaper; 019 020import java.io.IOException; 021import java.util.Enumeration; 022import java.util.List; 023import javax.servlet.ServletConfig; 024import javax.servlet.ServletException; 025import javax.servlet.http.*; 026 027/** 028 * <code>MdxQueryServlet</code> is a servlet which receives MDX queries, 029 * executes them, and formats the results in an HTML table. 030 * 031 * @author Sean McCullough 032 * @since 13 February, 2002 033 */ 034public class MdxQueryServlet extends HttpServlet { 035 private String connectString; 036 private CatalogLocator locator; 037 038 /** 039 * Initializes the servlet. 040 */ 041 public void init(ServletConfig config) throws ServletException { 042 super.init(config); 043 connectString = config.getInitParameter("connectString"); 044 Enumeration initParameterNames = config.getInitParameterNames(); 045 while (initParameterNames.hasMoreElements()) { 046 String name = (String) initParameterNames.nextElement(); 047 String value = config.getInitParameter(name); 048 MondrianProperties.instance().setProperty(name, value); 049 } 050 locator = new ServletContextCatalogLocator(config.getServletContext()); 051 } 052 053 /** 054 * Destroys the servlet. 055 */ 056 public void destroy() { 057 } 058 059 /** 060 * Processes requests for both HTTP <code>GET</code> and <code>POST</code> 061 * methods. 062 * 063 * @param request servlet request 064 * @param response servlet response 065 */ 066 protected void processRequest( 067 HttpServletRequest request, HttpServletResponse response) 068 throws ServletException, java.io.IOException 069 { 070 String queryName = request.getParameter("query"); 071 request.setAttribute("query", queryName); 072 if (queryName != null) { 073 processTransform(request, response); 074 return; 075 } 076 String queryString = request.getParameter("queryString"); 077 request.setAttribute("queryString", queryString); 078 mondrian.olap.Connection mdxConnection = null; 079 StringBuilder html = new StringBuilder(); 080 081 // execute the query 082 try { 083 mdxConnection = DriverManager.getConnection(connectString, locator); 084 Query q = mdxConnection.parseQuery(queryString); 085 Result result = mdxConnection.execute(q); 086 List<Position> slicers = result.getSlicerAxis().getPositions(); 087 html.append("<table class='resulttable' cellspacing=1 border=0>"); 088 html.append(Util.nl); 089 090 List<Position> columns = result.getAxes()[0].getPositions(); 091 List<Position> rows = null; 092 if (result.getAxes().length == 2) { 093 rows = result.getAxes()[1].getPositions(); 094 } 095 int columnWidth = columns.get(0).size(); 096 int rowWidth = 0; 097 if (result.getAxes().length == 2) { 098 rowWidth = result.getAxes()[1].getPositions().get(0).size(); 099 } 100 for (int j = 0; j < columnWidth; j++) { 101 html.append("<tr>"); 102 103 // if it has more than 1 dimension 104 if (j == 0 && result.getAxes().length > 1) { 105 // Print the top-left cell, and fill it with slicer members. 106 html.append("<td nowrap class='slicer' rowspan='") 107 .append(columnWidth) 108 .append("' colspan='") 109 .append(rowWidth) 110 .append("'>"); 111 for (Position position : slicers) { 112 int k = 0; 113 for (Member member : position) { 114 if (k > 0) { 115 html.append("<br/>"); 116 } 117 html.append(member.getUniqueName()); 118 k++; 119 } 120 } 121 html.append(" </td>").append(Util.nl); 122 } 123 124 // Print the column headings. 125 for (int i = 0; i < columns.size(); i++) { 126 Position position = columns.get(i); 127 //Member member = columns[i].getMember(j); 128 Member member = position.get(j); 129 int width = 1; 130 while ((i + 1) < columns.size() 131 && columns.get(i + 1).get(j) == member) 132 { 133 i++; 134 width++; 135 } 136 html.append("<td nowrap class='columnheading' colspan='") 137 .append(width).append("'>") 138 .append(member.getUniqueName()).append("</td>"); 139 } 140 html.append("</tr>").append(Util.nl); 141 } 142 //if is two axes, show 143 if (result.getAxes().length > 1) { 144 for (int i = 0; i < rows.size(); i++) { 145 html.append("<tr>"); 146 final Position row = rows.get(i); 147 for (Member member : row) { 148 html.append("<td nowrap class='rowheading'>") 149 .append(member.getUniqueName()) 150 .append("</td>"); 151 } 152 for (int j = 0; j < columns.size(); j++) { 153 showCell(html, result.getCell(new int[] {j, i})); 154 } 155 html.append("</tr>"); 156 } 157 } else { 158 html.append("<tr>"); 159 for (int i = 0; i < columns.size(); i++) { 160 showCell(html, result.getCell(new int[] {i})); 161 } 162 html.append("</tr>"); 163 } 164 html.append("</table>"); 165 } catch (Throwable e) { 166 final String[] strings = Util.convertStackToString(e); 167 html.append("Error:<pre><blockquote>"); 168 for (String string : strings) { 169 html.append(StringEscaper.htmlEscaper.escapeString(string)); 170 } 171 html.append("</blockquote></pre>"); 172 } finally { 173 if (mdxConnection != null) { 174 mdxConnection.close(); 175 } 176 } 177 178 request.setAttribute("result", html.toString()); 179 response.setHeader("Content-Type", "text/html"); 180 getServletContext().getRequestDispatcher("/adhoc.jsp").include( 181 request, response); 182 } 183 184 private void showCell(StringBuilder out, Cell cell) { 185 out.append("<td class='cell'>") 186 .append(cell.getFormattedValue()) 187 .append("</td>"); 188 } 189 190 private void processTransform( 191 HttpServletRequest request, HttpServletResponse response) 192 throws ServletException, IOException 193 { 194 String queryName = request.getParameter("query"); 195 ResultCache rc = 196 ResultCache.getInstance( 197 request.getSession(), getServletContext(), queryName); 198 Query query = rc.getQuery(); 199 query = query.clone(); 200 rc.setDirty(); 201 String operation = request.getParameter("operation"); 202 if (operation.equals("expand")) { 203 String memberName = request.getParameter("member"); 204 boolean fail = true; 205 Member member = query.getSchemaReader(true).getMemberByUniqueName( 206 Util.parseIdentifier(memberName), fail); 207 if (true) { 208 throw new UnsupportedOperationException( 209 "query.toggleDrillState(member) has been de-supported"); 210 } 211 } else { 212 throw Util.newInternal("unkown operation '" + operation + "'"); 213 } 214 rc.setQuery(query); 215 String redirect = request.getParameter("redirect"); 216 if (redirect == null) { 217 redirect = "/adhoc.jsp"; 218 } 219 response.setHeader("Content-Type", "text/html"); 220 getServletContext().getRequestDispatcher(redirect).include( 221 request, response); 222 } 223 224 /** 225 * Handles the HTTP <code>GET</code> method. 226 * 227 * @param request servlet request 228 * @param response servlet response 229 */ 230 protected void doGet( 231 HttpServletRequest request, HttpServletResponse response) 232 throws ServletException, java.io.IOException 233 { 234 processRequest(request, response); 235 } 236 237 /** 238 * Handles the HTTP <code>POST</code> method. 239 * 240 * @param request servlet request 241 * @param response servlet response 242 */ 243 protected void doPost( 244 HttpServletRequest request, HttpServletResponse response) 245 throws ServletException, java.io.IOException 246 { 247 processRequest(request, response); 248 } 249 250 /** 251 * Returns a short description of the servlet. 252 */ 253 public String getServletInfo() { 254 return "Process an MDX query and return the result formatted as an " 255 + "HTML table"; 256 } 257 258} 259 260// End MdxQueryServlet.java