FileDocCategorySizeDatePackage
EJBQLC.javaAPI DocGlassfish v2 API9215Fri May 04 22:34:50 BST 2007com.sun.jdo.spi.persistence.support.ejb.ejbqlc

EJBQLC.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */



/*
 * EJBQLC.java
 *
 * Created on November 12, 2001
 */

package com.sun.jdo.spi.persistence.support.ejb.ejbqlc;

import java.io.Reader;
import java.io.StringReader;
import java.util.Collection;
import java.util.ResourceBundle;
import java.lang.reflect.Method;

import persistence.antlr.TokenBuffer;
import persistence.antlr.ANTLRException;

import com.sun.jdo.spi.persistence.utility.I18NHelper;
import com.sun.jdo.api.persistence.model.Model;
import com.sun.jdo.spi.persistence.support.ejb.model.util.NameMapper;
import com.sun.jdo.spi.persistence.utility.logging.Logger;
import com.sun.jdo.spi.persistence.utility.generator.JavaClassWriterHelper;

/**
 * This class is the driver of the EJBQL compiler. It controls the compiler 
 * passes: syntax analysis, semantic analysis and generation of the JDOQL query.
 * <p>
 * A EJBQLC instance is able to compile multiple EJBQL queries as long as they 
 * come from the same deployement descriptor. The class uses the model instance 
 * passed to the constructor to access any meta data from the deployement 
 * descriptor. Method {@link #compile} compiles a single EJBQL query string 
 * together with the java.lang.reflect.Method instance of the corresponding 
 * finder/selector method. The result is a JDOQLElements instance, that can be 
 * used to construct a JDOQL query instance.
 *
 * @author  Michael Bouschen
 * @author  Shing Wai Chan
 */
public class EJBQLC
{
    /** Meta data access. */
    protected Model model;
    
    /** Name mapping EJB <-> JDO. */
    protected NameMapper nameMapper;
    
    /** The intermediate form of the EJBQL query string. */
    protected EJBQLAST ast;
    
    /** The logger */
    private static Logger logger = LogHelperQueryCompilerEJB.getLogger();
    
    /** I18N support. */
    protected final static ResourceBundle msgs = I18NHelper.loadBundle(
        EJBQLC.class);
        
    /**
     * Signature with CVS keyword substitution for identifying the generated code
     */
    public static final String SIGNATURE = "$RCSfile: EJBQLC.java,v $ $Revision: 1.4 $"; //NOI18N
    
    /**
     * Constructor. 
     * 
     * @param model meta data access.
     * @param nameMapper name mapping EJB <-> JDO.
     */
    public EJBQLC(Model model, NameMapper nameMapper)
    {
        this.model = model;
        this.nameMapper = nameMapper;
    }
    
    /**
     * Compiles the specified query string for the specified 
     * finder/selector method.
     * @param ejbqlQuery the EJBQL query text
     * @param method the Method instance of the finder or selector
     * @param resultTypeMapping result-type-mapping element from the DD
     * @param finderNotSelector <code>true</code> indicates a finder,
     * <code>false</code> a selector
     * @param ejbName the ejb name of the entity bean 
     */
    public JDOQLElements compile(String ejbqlQuery, Method method, 
                                 int resultTypeMapping,
                                 boolean finderNotSelector, String ejbName)
        throws EJBQLException
    {
        boolean finer = logger.isLoggable(Logger.FINER);
        boolean finest = logger.isLoggable(Logger.FINEST);
        if (method == null)
            ErrorMsg.fatal(I18NHelper.getMessage(msgs, 
                "ERR_MissingMethodInstance")); //NOI18N
        if ((ejbqlQuery == null) || ejbqlQuery.trim().length() == 0)
            ErrorMsg.error(I18NHelper.getMessage(msgs, 
                "EXC_MissingEjbqlQueryText", ejbName, //NOI18N
                getMethodSignature(method))); 
        if (finer) 
            logger.finer("LOG_EJBQLCCompile", ejbName, //NOI18N
                         getMethodSignature(method), ejbqlQuery);
                                    
        JDOQLElements result = null;
        TypeSupport typeSupport = new TypeSupport(model, nameMapper);
        ParameterSupport paramSupport = new ParameterSupport(method);
        String pass = null;

        try
        {
            // syntax analysis
            pass = "syntax analysis"; //NOI18N
            if (finer) logger.finer("LOG_EJBQLCStartPass", pass); //NOI18N
            EJBQLParser parser = createStringParser(ejbqlQuery);
            parser.query();
            ast = (EJBQLAST)parser.getAST();
            if (finest) logger.finest("LOG_EJBQLCDumpTree", ast.getTreeRepr("(AST)")); //NOI18N

            // semantic analysis
            pass = "semantic analysis"; //NOI18N
            if (finer) logger.finer("LOG_EJBQLCStartPass", pass); //NOI18N
            Semantic semantic = new Semantic();
            semantic.init(typeSupport, paramSupport, method, resultTypeMapping,
                          finderNotSelector, ejbName);
            semantic.setASTFactory(EJBQLASTFactory.getInstance());
            semantic.query(ast);
            ast = (EJBQLAST)semantic.getAST();
            if (finest) logger.finest("LOG_EJBQLCDumpTree", ast.getTreeRepr("(typed AST)")); //NOI18N

            // JDOQL code generation
            pass = "code generation"; //NOI18N
            if (finer) logger.finer("LOG_EJBQLCStartPass", pass); //NOI18N
            JDOQLCodeGeneration codeGen = new JDOQLCodeGeneration();
            codeGen.init(typeSupport, paramSupport);
            codeGen.setASTFactory(EJBQLASTFactory.getInstance());
            codeGen.query(ast);
            result = codeGen.getJDOQLElements();
            if (finer) logger.finer("LOG_EJBQLCResult", result.toString()); //NOI18N
        }
        catch (EJBQLException ex) {
            // add EJB name, finder/selector, EJBQL to error message.
            Object[] msgArgs = { ejbName, getMethodSignature(method), 
                                 ejbqlQuery, ex.getMessage() };
            ErrorMsg.error(I18NHelper.getMessage(msgs, 
                "EXC_InvalidEJBQLQuery", msgArgs)); //NOI18N
        }
        catch (Throwable t) {
            Object[] msgArgs = { ejbName, getMethodSignature(method), 
                                 ejbqlQuery, t.toString() };
            // log a SEVERE message with nested exception
            ErrorMsg.log(Logger.SEVERE, I18NHelper.getMessage(msgs,
                    "EXC_EJBQLQueryInternalError", msgArgs), t); //NOI18N
        }

        // return the JDOQLElements instance representing the elements 
        // of the JDOQL query.
        return result;
    }

    //========= Internal helper methods ==========
    
    /**
     * Creates an ANTLR EJBQL parser reading a string.
     */
    private EJBQLParser createStringParser(String text)
    {
        Reader in = new StringReader(text);
        EJBQLLexer lexer = new EJBQLLexer(in);
        TokenBuffer buffer = new TokenBuffer(lexer);
        EJBQLParser parser = new EJBQLParser(buffer);
        parser.setASTFactory(EJBQLASTFactory.getInstance());
        return parser;
    }
    
    /** 
     * Returns the signature of a method w/o exceptions and modifiers 
     * as a string.
     */
    private String getMethodSignature(Method m)
    {
        if (m == null) 
            return ""; //NOI18N
        
        return m.getReturnType().getName() + ' ' + m.getName() + 
            JavaClassWriterHelper.parenleft_ +
            JavaClassWriterHelper.getParameterTypesList(m) + 
            JavaClassWriterHelper.parenright_ ;
    }

}