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("&nbsp;</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