/*
* This software is subject to the terms of the Eclipse Public License v1.0
* Agreement, available at the following URL:
* http://www.eclipse.org/legal/epl-v10.html.
* You must accept the terms of that agreement to use this software.
*
* Copyright (c) 2002-2013 Pentaho Corporation..  All rights reserved.
*/

package mondrian.xmla.impl;

import mondrian.olap.MondrianServer;
import mondrian.olap.Util;
import mondrian.server.RepositoryContentFinder;
import mondrian.server.UrlRepositoryContentFinder;
import mondrian.spi.CatalogLocator;
import mondrian.spi.impl.ServletContextCatalogLocator;
import mondrian.xmla.XmlaHandler;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import javax.servlet.*;

/**
 * Extension to {@link mondrian.xmla.XmlaServlet} that instantiates a
 * Mondrian engine.
 *
 * @author jhyde
 */
public class MondrianXmlaServlet extends DefaultXmlaServlet {
    public static final String DEFAULT_DATASOURCE_FILE = "datasources.xml";

    protected MondrianServer server;

    @Override
    protected XmlaHandler.ConnectionFactory createConnectionFactory(
        ServletConfig servletConfig)
        throws ServletException
    {
        if (server == null) {
            // A derived class can alter how the calalog locator object is
            // created.
            CatalogLocator catalogLocator = makeCatalogLocator(servletConfig);

            String dataSources = makeDataSourcesUrl(servletConfig);
            RepositoryContentFinder contentFinder =
                makeContentFinder(dataSources);
            server =
                MondrianServer.createWithRepository(
                    contentFinder, catalogLocator);
        }
        return (XmlaHandler.ConnectionFactory) server;
    }

    @Override
    public void destroy() {
        super.destroy();
        if (server != null) {
            server.shutdown();
            server = null;
        }
    }

    /**
     * Creates a callback for reading the repository. Derived classes may
     * override.
     *
     * @param dataSources Data sources
     * @return Callback for reading repository
     */
    protected RepositoryContentFinder makeContentFinder(String dataSources) {
        return new UrlRepositoryContentFinder(dataSources);
    }

    /**
     * Make catalog locator.  Derived classes can roll their own.
     *
     * @param servletConfig Servlet configuration info
     * @return Catalog locator
     */
    protected CatalogLocator makeCatalogLocator(ServletConfig servletConfig) {
        ServletContext servletContext = servletConfig.getServletContext();
        return new ServletContextCatalogLocator(servletContext);
    }

    /**
     * Creates the URL where the data sources file is to be found.
     *
     * <p>Derived classes can roll their own.
     *
     * <p>If there is an initParameter called "DataSourcesConfig"
     * get its value, replace any "${key}" content with "value" where
     * "key/value" are System properties, and try to create a URL
     * instance out of it. If that fails, then assume its a
     * real filepath and if the file exists then create a URL from it
     * (but only if the file exists).
     * If there is no initParameter with that name, then attempt to
     * find the file called "datasources.xml"  under "WEB-INF/"
     * and if it exists, use it.
     *
     * @param servletConfig Servlet config
     * @return URL where data sources are to be found
     */
    protected String makeDataSourcesUrl(ServletConfig servletConfig)
    {
        String paramValue =
                servletConfig.getInitParameter(PARAM_DATASOURCES_CONFIG);
        // if false, then do not throw exception if the file/url
        // can not be found
        boolean optional =
            getBooleanInitParameter(
                servletConfig, PARAM_OPTIONAL_DATASOURCE_CONFIG);

        URL dataSourcesConfigUrl = null;
        try {
            if (paramValue == null) {
                // fallback to default
                String defaultDS = "WEB-INF/" + DEFAULT_DATASOURCE_FILE;
                ServletContext servletContext =
                    servletConfig.getServletContext();
                File realPath = new File(servletContext.getRealPath(defaultDS));
                if (realPath.exists()) {
                    // only if it exists
                    dataSourcesConfigUrl = realPath.toURL();
                    return dataSourcesConfigUrl.toString();
                } else {
                    return null;
                }
            } else if (paramValue.startsWith("inline:")) {
                return paramValue;
            } else {
                paramValue = Util.replaceProperties(
                    paramValue,
                    Util.toMap(System.getProperties()));
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(
                        "XmlaServlet.makeDataSources: paramValue="
                        + paramValue);
                }
                // is the parameter a valid URL
                MalformedURLException mue = null;
                try {
                    dataSourcesConfigUrl = new URL(paramValue);
                } catch (MalformedURLException e) {
                    // not a valid url
                    mue = e;
                }
                if (dataSourcesConfigUrl == null) {
                    // see if its a full valid file path
                    File f = new File(paramValue);
                    if (f.exists()) {
                        // yes, a real file path
                        dataSourcesConfigUrl = f.toURL();
                    } else if (mue != null) {
                        // neither url or file,
                        // is it not optional
                        if (! optional) {
                            throw mue;
                        }
                    }
                    return null;
                }
                return dataSourcesConfigUrl.toString();
            }
        } catch (MalformedURLException mue) {
            throw Util.newError(mue, "invalid URL path '" + paramValue + "'");
        }
    }
}

// End MondrianXmlaServlet.java
