org.acmsl.queryj.api.MetaLanguageUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.acmsl.queryj.api.MetaLanguageUtils.java

Source

/*
                    QueryJ Core
    
Copyright (C) 2002-2006  Jose San Leandro Armendariz
                         chous@acm-sl.org
    
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or any later version.
    
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
    
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
Thanks to ACM S.L. for distributing this library under the GPL license.
Contact info: chous@acm-sl.org
Postal Address: c/Playa de Lagoa, 1
                Urb. Valdecabanas
                Boadilla del monte
                28660 Madrid
                Spain
    
 ******************************************************************************
 *
 * Filename: MetaLanguageUtils.java
 *
 * Author: Jose San Leandro Armendariz
 *
 * Description: Provides insight about the meta-language used in model
 *              descriptions.
 */
package org.acmsl.queryj.api;

/*
 * Importing some project classes.
 */
import org.acmsl.queryj.Literals;
import org.acmsl.queryj.metadata.MetadataManager;
import org.acmsl.queryj.metadata.vo.Attribute;
import org.acmsl.queryj.metadata.vo.Table;
import org.acmsl.queryj.tools.antlr.PerCommentLoggingListener;
import org.acmsl.queryj.tools.antlr.PerCommentLexer;
import org.acmsl.queryj.tools.antlr.PerCommentListener;
import org.acmsl.queryj.tools.antlr.PerCommentParser;
import org.acmsl.queryj.tools.antlr.PerCommentVisitor;

/*
 * Importing ACM-SL Commons classes.
 */
import org.acmsl.commons.logging.UniqueLogFactory;
import org.acmsl.commons.patterns.Singleton;
import org.acmsl.commons.patterns.Utils;
import org.acmsl.commons.utils.StringValidator;

/*
 * Importing some ANTLR classes.
 */
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;

/*
 * Importing some Commons-Logging classes.
 */
import org.apache.commons.logging.Log;

/*
 * Importing some JetBrains annotations.
 */
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/*
 * Importing some JDK classes.
 */
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/*
 * Importing checkthread.org annotations.
 */
import org.checkthread.annotations.ThreadSafe;

/**
 * Provides insight about the meta-language used in model descriptions.
 * @author <a href="mailto:chous@acm-sl.org">Jose San Leandro</a>
 */
@ThreadSafe
public class MetaLanguageUtils implements Singleton, Utils {
    /**
     * The cache of parsers.
     */
    private final Map<String, PerCommentParser> PARSER_CACHE = new ConcurrentHashMap<>();

    /**
     * Singleton implemented to avoid the double-checked locking.
     */
    private static class MetaLanguageUtilsSingletonContainer {
        /**
         * The actual singleton.
         */
        public static final MetaLanguageUtils SINGLETON = new MetaLanguageUtils();
    }

    /**
     * Protected constructor to avoid accidental instantiation.
     */
    protected MetaLanguageUtils() {
    }

    /**
     * Retrieves a <code>MetaLanguageUtils</code> instance.
     * @return such instance.
     */
    public static MetaLanguageUtils getInstance() {
        return MetaLanguageUtilsSingletonContainer.SINGLETON;
    }

    /**
     * Checks whether given table is static.
     * @param tableComment the table's comment.
     * @return <code>true</code> in such case.
     */
    public boolean isStatic(@NotNull final String tableComment) {
        return (retrieveStaticAttribute(tableComment) != null);
    }

    /**
    * Retrieves the attribute used to identify table content.
    * @param tableComment the table's comment.
    * @return such attribute.
    */
    @Nullable
    public String retrieveStaticAttribute(@Nullable final String tableComment) {
        @Nullable
        String result = null;

        if (!isEmpty(tableComment)) {
            try {
                assert tableComment != null;

                @NotNull
                final PerCommentParser t_Parser = setUpParser(tableComment);

                @NotNull
                final ParseTree tree = t_Parser.tableComment();

                @NotNull
                final PerCommentVisitor<String> visitor = new PerCommentTabStaticVisitor();

                result = visitor.visit(tree);
            } catch (@NotNull final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_TABLE_COMMENT + tableComment, recognitionException);
                }
            }
        }

        return result;
    }

    /**
     * Retrieves the parent table in an ISA relationship, as
     * declared by the table comment.
     * @param tableComment the table's comment.
     * @return the parent table, or <code>null</code> otherwise.
     */
    @Nullable
    public String retrieveDeclaredParent(@NotNull final String tableComment) {
        @Nullable
        String result = null;

        if (!isEmpty(tableComment)) {
            try {
                @NotNull
                final PerCommentParser t_Parser = setUpParser(tableComment);

                @NotNull
                final ParseTree tree = t_Parser.tableComment();

                @NotNull
                final PerCommentVisitor<String> visitor = new PerCommentTabIsaVisitor();

                result = visitor.visit(tree);
            } catch (@NotNull final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_TABLE_COMMENT + tableComment, recognitionException);
                }
            }
        }

        return result;
    }

    /**
     * Retrieves the table the comment owner discriminates among its
     * children in an ISA relationship.
     * @param tableComment the table's comment.
     * @return the ISA parent table.
     */
    @SuppressWarnings("unused")
    @Nullable
    public String retrieveDiscriminatingParent(@NotNull final String tableComment) {
        @Nullable
        String result = null;

        if (!isEmpty(tableComment)) {
            try {
                @NotNull
                final PerCommentParser t_Parser = setUpParser(tableComment);

                @NotNull
                final ParseTree tree = t_Parser.tableComment();

                @NotNull
                final PerCommentVisitor<String> visitor = new PerCommentTabIsatypeVisitor();

                result = visitor.visit(tree);
            } catch (@NotNull final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_TABLE_COMMENT + tableComment, recognitionException);
                }
            }
        }

        return result;
    }

    /**
     * Retrieves the value to denote <code>true</code> values. If
     * <code>null</code>, then the column is not considered boolean.
     * @param columnComment the column comment.
     * @return the values to use in the database to denote <code>true</code>,
     * <code>false</code> and <code>null</code> values, or <code>null</code>
     * if the column is not boolean.
     */
    @NotNull
    @SuppressWarnings("unused")
    public String[] retrieveColumnBool(@NotNull final String columnComment) {
        @Nullable
        String[] result = null;

        boolean done = false;

        if (!isEmpty(columnComment)) {
            try {
                @NotNull
                final PerCommentParser t_Parser = setUpParser(columnComment);

                @NotNull
                final ParseTree tree = t_Parser.columnComment();

                @NotNull
                final PerCommentVisitor<List<String>> visitor = new PerCommentColBoolVisitor();

                @Nullable
                final List<String> boolDefs = visitor.visit(tree);

                if ((boolDefs != null) && (boolDefs.size() > 1)) {
                    done = true;
                    result = boolDefs.toArray(new String[boolDefs.size()]);
                }
            } catch (@NotNull final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_COLUMN_COMMENT + columnComment, recognitionException);
                }
            }
        }

        if ((!done) || (result == null)) {
            result = new String[0];
        }

        return result;
    }

    /**
     * Retrieves whether the column is meant to be read-only from the
     * Java side (i.e. a last-modified or creation-date timestamp).
     * @param columnComment the column comment.
     * @return such condition.
     */
    @SuppressWarnings("unused")
    public boolean retrieveColumnReadOnly(@NotNull final String columnComment) {
        boolean result = false;

        if (!isEmpty(columnComment)) {
            try {
                @NotNull
                final PerCommentParser t_Parser = setUpParser(columnComment);

                @NotNull
                final ParseTree tree = t_Parser.columnComment();

                @NotNull
                final PerCommentVisitor<Boolean> visitor = new PerCommentColReadonlyVisitor();

                @Nullable
                final Boolean resultValue = visitor.visit(tree);

                if (resultValue != null) {
                    result = resultValue;
                }
            } catch (@NotNull final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_COLUMN_COMMENT + columnComment, recognitionException);
                }
            }
        }

        return result;
    }

    /**
     * Retrieves which values of the column correspond to which ISA descendant
     * table (whose parent is declared in table comments as <code>@isatype</code>).
     * @param columnComment the column comment.
     * @return such associations.
     */
    @SuppressWarnings("unused")
    @NotNull
    public List<List<String>> retrieveColumnDiscriminatedTables(@NotNull final String columnComment) {
        @Nullable
        List<List<String>> result = null;

        if (!isEmpty(columnComment)) {
            try {
                @NotNull
                final PerCommentParser t_Parser = setUpParser(columnComment);

                @NotNull
                final ParseTree tree = t_Parser.columnComment();

                @NotNull
                final PerCommentVisitor<List<List<String>>> visitor = new PerCommentColIsarefsVisitor();

                @Nullable
                final List<List<String>> resultValue = visitor.visit(tree);

                if (resultValue != null) {
                    result = resultValue;
                }
            } catch (@NotNull final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_COLUMN_COMMENT + columnComment, recognitionException);
                }
            }
        }

        if (result == null) {
            result = new ArrayList<>(0);
        }

        return result;
    }

    /**
     * Retrieves whether the table is meant to be decorated.
     * @param tableComment the table comment.
     * @return such condition.
     */
    public boolean retrieveTableDecorator(@NotNull final String tableComment) {
        boolean result = false;

        if (!isEmpty(tableComment)) {
            try {
                @NotNull
                final PerCommentParser t_Parser = setUpParser(tableComment);

                @Nullable
                final ParseTree t_Tree = t_Parser.tableComment();

                if (t_Tree != null) {
                    @NotNull
                    final PerCommentVisitor<Boolean> t_Visitor = new PerCommentTabDecoratorVisitor();

                    try {
                        @Nullable
                        final Boolean resultValue = t_Visitor.visit(t_Tree);

                        if (resultValue != null) {
                            result = resultValue;
                        }
                    } catch (@NotNull final Throwable npe) {
                        @Nullable
                        final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                        if (t_Log != null) {
                            t_Log.fatal(npe);
                        }
                        npe.printStackTrace(System.err);
                    }
                }
            } catch (@NotNull final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_TABLE_COMMENT + tableComment, recognitionException);
                }
            }
        }

        return result;
    }

    /**
     * Retrieves whether the table is modelling a relationship.
     * @param tableComment the table comment.
     * @return such condition.
     */
    @SuppressWarnings("unused")
    @NotNull
    public List<List<String>> retrieveTableRelationship(@NotNull final String tableComment) {
        @Nullable
        List<List<String>> result = null;

        if (!isEmpty(tableComment)) {
            try {
                @NotNull
                final PerCommentParser t_Parser = setUpParser(tableComment);

                @NotNull
                final ParseTree tree = t_Parser.tableComment();

                @NotNull
                final PerCommentVisitor<List<List<String>>> visitor = new PerCommentTabRelationshipVisitor();

                @Nullable
                final List<List<String>> resultValue = visitor.visit(tree);

                if (resultValue != null) {
                    result = resultValue;
                }
            } catch (final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_TABLE_COMMENT + tableComment, recognitionException);
                }

                result = new ArrayList<>();
            }
        }

        if (result == null) {
            result = new ArrayList<>(0);
        }

        return result;
    }

    /**
     * Sets up the comment parser.
     * @param comment the comment to parse.
     * @return the {@link PerCommentParser} instance.
     */
    @SuppressWarnings("unchecked")
    protected PerCommentParser setUpParser(@NotNull final String comment) throws RecognitionException {
        @NotNull
        final PerCommentParser result;

        @Nullable
        final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

        if ((t_Log != null) && (t_Log.isDebugEnabled())) {
            t_Log.debug("Parsing '" + comment + "'");
        }

        @NotNull
        final PerCommentLexer t_Lexer = new PerCommentLexer(new ANTLRInputStream(comment));

        @NotNull
        final CommonTokenStream t_Tokens = new CommonTokenStream(t_Lexer);

        result = new PerCommentParser(t_Tokens);

        @NotNull
        final PerCommentListener listener = new PerCommentLoggingListener(comment);

        result.addParseListener(listener);

        return result;
    }

    /**
     * Checks whether given input is empty or not.
     * @param text the text.
     * @return <code>true</code> in such case.
     */
    protected boolean isEmpty(@Nullable final String text) {
        return isEmpty(text, StringValidator.getInstance());
    }

    /**
     * Checks whether given input is empty or not.
     * @param text the text.
     * @param stringValidator the {@link StringValidator} instance.
     * @return <code>true</code> in such case.
     */
    protected boolean isEmpty(@Nullable final String text, @NotNull final StringValidator stringValidator) {
        return stringValidator.isEmpty(text);
    }

    /**
     * Checks whether given table contains static values or not.
     * @param tableName the table name.
     * @param metadataManager the {@link MetadataManager} instance.
     * @return <code>true</code> in such case.
     */
    public boolean containsStaticValues(@NotNull final String tableName,
            @NotNull final MetadataManager metadataManager) {
        boolean result = false;

        @Nullable
        final Table<String, Attribute<String>, List<Attribute<String>>> t_Table = metadataManager.getTableDAO()
                .findByName(tableName);

        if (t_Table != null) {
            result = t_Table.isStatic();
        }

        return result;
    }

    /**
     * Retrieves whether the column is bound to a sequence.
     * @param columnComment the column comment.
     * @return the sequence name, or {@code null} otherwise.
     */
    @SuppressWarnings("unused")
    @Nullable
    public String retrieveColumnOraseq(@NotNull final String columnComment) {
        @Nullable
        String result = null;

        if (!isEmpty(columnComment)) {
            try {
                @NotNull
                final PerCommentParser t_Parser = setUpParser(columnComment);

                @NotNull
                final ParseTree tree = t_Parser.columnComment();

                @NotNull
                final PerCommentVisitor<String> visitor = new PerCommentColOraseqVisitor();

                @Nullable
                final String resultValue = visitor.visit(tree);

                if (resultValue != null) {
                    result = resultValue;
                }
            } catch (@NotNull final RecognitionException recognitionException) {
                @Nullable
                final Log t_Log = UniqueLogFactory.getLog(MetaLanguageUtils.class);

                if (t_Log != null) {
                    t_Log.error(Literals.INVALID_COLUMN_COMMENT + columnComment, recognitionException);
                }
            }
        }

        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @NotNull
    public String toString() {
        return "{ \"class\": \"" + MetaLanguageUtils.class.getName() + '"' + ", \"PARSER_CACHE\": " + PARSER_CACHE
                + " }";
    }
}