org.jboss.bqt.jdbc.sql.lang.Symbol.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.bqt.jdbc.sql.lang.Symbol.java

Source

/*
 * JBoss, Home of Professional Open Source.
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */

package org.jboss.bqt.jdbc.sql.lang;

import org.apache.commons.lang.StringUtils;

/**
 * This is the server's representation of a metadata symbol.  The only thing
 * a symbol has to have is a name.  This name relates only to how a symbol is
 * specified in a user's query and does not necessarily relate to any
 * actual metadata identifier (although it may).  Subclasses of this class
 * provide specialized instances of symbol for various circumstances in a
 * user's query.  In the context of a single query, a symbol's name has
 * a unique meaning although it may be used more than once in some circumstances.
 */
public abstract class Symbol implements LanguageObject {

    /** 
     * Name of the symbol
     * 
     * Prior to resolving it is the name as entered in the query,
     * after resolving it is the fully qualified name.
     */
    private String name;

    /** 
     * upper case of name
     */
    private String canonicalName;

    /**
     * Prior to resolving null, after resolving it is the exact string
     * entered in the query.
     * 
     * The AliasGenerator can also set this value as necessary for the data tier.
     */
    private String outputName;

    /**
     * Constructor to be used for cloning instances. Calls to String.toUpperCase() to generate the canonical names
     * were the big performance hit during cloning, so this method allows subclasses to simply pass in the canonical name
     * to avoid toUpperCase().
     * @param name
     * @param canonicalName
     * @since 4.3
     */
    protected Symbol(String name, String canonicalName) {
        this.name = name;
        this.canonicalName = canonicalName;
    }

    /**
     * Construct a symbol with a name.
     * @param name Name of the symbol
     * @throws IllegalArgumentException If name is null
     */
    public Symbol(String name) {
        setName(name);
    }

    /**
     * Change the symbol's name.  This will change the symbol's hash code
     * and canonical name!!!!!!!!!!!!!!!!!  If this symbol is in a hashed
     * collection, it will be lost!
     * @param name New name
     */
    public void setName(String name) {
        if (name == null) {
            throw new IllegalArgumentException("Error: called setName with null value"); //$NON-NLS-1$
        }
        this.name = name;
        this.outputName = null;
        // Canonical name is lazily created
        this.canonicalName = null;
    }

    /**
     * Get the name of the symbol
     * @return Name of the symbol, never null
     */
    public String getName() {
        return this.name;
    }

    /**
     * Get canonical name for comparisons
     * @return Canonical name for comparisons
     */
    public String getCanonicalName() {
        // PERFORMANCE1: String.toUpperCase() is an expensive call, and calls from this class are the largest component
        // of the total toUpperCase() calls, so we are lazily performing the toUpperCase and calculating the hash.
        computeCanonicalNameAndHash();
        return this.canonicalName;
    }

    /**
     * Returns true if this symbol has been completely resolved with respect
     * to actual runtime metadata.  A resolved symbol has been validated that
     * it refers to actual metadata and will have references to the real metadata
     * IDs if necessary.  Different types of symbols determine their resolution
     * in different ways, so this method is abstract and must be implemented
     * by subclasses.
     * @return True if resolved with runtime metadata
     */
    public abstract boolean isResolved();

    /**
     * Returns string representation of this symbol.
     * @return String representing the symbol
     */
    public String toString() {
        return "Symbal.toString() not fully implemented";
        //      return SQLStringVisitor.getSQLString(this);
    }

    /**
     * Return a hash code for this symbol.
     * @return Hash code
     */
    public int hashCode() {
        computeCanonicalNameAndHash();
        // Return cached hash code
        return this.canonicalName.hashCode();
    }

    /**
     * Compare the symbol based ONLY on name.  Symbols are not compared based on
     * their underlying physical metadata IDs but rather on their representation
     * in the context of a particular query.  Case is not important when comparing
     * symbol names.
     * @param obj Other object
     * @return True if other obj is a Symbol (or subclass) and name is equal
     */
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }

        if (!(obj instanceof Symbol)) {
            return false;
        }
        return ((Symbol) obj).getCanonicalName().equals(getCanonicalName());
    }

    /**
     * Return a copy of this object.
     * @return Object
     */
    public abstract Object clone();

    protected String getCanonical() {
        return canonicalName;
    }

    private void computeCanonicalNameAndHash() {
        if (canonicalName == null) {
            canonicalName = StringUtils.upperCase(name);
        }
    }

    public String getOutputName() {
        return this.outputName == null ? getName() : this.outputName;
    }

    public void setOutputName(String outputName) {
        this.outputName = outputName;
    }

}