rolapschema.java

来自「数据仓库展示程序」· Java 代码 · 共 1,346 行 · 第 1/4 页

JAVA
1,346
字号
        } catch (Exception e) {
            throw MondrianResource.instance().NamedSetHasBadFormula.ex(
                    xmlNamedSet.name, e);
        }
        final Formula formula = new Formula(
                new String[] {xmlNamedSet.name},
                exp);
        return formula.getNamedSet();
    }

    private Role createRole(MondrianDef.Role xmlRole) {
        Role role = new Role();
        for (int i = 0; i < xmlRole.schemaGrants.length; i++) {
            MondrianDef.SchemaGrant schemaGrant = xmlRole.schemaGrants[i];
            role.grant(this, getAccess(schemaGrant.access, schemaAllowed));
            for (int j = 0; j < schemaGrant.cubeGrants.length; j++) {
                MondrianDef.CubeGrant cubeGrant = schemaGrant.cubeGrants[j];
                Cube cube = lookupCube(cubeGrant.cube);
                if (cube == null) {
                    throw Util.newError("Unknown cube '" + cube + "'");
                }
                role.grant(cube, getAccess(cubeGrant.access, cubeAllowed));
                final SchemaReader schemaReader = cube.getSchemaReader(null);
                for (int k = 0; k < cubeGrant.dimensionGrants.length; k++) {
                    MondrianDef.DimensionGrant dimensionGrant =
                        cubeGrant.dimensionGrants[k];
                    Dimension dimension = (Dimension)
                        schemaReader.lookupCompound(
                            cube, Util.explode(dimensionGrant.dimension), true,
                            Category.Dimension);
                    role.grant(dimension,
                        getAccess(dimensionGrant.access, dimensionAllowed));
                }
                for (int k = 0; k < cubeGrant.hierarchyGrants.length; k++) {
                    MondrianDef.HierarchyGrant hierarchyGrant =
                        cubeGrant.hierarchyGrants[k];
                    Hierarchy hierarchy = (Hierarchy)
                        schemaReader.lookupCompound(
                            cube, Util.explode(hierarchyGrant.hierarchy), true,
                            Category.Hierarchy);
                    final int hierarchyAccess =
                        getAccess(hierarchyGrant.access, hierarchyAllowed);
                    Level topLevel = null;
                    if (hierarchyGrant.topLevel != null) {
                        if (hierarchyAccess != Access.CUSTOM) {
                            throw Util.newError("You may only specify 'topLevel' if access='custom'");
                        }
                        topLevel = (Level) schemaReader.lookupCompound(
                            cube, Util.explode(hierarchyGrant.topLevel), true,
                            Category.Level);
                    }
                    Level bottomLevel = null;
                    if (hierarchyGrant.bottomLevel != null) {
                        if (hierarchyAccess != Access.CUSTOM) {
                            throw Util.newError("You may only specify 'bottomLevel' if access='custom'");
                        }
                        bottomLevel = (Level) schemaReader.lookupCompound(
                            cube, Util.explode(hierarchyGrant.bottomLevel),
                            true, Category.Level);
                    }
                    role.grant(hierarchy, hierarchyAccess, topLevel, bottomLevel);
                    for (int m = 0; m < hierarchyGrant.memberGrants.length; m++) {
                        if (hierarchyAccess != Access.CUSTOM) {
                            throw Util.newError("You may only specify <MemberGrant> if <Hierarchy> has access='custom'");
                        }
                        MondrianDef.MemberGrant memberGrant = hierarchyGrant.memberGrants[m];
                        Member member = schemaReader.getMemberByUniqueName(Util.explode(memberGrant.member),true);
                        if (member.getHierarchy() != hierarchy) {
                            throw Util.newError("Member '" + member + "' is not in hierarchy '" + hierarchy + "'");
                        }
                        role.grant(member, getAccess(memberGrant.access, memberAllowed));
                    }
                }
            }
        }
        role.makeImmutable();
        return role;
    }

    private int getAccess(String accessString, int[] allowed) {
        final int access = Access.instance().getOrdinal(accessString);
        for (int i = 0; i < allowed.length; i++) {
            if (access == allowed[i]) {
                return access; // value is ok
            }
        }
        throw Util.newError("Bad value access='" + accessString + "'");
    }

    public Dimension createDimension(Cube cube, String xml) {
        MondrianDef.CubeDimension xmlDimension = null;
        try {
            final Parser xmlParser = XOMUtil.createDefaultParser();
            final DOMWrapper def = xmlParser.parse(xml);
            final String tagName = def.getTagName();
            if (tagName.equals("Dimension")) {
                xmlDimension = new MondrianDef.Dimension(def);
            } else if (tagName.equals("DimensionUsage")) {
                xmlDimension = new MondrianDef.DimensionUsage(def);
            } else {
                throw new XOMException("Got <" + tagName +
                        "> when expecting <Dimension> or <DimensionUsage>");
            }
        } catch (XOMException e) {
            throw Util.newError(e, "Error while adding dimension to cube '" +
                    cube + "' from XML [" + xml + "]");
        }
        return ((RolapCube) cube).createDimension(xmlDimension);
    }

    public Cube createCube(String xml) {
        MondrianDef.Cube xmlDimension;
        try {
            final Parser xmlParser = XOMUtil.createDefaultParser();
            final DOMWrapper def = xmlParser.parse(xml);
            final String tagName = def.getTagName();
            if (tagName.equals("Cube")) {
                xmlDimension = new MondrianDef.Cube(def);
            } else {
                throw new XOMException("Got <" + tagName +
                    "> when expecting <Cube>");
            }
        } catch (XOMException e) {
            throw Util.newError(e, "Error while creating cube from XML [" +
                xml + "]");
        }
        // Create empty XML schema, to keep the method happy. This is okay,
        // because there are no forward-references to resolve.
        final MondrianDef.Schema xmlSchema = new MondrianDef.Schema();
        RolapCube cube = new RolapCube(this, xmlSchema, xmlDimension);
        return cube;
    }

    /**
     * A collection of schemas, identified by their connection properties
     * (catalog name, JDBC URL, and so forth).
     *
     * <p>To lookup a schema, call <code>Pool.instance().{@link #get(String, DataSource, Util.PropertyList)}</code>.
     */
    static class Pool {
        private static MessageDigest md = null;
        static {
            try {
                md = MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }

        private static Pool pool = new Pool();

        private Map mapUrlToSchema = new HashMap();


        private Pool() {
        }

        static Pool instance() {
            return pool;
        }

        /**
         * Read a Reader until EOF and return as String.
         * Note: this ought to be in a Utility class.
         *
         * @param rdr  Reader to read.
         * @param bufferSize size of buffer to allocate for reading.
         * @return content of Reader as String or null if Reader was empty.
         * @throws IOException
         */
        public static String readFully(final Reader rdr, final int bufferSize)
                     throws IOException {

            if (bufferSize <= 0) {
                throw new IllegalArgumentException(
                            "Buffer size must be greater than 0");
            }

            final char[] buffer = new char[bufferSize];
            final StringBuffer buf = new StringBuffer(bufferSize);

            int len = rdr.read(buffer);
            while (len != -1) {
                buf.append(buffer, 0, len);
                len = rdr.read(buffer);
            }

            final String s = buf.toString();
            return (s.length() == 0) ? null : s;
        }

        /**
         * Create an MD5 hash of String.
         * Note: this ought to be in a Utility class.
         *
         * @param value String to create one way hash upon.
         * @return MD5 hash.
         * @throws NoSuchAlgorithmException
         */
        public static String encodeMD5(final String value) {
            md.reset();
            final byte[] bytes = md.digest(value.getBytes());
            return (bytes != null) ? new String(bytes) : null;
        }


        public static final int BUF_SIZE = 8096;

        /**
         * Read URL and return String containing content.
         * Note: this ought to be in a Utility class.
         *
         * @param urlStr actually a catalog URL
         * @return String containing content of catalog.
         * @throws MalformedURLException
         * @throws IOException
         */
        public static String readURL(final String urlStr)
                throws MalformedURLException, IOException {

            final URL url = new URL(urlStr);
            final Reader r =
                new BufferedReader(new InputStreamReader(url.openStream()));
            final String xmlCatalog = readFully(r, BUF_SIZE);
            return xmlCatalog;
        }

        /**
         * Compare two byte arrays for equality checking both length and
         * byte values.
         * Note: this ought to be in a Utility class.
         *
         * @param b1 first byte array.
         * @param b2 second byte array.
         * @return true if lengths and all values are equal and false otherwise.
        private static boolean equals(final byte[] b1, final byte[] b2) {
            if (b1.length != b2.length) {
                return false;
            } else {
                for (int i = 0; i < b1.length; i++) {
                    if (b1[i] != b2[i]) {
                        return false;
                    }
                }
            }
            return true;
        }
         */
        /**
         * Note: this is a place holder variable. The value of USE_MD5 should be
         * determined by a new mondrian property in the connectInfo string.
         * Currently a "normal" property is used simply so that I can test it.
         */
        private static final String MD5_PROP
                        = "mondrian.catalog.content.cache.enabled";
        private static final boolean USE_MD5    = Boolean.getBoolean(MD5_PROP);

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

            final String key = (dataSource == null)
                            ? makeKey(catalogName,
                                      connectionKey,
                                      jdbcUser,
                                      dataSourceStr)
                            : makeKey(catalogName,
                                      dataSource);

            RolapSchema schema = null;

            final String dynProc =
                connectInfo.get(RolapConnectionProperties.DynamicSchemaProcessor);
            // If there is a dynamic processor registered, use it. This
            // implies there is not MD5 based caching, but, as with the previous
            // implementation, if the catalog string is in the connectInfo
            // object as catalog content then it is used.
            if ( ! Util.isEmpty(dynProc)) {
                String catalogStr =
                    connectInfo.get(RolapConnectionProperties.CatalogContent);

                schema = (catalogStr == null)
                    // If a schema will be dynamically processed, caching is not
                    // possible.
                    ? new RolapSchema(key,
                                      catalogName,
                                      connectInfo,
                                      dynProc,
                                      dataSource)
                    // Got the catalog string, no need to get it again in the
                    // constructor
                    : new RolapSchema(key,
                                      catalogName,
                                      catalogStr,
                                      connectInfo,
                                      dataSource);

                if (LOGGER.isDebugEnabled()) {
                    String msg = "Pool.get: create schema \"" +
                        catalogName +
                        "\" using dynamic processor";
                    LOGGER.debug(msg);
                }
            } else {

                if (USE_MD5) {
                    // Different catalogNames can actually yield the same
                    // catalogStr! So, we use the MD5 as the key as well as
                    // the key made above - its has two entries in the
                    // mapUrlToSchema Map. We must then also during the
                    // remove operation make sure we remove both.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?