Package mondrian.rolap

Source Code of mondrian.rolap.RolapSchemaPool

/*
// 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) 2001-2005 Julian Hyde and others
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/

package mondrian.rolap;

import mondrian.olap.Util;
import mondrian.resource.MondrianResource;
import mondrian.rolap.aggmatcher.JdbcSchema;
import mondrian.spi.DynamicSchemaProcessor;
import mondrian.util.*;

import org.apache.log4j.Logger;

import java.io.IOException;
import java.lang.ref.*;
import java.lang.reflect.Constructor;
import java.util.*;

import javax.sql.DataSource;

/**
* A collection of schemas, identified by their connection properties
* (catalog name, JDBC URL, and so forth).
*
* <p>To lookup a schema, call
* <code>RolapSchemaPool.{@link #instance}().{@link #get}</code>.</p>
*/
class RolapSchemaPool {
    static final Logger LOGGER = Logger.getLogger(RolapSchemaPool.class);

    private static final RolapSchemaPool INSTANCE = new RolapSchemaPool();

    private final Map<SchemaKey, ExpiringReference<RolapSchema>>
        mapKeyToSchema =
            new HashMap<SchemaKey, ExpiringReference<RolapSchema>>();

    // REVIEW: This map is now considered unsafe. If two schemas have identical
    // metadata but a different underlying database connection, we should not
    // share a cache. Since SchemaContentKey is now a hash of the schema
    // definition, this field can probably be removed.
    private final Map<ByteString, ExpiringReference<RolapSchema>>
        mapMd5ToSchema =
            new HashMap<ByteString, ExpiringReference<RolapSchema>>();

    private RolapSchemaPool() {
    }

    static RolapSchemaPool instance() {
        return INSTANCE;
    }

    synchronized RolapSchema get(
        final String catalogUrl,
        final String connectionKey,
        final String jdbcUser,
        final String dataSourceStr,
        final Util.PropertyList connectInfo)
    {
        return get(
            catalogUrl,
            connectionKey,
            jdbcUser,
            dataSourceStr,
            null,
            connectInfo);
    }

    synchronized RolapSchema get(
        final String catalogUrl,
        final DataSource dataSource,
        final Util.PropertyList connectInfo)
    {
        return get(
            catalogUrl,
            null,
            null,
            null,
            dataSource,
            connectInfo);
    }

    private RolapSchema get(
        final String catalogUrl,
        final String connectionKey,
        final String jdbcUser,
        final String dataSourceStr,
        final DataSource dataSource,
        final Util.PropertyList connectInfo)
    {
        final String connectionUuidStr = connectInfo.get(
            RolapConnectionProperties.JdbcConnectionUuid.name());
        final boolean useSchemaPool =
            Boolean.parseBoolean(
                connectInfo.get(
                    RolapConnectionProperties.UseSchemaPool.name(),
                    "true"));
        final String pinSchemaTimeout =
            connectInfo.get(
                RolapConnectionProperties.PinSchemaTimeout.name(),
                "-1s");
        final boolean useContentChecksum =
            Boolean.parseBoolean(
                connectInfo.get(
                    RolapConnectionProperties.UseContentChecksum.name()));
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(
                "get: catalog=" + catalogUrl
                + ", connectionKey=" + connectionKey
                + ", jdbcUser=" + jdbcUser
                + ", dataSourceStr=" + dataSourceStr
                + ", dataSource=" + dataSource
                + ", jdbcConnectionUuid=" + connectionUuidStr
                + ", useSchemaPool=" + useSchemaPool
                + ", useContentChecksum=" + useContentChecksum
                + ", map-size=" + mapKeyToSchema.size()
                + ", md5-map-size=" + mapMd5ToSchema.size());
        }
        final ConnectionKey connectionKey1 =
            ConnectionKey.create(
                connectionUuidStr,
                dataSource,
                catalogUrl,
                connectionKey,
                jdbcUser,
                dataSourceStr);

        final String catalogStr = getSchemaContent(connectInfo, catalogUrl);
        final SchemaContentKey schemaContentKey =
            SchemaContentKey.create(connectInfo, catalogUrl, catalogStr);
        final SchemaKey key =
            new SchemaKey(
                schemaContentKey,
                connectionKey1);

        // Use the schema pool unless "UseSchemaPool" is explicitly false.
        RolapSchema schema = null;
        if (!useSchemaPool) {
            schema =
                new RolapSchema(
                    key,
                    null,
                    catalogUrl,
                    catalogStr,
                    connectInfo,
                    dataSource);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug(
                    "create (no pool): schema-name=" + schema.getName()
                    + ", schema-id="
                    + Integer.toHexString(System.identityHashCode(schema)));
            }
            return schema;
        }

        if (useContentChecksum) {
            final ByteString md5Bytes =
                new ByteString(Util.digestMd5(catalogStr));
            final ExpiringReference<RolapSchema> ref =
                mapMd5ToSchema.get(md5Bytes);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug(
                    "get(key=" + key
                    + ") returned " + toString(ref));
            }

            if (ref != null) {
                schema = ref.get(pinSchemaTimeout);
                if (schema == null) {
                    // clear out the reference since schema is null
                    mapKeyToSchema.remove(key);
                    mapMd5ToSchema.remove(md5Bytes);
                }
            }

            if (schema == null) {
                schema = new RolapSchema(
                    key,
                    md5Bytes,
                    catalogUrl,
                    catalogStr,
                    connectInfo,
                    dataSource);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(
                        "create: schema-name=" + schema.getName()
                        + ", schema-id=" + System.identityHashCode(schema));
                }
                putSchema(schema, md5Bytes, pinSchemaTimeout);
            }
            return schema;
        }

        ExpiringReference<RolapSchema> ref = mapKeyToSchema.get(key);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(
                "get(key=" + key
                + ") returned " + toString(ref));
        }
        if (ref != null) {
            schema = ref.get(pinSchemaTimeout);
            if (schema == null) {
                mapKeyToSchema.remove(key);
            }
        }

        if (schema == null) {
            schema = new RolapSchema(
                key,
                null,
                catalogUrl,
                catalogStr,
                connectInfo,
                dataSource);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("create: " + schema);
            }
            putSchema(schema, null, pinSchemaTimeout);
        }

        return schema;
    }

    private void putSchema(
        final RolapSchema schema,
        final ByteString md5Bytes,
        final String pinTimeout)
    {
        final ExpiringReference<RolapSchema> reference =
            new ExpiringReference<RolapSchema>(
                schema, pinTimeout);
        if (md5Bytes != null) {
            mapMd5ToSchema.put(md5Bytes, reference);
        }
        mapKeyToSchema.put(schema.key, reference);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(
                "put: schema=" + schema
                + ", key=" + schema.key
                + ", checksum=" + md5Bytes
                + ", map-size=" + mapKeyToSchema.size()
                + ", md5-map-size=" + mapMd5ToSchema.size());
        }
    }

    private static String getSchemaContent(
        final Util.PropertyList connectInfo,
        final String catalogUrl)
    {
        // We will return the first of the following:
        //  1. CatalogContent property if set
        //  2. DynamicSchemaProcessor#processSchema if set
        //  3. Util.readVirtualFileAsString(catalogUrl)

        String catalogStr = connectInfo.get(
            RolapConnectionProperties.CatalogContent.name());

        if (Util.isEmpty(catalogStr)) {
            if (Util.isEmpty(catalogUrl)) {
                throw MondrianResource.instance()
                    .ConnectStringMandatoryProperties.ex(
                        RolapConnectionProperties.Catalog.name(),
                        RolapConnectionProperties.CatalogContent.name());
            }
            // check for a DynamicSchemaProcessor
            String dynProcName = connectInfo.get(
                RolapConnectionProperties.DynamicSchemaProcessor.name());
            if (!Util.isEmpty(dynProcName)) {
                catalogStr =
                    processDynamicSchema(
                        dynProcName, catalogUrl, connectInfo);
            }

            if (Util.isEmpty(catalogStr)) {
                // read schema from file
                try {
                    catalogStr = Util.readVirtualFileAsString(catalogUrl);
                } catch (IOException e) {
                    throw Util.newError(
                        e,
                        "loading schema from url " + catalogUrl);
                }
            }
        }

        return catalogStr;
    }

    private static String processDynamicSchema(
        final String dynProcName,
        final String catalogUrl,
        final Util.PropertyList connectInfo)
    {
        if (RolapSchema.LOGGER.isDebugEnabled()) {
            RolapSchema.LOGGER.debug(
                "Pool.get: create schema \"" + catalogUrl
                + "\" using dynamic processor");
        }
        try {
            final DynamicSchemaProcessor dynProc =
                ClassResolver.INSTANCE.instantiateSafe(dynProcName);
            return dynProc.processSchema(catalogUrl, connectInfo);
        } catch (Exception e) {
            throw Util.newError(
                e,
                "loading DynamicSchemaProcessor " + dynProcName);
        }
    }

    synchronized void remove(
        final String catalogUrl,
        final String connectionKey,
        final String jdbcUser,
        final String dataSourceStr)
    {
        final SchemaContentKey schemaContentKey =
            SchemaContentKey.create(
                new Util.PropertyList(),
                catalogUrl,
                null);
        final ConnectionKey connectionUuid =
            ConnectionKey.create(
                null,
                null,
                catalogUrl,
                connectionKey,
                jdbcUser,
                dataSourceStr);
        final SchemaKey key =
            new SchemaKey(schemaContentKey, connectionUuid);
        if (RolapSchema.LOGGER.isDebugEnabled()) {
            RolapSchema.LOGGER.debug(
                "Pool.remove: schema \"" + catalogUrl
                + "\" and datasource string \"" + dataSourceStr + "\"");
        }
        remove(key);
    }

    synchronized void remove(
        final String catalogUrl,
        final DataSource dataSource)
    {
        final SchemaContentKey schemaContentKey =
            SchemaContentKey.create(
                new Util.PropertyList(),
                catalogUrl,
                null);
        final ConnectionKey connectionKey =
            ConnectionKey.create(
                null,
                dataSource,
                catalogUrl,
                null,
                null,
                null);
        final SchemaKey key =
            new SchemaKey(schemaContentKey, connectionKey);
        if (RolapSchema.LOGGER.isDebugEnabled()) {
            RolapSchema.LOGGER.debug(
                "Pool.remove: schema \"" + catalogUrl
                + "\" and datasource object");
        }
        remove(key);
    }

    synchronized void remove(RolapSchema schema) {
        if (schema != null) {
            if (RolapSchema.LOGGER.isDebugEnabled()) {
                RolapSchema.LOGGER.debug(
                    "Pool.remove: schema \"" + schema.getName()
                    + "\" and datasource object");
            }
            remove(schema.key);
        }
    }

    private void remove(SchemaKey key) {
        Reference<RolapSchema> ref = mapKeyToSchema.get(key);
        if (ref != null) {
            RolapSchema schema = ref.get();
            if (schema != null) {
                mapMd5ToSchema.remove(schema.getChecksum());
                schema.finalCleanUp();
            }
        }
        mapKeyToSchema.remove(key);
    }

    synchronized void clear() {
        if (RolapSchema.LOGGER.isDebugEnabled()) {
            RolapSchema.LOGGER.debug("Pool.clear: clearing all RolapSchemas");
        }

        for (Reference<RolapSchema> ref : mapKeyToSchema.values()) {
            if (ref != null) {
                RolapSchema schema = ref.get();
                if (schema != null) {
                    schema.finalCleanUp();
                }
            }
        }
        mapKeyToSchema.clear();
        mapMd5ToSchema.clear();
        JdbcSchema.clearAllDBs();
    }

    /**
     * Returns a list of schemas in this pool.
     *
     * @return List of schemas in this pool
     */
    synchronized List<RolapSchema> getRolapSchemas() {
        List<RolapSchema> list = new ArrayList<RolapSchema>();
        for (RolapSchema schema
            : Util.GcIterator.over(mapKeyToSchema.values()))
        {
            list.add(schema);
        }
        return list;
    }

    synchronized boolean contains(RolapSchema rolapSchema) {
        return mapKeyToSchema.containsKey(rolapSchema.key);
    }

    private static <T> String toString(Reference<T> ref) {
        if (ref == null) {
            return "null";
        } else {
            T t = ref.get();
            if (t == null) {
                return "ref(null)";
            } else {
                return "ref(" + t
                    + ", id=" + Integer.toHexString(System.identityHashCode(t))
                    + ")";
            }
        }
    }
}

// End RolapSchemaPool.java
TOP

Related Classes of mondrian.rolap.RolapSchemaPool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.