001    /*
002    // $Id: //open/mondrian/src/main/mondrian/web/servlet/MDXQueryServlet.java#28 $
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-2008 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/src/main/mondrian/web/servlet/MDXQueryServlet.java#28 $
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("&nbsp;</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    }
247    
248    // End MDXQueryServlet.java