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