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) 2011-2012 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.xmla.impl;
011
012import mondrian.olap.MondrianServer;
013import mondrian.olap.Util;
014import mondrian.server.RepositoryContentFinder;
015import mondrian.server.UrlRepositoryContentFinder;
016import mondrian.spi.CatalogLocator;
017import mondrian.spi.impl.ServletContextCatalogLocator;
018import mondrian.xmla.XmlaHandler;
019
020import java.io.File;
021import java.net.MalformedURLException;
022import java.net.URL;
023import javax.servlet.*;
024
025/**
026 * Extension to {@link mondrian.xmla.XmlaServlet} that instantiates a
027 * Mondrian engine.
028 *
029 * @author jhyde
030 */
031public class MondrianXmlaServlet extends DefaultXmlaServlet {
032    public static final String DEFAULT_DATASOURCE_FILE = "datasources.xml";
033
034    protected MondrianServer server;
035
036    @Override
037    protected XmlaHandler.ConnectionFactory createConnectionFactory(
038        ServletConfig servletConfig)
039        throws ServletException
040    {
041        if (server == null) {
042            // A derived class can alter how the calalog locator object is
043            // created.
044            CatalogLocator catalogLocator = makeCatalogLocator(servletConfig);
045
046            String dataSources = makeDataSourcesUrl(servletConfig);
047            RepositoryContentFinder contentFinder =
048                makeContentFinder(dataSources);
049            server =
050                MondrianServer.createWithRepository(
051                    contentFinder, catalogLocator);
052        }
053        return (XmlaHandler.ConnectionFactory) server;
054    }
055
056    @Override
057    public void destroy() {
058        super.destroy();
059        if (server != null) {
060            server.shutdown();
061            server = null;
062        }
063    }
064
065    /**
066     * Creates a callback for reading the repository. Derived classes may
067     * override.
068     *
069     * @param dataSources Data sources
070     * @return Callback for reading repository
071     */
072    protected RepositoryContentFinder makeContentFinder(String dataSources) {
073        return new UrlRepositoryContentFinder(dataSources);
074    }
075
076    /**
077     * Make catalog locator.  Derived classes can roll their own.
078     *
079     * @param servletConfig Servlet configuration info
080     * @return Catalog locator
081     */
082    protected CatalogLocator makeCatalogLocator(ServletConfig servletConfig) {
083        ServletContext servletContext = servletConfig.getServletContext();
084        return new ServletContextCatalogLocator(servletContext);
085    }
086
087    /**
088     * Creates the URL where the data sources file is to be found.
089     *
090     * <p>Derived classes can roll their own.
091     *
092     * <p>If there is an initParameter called "DataSourcesConfig"
093     * get its value, replace any "${key}" content with "value" where
094     * "key/value" are System properties, and try to create a URL
095     * instance out of it. If that fails, then assume its a
096     * real filepath and if the file exists then create a URL from it
097     * (but only if the file exists).
098     * If there is no initParameter with that name, then attempt to
099     * find the file called "datasources.xml"  under "WEB-INF/"
100     * and if it exists, use it.
101     *
102     * @param servletConfig Servlet config
103     * @return URL where data sources are to be found
104     */
105    protected String makeDataSourcesUrl(ServletConfig servletConfig)
106    {
107        String paramValue =
108                servletConfig.getInitParameter(PARAM_DATASOURCES_CONFIG);
109        // if false, then do not throw exception if the file/url
110        // can not be found
111        boolean optional =
112            getBooleanInitParameter(
113                servletConfig, PARAM_OPTIONAL_DATASOURCE_CONFIG);
114
115        URL dataSourcesConfigUrl = null;
116        try {
117            if (paramValue == null) {
118                // fallback to default
119                String defaultDS = "WEB-INF/" + DEFAULT_DATASOURCE_FILE;
120                ServletContext servletContext =
121                    servletConfig.getServletContext();
122                File realPath = new File(servletContext.getRealPath(defaultDS));
123                if (realPath.exists()) {
124                    // only if it exists
125                    dataSourcesConfigUrl = realPath.toURL();
126                    return dataSourcesConfigUrl.toString();
127                } else {
128                    return null;
129                }
130            } else if (paramValue.startsWith("inline:")) {
131                return paramValue;
132            } else {
133                paramValue = Util.replaceProperties(
134                    paramValue,
135                    Util.toMap(System.getProperties()));
136                if (LOGGER.isDebugEnabled()) {
137                    LOGGER.debug(
138                        "XmlaServlet.makeDataSources: paramValue="
139                        + paramValue);
140                }
141                // is the parameter a valid URL
142                MalformedURLException mue = null;
143                try {
144                    dataSourcesConfigUrl = new URL(paramValue);
145                } catch (MalformedURLException e) {
146                    // not a valid url
147                    mue = e;
148                }
149                if (dataSourcesConfigUrl == null) {
150                    // see if its a full valid file path
151                    File f = new File(paramValue);
152                    if (f.exists()) {
153                        // yes, a real file path
154                        dataSourcesConfigUrl = f.toURL();
155                    } else if (mue != null) {
156                        // neither url or file,
157                        // is it not optional
158                        if (! optional) {
159                            throw mue;
160                        }
161                    }
162                    return null;
163                }
164                return dataSourcesConfigUrl.toString();
165            }
166        } catch (MalformedURLException mue) {
167            throw Util.newError(mue, "invalid URL path '" + paramValue + "'");
168        }
169    }
170}
171
172// End MondrianXmlaServlet.java