dev@glassfish.java.net

[Fwd: persistence Digest 27 Oct 2005 13:46:33 -0000 Issue 6]

From: Carla Mott <Carla.Mott_at_Sun.COM>
Date: Thu, 27 Oct 2005 11:16:29 -0700

-- 
Carla Mott
Sun Microsystems		
carla.mott_at_sun.com

attached mail follows:



Content-type: text/plain; charset=us-ascii


persistence Digest 27 Oct 2005 13:46:33 -0000 Issue 6

Topics (messages 20 through 24):

Re: New persistence.xml struture
        20 by: Michael Bouschen
        21 by: Sanjeeb Kumar Sahoo

EJBQL update: grammar change
        22 by: Michael Bouschen

Re: persistence-api changes for new packaging proposal]
        23 by: Sanjeeb Kumar Sahoo

EJBQL NOT queries
        24 by: Michael Bouschen

Administrivia:

To subscribe to the digest, e-mail:
        persistence-digest-subscribe_at_glassfish.dev.java.net

To unsubscribe from the digest, e-mail:
        persistence-digest-unsubscribe_at_glassfish.dev.java.net

To post to the list, e-mail:
        persistence_at_glassfish.dev.java.net


----------------------------------------------------------------------


Content-type: message/rfc822

Date: Wed, 26 Oct 2005 15:54:26 +0200
From: Michael Bouschen <Michael.Bouschen_at_Sun.COM>
Subject: Re: New persistence.xml struture
To: Tom Ware <tom.ware_at_oracle.com>
Cc: persistence_at_glassfish.dev.java.net
Message-id: <435F8A92.9050005_at_sun.com>
MIME-version: 1.0
Content-type: multipart/mixed; boundary="Boundary_(ID_GUJJ6dLBdbj3Nx0oMOPFQg)"

This is a multi-part message in MIME format.

--Boundary_(ID_GUJJ6dLBdbj3Nx0oMOPFQg)
Content-type: text/plain; charset=us-ascii; format=flowed
Content-transfer-encoding: 7BIT

Hi Tom,

sorry, the second attachment (stacktrace2.txt) of my previous mail does
not show the correct stacktrace. Attached you find the right one.

Regards Michael

> Hi Tom,
>
> today I updated the persistence.xml file in my containerless test
> example according to the syntax of the latest packaging proposal.
>
> I have two questions/issues. Do you want me to file issues in the
> glassfish issue tracker system for the two?
>
> (1) I need to include namespace uri in the top most element:
> <persistence xmlns="urn:ejb3-namespace">
> Otherwise, I get a NPE in PersistenceUnitProcessor.processPersistenceXML
> (see attached stacktrace in stacktrace1.txt). The code expects to get a
> list of PersistentUnitInfos from the context handler of the XMLReader.
> W/o the namespace uri the XML reader does not find any persistence unit
> and the returned list is null. Is it required to include the namespace uri?
>
> Furthermore, I understand the recent packaging proposal discussion there
> is no requirement that a persistent.xml needs to specify at least one
> persistence unit. So the list of PersistentUnitInfos might be empty anyway.
>
> (2) I read the new structure of the persistence.xml file that
> persistence-unit has a required attribute called name:
> <persistence-unit name="containerless">
> The current implementation runs into a NPE for the above line (see
> attached stacktrace in stacktrace2.txt). Instead it accepts a nested
> element called name:
> <persistence-unit>
> <name>containerless</name>
>
> Regards Michael
>
>
>
> ------------------------------------------------------------------------
>
> run:
> [java] java.lang.reflect.InvocationTargetException
> [java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> [java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> [java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> [java] at java.lang.reflect.Method.invoke(Method.java:585)
> [java] at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:141)
> [java] Caused by: java.lang.reflect.InvocationTargetException
> [java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> [java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> [java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> [java] at java.lang.reflect.Method.invoke(Method.java:585)
> [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializerAgent.initializeFromAgent(JavaSECMPInitializerAgent.java:54)
> [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializerAgent.premain(JavaSECMPInitializerAgent.java:47)
> [java] ... 5 more
> [java] Caused by: java.lang.NullPointerException
> [java] at oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcessor.processPersistenceXML(PersistenceUnitProcessor.java:166)
> [java] at oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcessor.processDirectory(PersistenceUnitProcessor.java:84)
> [java] at oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcessor.processPersistenceArchive(PersistenceUnitProcessor.java:132)
> [java] at oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcessor.getPersistenceUnits(PersistenceUnitProcessor.java:65)
> [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.initPersistenceUnits(JavaSECMPInitializer.java:275)
> [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.initialize(JavaSECMPInitializer.java:298)
> [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.initializeFromAgent(JavaSECMPInitializer.java:315)
> [java] ... 11 more
> [java] FATAL ERROR in native method: processing of -javaagent failed
> [java] Exception in thread "main"
>
> BUILD SUCCESSFUL
> Total time: 2 seconds
>
>
>
[...]




--Boundary_(ID_GUJJ6dLBdbj3Nx0oMOPFQg)
Content-type: text/plain; name=stacktrace2.txt
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=stacktrace2.txt

run:
     [java] java.lang.reflect.InvocationTargetException
     [java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     [java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     [java] at java.lang.reflect.Method.invoke(Method.java:585)
     [java] at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:141)
     [java] Caused by: java.lang.reflect.InvocationTargetException
     [java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     [java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     [java] at java.lang.reflect.Method.invoke(Method.java:585)
     [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializerAgent.initializeFromAgent(JavaSECMPInitializerAgent.java:54)
     [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializerAgent.premain(JavaSECMPInitializerAgent.java:47)
     [java] ... 5 more
     [java] Caused by: java.lang.NullPointerException
     [java] at java.util.Hashtable.get(Hashtable.java:336)
     [java] at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:353)
     [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.callPredeploy(JavaSECMPInitializer.java:140)
     [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.initPersistenceUnits(JavaSECMPInitializer.java:279)
     [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.initialize(JavaSECMPInitializer.java:298)
     [java] FATAL ERROR in native method: processing of -javaagent failed
     [java] at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.initializeFromAgent(JavaSECMPInitializer.java:315)
     [java] ... 11 more
     [java] Exception in thread "main"

BUILD SUCCESSFUL
Total time: 2 seconds


--Boundary_(ID_GUJJ6dLBdbj3Nx0oMOPFQg)--


Content-type: message/rfc822

Date: Wed, 26 Oct 2005 19:37:54 +0530
From: Sanjeeb Kumar Sahoo <Sanjeeb.Sahoo_at_Sun.COM>
Subject: Re: New persistence.xml struture
To: persistence_at_glassfish.dev.java.net
Cc: Tom Ware <tom.ware_at_oracle.com>
Message-id: <435F8DBA.9060909_at_Sun.COM>
MIME-version: 1.0
Content-type: text/plain; charset=ISO-8859-1; format=flowed
Content-transfer-encoding: 7BIT

Hi Michael,
Michael Bouschen wrote:

> Hi Tom,
>
> today I updated the persistence.xml file in my containerless test
> example according to the syntax of the latest packaging proposal.
>
> I have two questions/issues. Do you want me to file issues in the
> glassfish issue tracker system for the two?
>
> (1) I need to include namespace uri in the top most element:
> <persistence xmlns="urn:ejb3-namespace">

It is OK to expect a name space from user in the persistence.xml.
But the correct name space is http://java.sun.com/xml/ns/persistence.
What you have used is the old namespace that was proposed earlier.

Thanks,
Sahoo

> Otherwise, I get a NPE in
> PersistenceUnitProcessor.processPersistenceXML (see attached
> stacktrace in stacktrace1.txt). The code expects to get a list of
> PersistentUnitInfos from the context handler of the XMLReader. W/o the
> namespace uri the XML reader does not find any persistence unit and
> the returned list is null. Is it required to include the namespace uri?
>
> Furthermore, I understand the recent packaging proposal discussion
> there is no requirement that a persistent.xml needs to specify at
> least one persistence unit. So the list of PersistentUnitInfos might
> be empty anyway.
>
> (2) I read the new structure of the persistence.xml file that
> persistence-unit has a required attribute called name:
> <persistence-unit name="containerless">
> The current implementation runs into a NPE for the above line (see
> attached stacktrace in stacktrace2.txt). Instead it accepts a nested
> element called name:
> <persistence-unit>
> <name>containerless</name>
>
> Regards Michael
>
>



Content-type: message/rfc822

Date: Wed, 26 Oct 2005 20:05:23 +0200
From: Michael Bouschen <Michael.Bouschen_at_Sun.COM>
Subject: EJBQL update: grammar change
To: Tom Ware <tom.ware_at_oracle.com>
Cc: persistence_at_glassfish.dev.java.net
Message-id: <435FC563.8020302_at_sun.com>
MIME-version: 1.0
Content-type: multipart/mixed; boundary="Boundary_(ID_wa1/TFSRytggBq0TjeuHdA)"

This is a multi-part message in MIME format.

--Boundary_(ID_wa1/TFSRytggBq0TjeuHdA)
Content-type: text/plain; charset=us-ascii; format=flowed
Content-transfer-encoding: 7BIT

Hi Tom,

attached you find an updated version of EJBQLParser.g. I added new
grammar rules for
- multiple expressions in the SELECT clause
- constructor expression (NEW keyword)
- EXISTS
- ALL, ANY, SOME
- CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP
- SIZE

Please note, all of the above features are not fully implemented, so the
parser will throw an exception "Not yet implemented: SIZE function" if
any of these are used in an EJBQL query.

Please let me know if there are any issues with the change. Thanks!

Regards Michael




--Boundary_(ID_wa1/TFSRytggBq0TjeuHdA)
Content-type: text/plain; name=EJBQLParser.g
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=EJBQLParser.g

/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the "License"). You may not use this file except
 * in compliance with the License.
 *
 * You can obtain a copy of the license at
 * glassfish/bootstrap/legal/CDDLv1.0.txt or
 * https://glassfish.dev.java.net/public/CDDLv1.0.html.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * HEADER in each file and include the License file at
 * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
 * add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your
 * own identifying information: Portions Copyright [yyyy]
 * [name of copyright owner]
 */
// Added 20/12/2000 JED. Define the package for the class
header {
        package oracle.toplink.essentials.internal.parsing.ejbql.antlr273;

    import oracle.toplink.essentials.exceptions.EJBQLException;
}

/** */
class EJBQLParser extends Parser("oracle.toplink.essentials.internal.parsing.ejbql.EJBQLParser");
options {
        exportVocab=EJBQL;
        k = 3; // This is the number of tokens to look ahead to
        buildAST = true;
}

tokens {
        ABS="abs";
    ALL="all";
        AND="and";
    ANY="any";
        AS="as";
        ASC="asc";
        AVG="avg";
        BETWEEN="between";
    BOTH="both";
        BY="by";
        CONCAT="concat";
        COUNT="count";
    CURRENT_DATE="current_date";
    CURRENT_TIME="current_time";
    CURRENT_TIMESTAMP="current_timestamp";
        DESC="desc";
    DELETE="delete";
        DISTINCT="distinct";
        EMPTY="empty";
        ESCAPE="escape";
    EXISTS="exists";
        FALSE="false";
    FETCH="fetch";
        FROM="from";
    GROUP="group";
    HAVING="having";
        IN="in";
    INNER="inner";
        IS="is";
    JOIN="join";
    LEADING="leading";
    LEFT="left";
        LENGTH="length";
        LIKE="like";
        LOCATE="locate";
    LOWER="lower";
        MAX="max";
        MEMBER="member";
        MIN="min";
        MOD="mod";
    NEW="new";
        NOT="not";
        NULL="null";
        OBJECT="object";
        OF="of";
        OR="or";
        ORDER="order";
    OUTER="outer";
        SELECT="select";
        SET="set";
    SIZE="size";
        SQRT="sqrt";
    SOME="some";
        SUBSTRING="substring";
        SUM="sum";
    TRAILING="trailing";
    TRIM="trim";
        TRUE="true";
        UNKNOWN="unknown";
        UPDATE="update";
    UPPER="upper";
        WHERE="where";
}

{
    protected void validateAbstractSchemaName(Token token)
        throws RecognitionException {
        String text = token.getText();
        if (!isValidJavaIdentifier(token.getText())) {
            throw new NoViableAltException(token, getFilename());
        }
    }

    protected boolean isValidJavaIdentifier(String text) {
        if ((text == null) || text.equals(""))
            return false;

        // check first char
        if (!Character.isJavaIdentifierStart(text.charAt(0)))
            return false;

        // check remaining characters
        for (int i = 1; i < text.length(); i++) {
            if (!Character.isJavaIdentifierPart(text.charAt(i))) {
                return false;
            }
        }
        
        return true;
    }
}

document
        : selectStatement
        | updateStatement
    | deleteStatement
        ;

selectStatement
        : (selectClause {finishedSelect();})
          (fromClause {finishedFrom();})
          (whereClause {finishedWhere();})?
      (groupByClause {finishedGroupBy();})?
      (havingClause {finishedHaving();})?
          (orderByClause {finishedOrderBy();})?
          EOF {finishedAll();}
        ;

//================================================

updateStatement
        : (updateClause {finishedUpdate();})
          (setClause {finishedSet();})
          (whereClause {finishedWhere();})?
          EOF {finishedAll();}
        ;

updateClause
        : UPDATE {matchedUpdate();}
          (abstractSchemaName ((AS)? abstractSchemaIdentifier)?)
        ;

setClause
        : (set setAssignmentClause)
          (COMMA {startEqualsAssignment();} setAssignmentClause)*
         ;

set
        : SET {matchedSet();}
        ;

setAssignmentClause
        : ((leftMostIdentifier dot)? identifier equalsAssignment newValue {finishedEqualsAssignment();})
        ;

newValue
    : expressionOperand
        ;

//================================================

deleteStatement
    : deleteClause { finishedDelete(); }
      (whereClause {finishedWhere();})?
      EOF {finishedAll();}
    ;

deleteClause
    : DELETE { matchedDelete(); } FROM
      abstractSchemaName ((AS)? abstractSchemaIdentifier)?
    ;

//================================================

selectClause
        : SELECT {matchedSelect();} (distinct)?
      selectExpression
      ( COMMA
        {
            throw EJBQLException.notYetImplemented(
               "multiple expressions in SELECT clause");
        }
        selectExpression
      )*
    ;

distinct
        : DISTINCT {matchedDistinct();}
        ;

selectExpression
    : singleValuedPathExpression
    | aggregateFunction {finishedAggregate();}
    | identifier
    | OBJECT LEFT_ROUND_BRACKET identifier RIGHT_ROUND_BRACKET
    | constructorExpression
        ;

aggregateFunction
        : AVG {matchedAvg();} aggregateFunctionArg
    | MAX {matchedMax();} aggregateFunctionArg
    | MIN {matchedMin();} aggregateFunctionArg
    | SUM {matchedSum();} aggregateFunctionArg
        | COUNT {matchedCount();} countFunctionArg
        ;

aggregateFunctionArg
    : LEFT_ROUND_BRACKET (distinct)? stateFieldPathExpression RIGHT_ROUND_BRACKET
    ;

countFunctionArg
    : LEFT_ROUND_BRACKET (distinct)? ( identifier | pathExpression ) RIGHT_ROUND_BRACKET
    ;

constructorExpression
    : NEW
      {
          throw EJBQLException.notYetImplemented(
              "constructor expression");
      }
        constructorName
        LEFT_ROUND_BRACKET
        ( constructorItem ( COMMA constructorItem )* )?
        RIGHT_ROUND_BRACKET
    ;

constructorName
    : baseIdentifier ( DOT baseIdentifier )*
    ;

constructorItem
    : singleValuedPathExpression
    | aggregateFunction {finishedAggregate();}
    ;

fromClause
        : from identificationVariableDeclaration
      (COMMA (identificationVariableDeclaration |
               collectionMemberDeclaration) )*
        ;
from
        : FROM {matchedFrom();}
        ;

identificationVariableDeclaration
        : rangeVariableDeclaration (join)*
        ;

rangeVariableDeclaration
        : abstractSchemaName (AS)? abstractSchemaIdentifier
        ;

// Non-terminal abstractSchemaName first matches any token to allow abstract
// schema names that are keywords (such as order, etc.).
// Method validateAbstractSchemaName throws an exception if the text of the
// token is not a valid Java identifier.
abstractSchemaName
        : ident:.
      {
          validateAbstractSchemaName(ident);
          matchedAbstractSchemaName();
      }
        ;

abstractSchemaIdentifier
        : baseIdentifier {matchedAbstractSchemaIdentifier();}
        ;

join
{ boolean outerJoin; }
    : outerJoin = joinSpec
      ( associationPathExpression (AS)? baseIdentifier
        {
            matchedJoinIdentifier();
            finishedJoin(outerJoin);
        }
      | FETCH associationPathExpression
        { finishedFetchJoin(outerJoin); }
      )
    ;

joinSpec returns [boolean outer]
{ outer = false; }
    : (LEFT (OUTER)? { outer = true; } | INNER )? JOIN
    ;

collectionMemberDeclaration
        : IN LEFT_ROUND_BRACKET collectionValuedPathExpression RIGHT_ROUND_BRACKET
      (AS)? baseIdentifier
      {
          matchedCollectionMemberIdentifier();
          finishedInClauseInFrom();
      }
        ;

collectionValuedPathExpression
    : pathExpression
    ;

associationPathExpression
    : pathExpression
    ;

singleValuedPathExpression
        : pathExpression
        ;

stateFieldPathExpression
    : pathExpression
    ;

pathExpression
        : leftMostIdentifier dot (identifier dot)* identifier
        ;

dot
        : DOT {matchedDot();}
        ;

identifier
        : baseIdentifier {matchedIdentifier();}
        ;

leftMostIdentifier
        : baseIdentifier {matchedLeftMostIdentifier();}
        ;

baseIdentifier
        : TEXTCHAR
        ;

whereClause
        : WHERE {matchedWhere();} conditionalExpression
        ;

conditionalExpression
        : conditionalTerm (OR{matchedOr();} conditionalTerm {finishedOr();})*
        ;

conditionalTerm
        : {conditionalTermFound();} conditionalFactor (AND{matchedAnd();} conditionalFactor {finishedAnd();})*
        ;

conditionalFactor
        : (NOT {matchedNot();})? ( conditionalPrimary | existsExpression )
        ;

conditionalPrimary
        : (LEFT_ROUND_BRACKET conditionalExpression) =>
                (LEFT_ROUND_BRACKET {matchedLeftRoundBracket();} conditionalExpression RIGHT_ROUND_BRACKET {matchedRightRoundBracket();})
        | simpleConditionalExpression
        ;

simpleConditionalExpression
        : arithmeticExpression simpleConditionalExpressionRemainder
        ;

simpleConditionalExpressionRemainder
        : comparisonExpression
        | ((NOT)? BETWEEN) => (betweenExpression)
        | ((NOT)? LIKE) => (likeExpression)
        | ((NOT)? IN) => (inExpression)
        | (isNot NULL) => (nullComparisonExpression)
        | emptyCollectionComparisonExpression
        | collectionMemberExpression
        ;

betweenExpression
        : (NOT {matchedNot();})? BETWEEN {matchedBetween();} stringExpression AND {matchedAndAfterBetween();} stringExpression {finishedBetweenAnd();}
        ;

inExpression
        : (NOT {matchedNot();})? (IN {matchedIn();})
                (LEFT_ROUND_BRACKET
                        (literalString | literalNumeric | inputParameter | namedInputParameter)
                                (COMMA (literalString | literalNumeric | inputParameter | namedInputParameter))*
                RIGHT_ROUND_BRACKET)
                {finishedIn();}
        ;

likeExpression
        : (NOT {matchedNot();})?
                (LIKE {matchedLike();}
                        (literalString | inputParameter | namedInputParameter)
                        (ESCAPE {matchedEscape();} literalString {finishedEscape();})?)
                {finishedLike();}
        ;

nullComparisonExpression
        : isNot NULL {matchedNull();} {finishedNull();}
        ;

emptyCollectionComparisonExpression
        : isNot EMPTY {matchedEmpty();} {finishedEmpty();}
        ;

collectionMemberExpression
        : (NOT {matchedNot();})? (MEMBER (OF)?) {matchedMemberOf();} collectionValuedPathExpression {finishedMemberOf();}
        ;

existsExpression
    : EXISTS
      {
          throw EJBQLException.notYetImplemented("EXISTS expression");
      }
      LEFT_ROUND_BRACKET subquery RIGHT_ROUND_BRACKET
    ;

comparisonExpression
        : (equalTo | notEqualTo | greaterThan | greaterThanEqualTo | lessThan | lessThanEqualTo)
      ( arithmeticExpression | anyOrAllExpression )
      {finishedComparisonExpression();}
        ;

arithmeticExpression
    : simpleArithmeticExpression
    | LEFT_ROUND_BRACKET subquery RIGHT_ROUND_BRACKET
    ;

simpleArithmeticExpression : arithmeticTerm ((plus | minus) arithmeticTerm)* ;

arithmeticTerm : arithmeticFactor ((multiply | divide) arithmeticFactor)* {finishedMultiplyOrDivide();} ;

arithmeticFactor : (plus | minus)? arithmeticPrimary ;

arithmeticPrimary
        : expressionOperand
        | (LEFT_ROUND_BRACKET {matchedLeftRoundBracket();} arithmeticExpression RIGHT_ROUND_BRACKET {matchedRightRoundBracket();})
        ;

expressionOperand
        : leftMostIdentifier
        | stateFieldPathExpression
        | functionsReturningNumerics
        | functionsReturningDatetime
        | functionsReturningStrings
        | inputParameter
        | namedInputParameter
        | literalNumeric
        | literalString
        | literalBoolean
        ;

anyOrAllExpression
    : ( ALL | ANY | SOME )
        {
            throw EJBQLException.notYetImplemented("ALL, ANY, SOME expression");
        }
        LEFT_ROUND_BRACKET subquery RIGHT_ROUND_BRACKET
    ;

isNot
        : IS (NOT {matchedNot();})?
        ;

stringExpression
        : stringPrimary
    | LEFT_ROUND_BRACKET subquery RIGHT_ROUND_BRACKET
        ;

stringPrimary
        : literalString
        | functionsReturningStrings
        | inputParameter
        | namedInputParameter
    | stateFieldPathExpression
        ;

//Literals and Low level stuff
literal
        : literalNumeric
        | literalBoolean
        | literalString
        ;

literalNumeric
        : NUM_INT {matchedInteger();}
        | NUM_FLOAT {matchedFloat();}
        ;

literalBoolean
        : TRUE {matchedTRUE();}
        | FALSE {matchedFALSE();}
        ;

literalString
        : STRING_LITERAL_DOUBLE_QUOTED {matchedDoubleQuotedString();}
        | STRING_LITERAL_SINGLE_QUOTED {matchedSingleQuotedString();}
        ;

inputParameter
        : (QUESTIONMARK NUM_INT) {matchedInputParameter();}
        ;

namedInputParameter
        : (COLON TEXTCHAR) {matchedNamedInputParameter();}
        ;

functionsReturningNumerics
        : abs
        | length
        | mod
        | sqrt
        | locate
    | size
        ;

functionsReturningDatetime
    : CURRENT_DATE
      {
          throw EJBQLException.notYetImplemented("CURRENT_DATE function");
      }
    | CURRENT_TIME
      {
          throw EJBQLException.notYetImplemented("CURRENT_TIME function");
      }
    | CURRENT_TIMESTAMP
      {
          throw EJBQLException.notYetImplemented("CURRENT_TIMESTAMP function");
      }
    ;

functionsReturningStrings
        : concat
        | substring
    | trim
    | upper
    | lower
        ;

plus
        : PLUS {matchedPlus();}
        ;

minus
        : MINUS {matchedMinus();}
        ;

multiply
        : MULTIPLY {matchedMultiply();}
        ;

divide
        : DIVIDE {matchedDivide();}
        ;

equalTo
        : EQUALS {matchedEqualsComparison();}
        ;

equalsAssignment
        : EQUALS {matchedEqualsAssignment();}
        ;

greaterThan
        : GREATER_THAN {matchedGreaterThan();}
        ;

greaterThanEqualTo
        : GREATER_THAN_EQUAL_TO {matchedGreaterThanEqualTo();}
        ;

lessThan
        : LESS_THAN {matchedLessThan();}
        ;

lessThanEqualTo
        : LESS_THAN_EQUAL_TO {matchedLessThanEqualTo();}
        ;

notEqualTo
        : (NOT_EQUAL_TO) {matchedNotEqualTo();}
        ;

// Functions returning strings
concat
        : CONCAT {matchedConcat();}
                LEFT_ROUND_BRACKET
                        (singleValuedPathExpression | literalString) COMMA {matchedCommaAfterConcat();}
                        (singleValuedPathExpression | literalString)
                RIGHT_ROUND_BRACKET {finishedConcat();}
                
        ;

substring
        : SUBSTRING {matchedSubstring();}
                LEFT_ROUND_BRACKET
                        (singleValuedPathExpression | inputParameter | namedInputParameter | literalString) {finishedSubstringVariable();}
                        COMMA arithmeticExpression
                        COMMA arithmeticExpression
                RIGHT_ROUND_BRACKET
                {finishedSubstring();}
        ;

trim
    : TRIM {matchedTrim();}
        LEFT_ROUND_BRACKET
        ( ( trimDef )=> trimDef )? stringPrimary {finishedTrimVariable();}
        RIGHT_ROUND_BRACKET
      {finishedTrim();}
    ;

trimDef
    : ( trimSpec )? ( trimChar {finishedTrimChar();} )? FROM
    ;

trimSpec
    : LEADING {matchedLeading();}
    | TRAILING {matchedTrailing();}
    | BOTH {matchedBoth();}
    ;

trimChar
    : literalString
    | inputParameter
    ;

upper
    : UPPER { matchedUpper(); }
      LEFT_ROUND_BRACKET stringPrimary { finishedUpperVariable(); } RIGHT_ROUND_BRACKET
      { finishedUpper(); }
    ;

lower
    : LOWER { matchedLower(); }
      LEFT_ROUND_BRACKET stringPrimary { finishedLowerVariable(); } RIGHT_ROUND_BRACKET
      { finishedLower(); }
    ;


// Functions returning numerics
abs
        : ABS {matchedAbs();}
                LEFT_ROUND_BRACKET
                (singleValuedPathExpression | inputParameter | namedInputParameter ) {finishedAbsVariable();}
                RIGHT_ROUND_BRACKET
          {finishedAbs();}
        ;

length
        : LENGTH {matchedLength();}
                LEFT_ROUND_BRACKET
                singleValuedPathExpression {finishedLengthVariable();}
                RIGHT_ROUND_BRACKET
                {finishedLength();}
        ;

locate
        : LOCATE {matchedLocate();}
                LEFT_ROUND_BRACKET
                literalString {finishedLocateLiteral();}
                COMMA singleValuedPathExpression {finishedLocateVariable();}
                RIGHT_ROUND_BRACKET
                {finishedLocate();}
        ;

size
    : SIZE
        {
            throw EJBQLException.notYetImplemented("SIZE function");
        }
        LEFT_ROUND_BRACKET collectionValuedPathExpression RIGHT_ROUND_BRACKET
    ;

mod
        : MOD {matchedMod();}
                LEFT_ROUND_BRACKET
                        arithmeticExpression {finishedFirstArithmeticExpressionInMOD(); }
                        COMMA arithmeticExpression {finishedSecondArithmeticExpressionInMOD();}
                RIGHT_ROUND_BRACKET
        ;

sqrt
        : SQRT {matchedSqrt();}
                LEFT_ROUND_BRACKET
                (singleValuedPathExpression | inputParameter | namedInputParameter) {finishedSqrtVariable();}
                RIGHT_ROUND_BRACKET
        ;

subquery
    : simpleSelectClause
      subqueryFromClause
          (whereClause {finishedWhere();})?
      (groupByClause {finishedGroupBy();})?
      (havingClause {finishedHaving();})?
    ;

simpleSelectClause
    : SELECT {matchedSelect();} (distinct)? simpleSelectExpression
    ;

simpleSelectExpression
    : singleValuedPathExpression
    | aggregateFunction
    | baseIdentifier
    ;

subqueryFromClause
    : from subselectIdentificationVariableDeclaration
        ( COMMA subselectIdentificationVariableDeclaration )*
    ;

subselectIdentificationVariableDeclaration
    : identificationVariableDeclaration
    | associationPathExpression (AS)? baseIdentifier
    | collectionMemberDeclaration
    ;

orderByClause
        : ORDER BY {matchedOrderBy();}
                orderByItem (COMMA orderByItem)*
        ;

orderByItem
        : stateFieldPathExpression {matchedOrderByItem();}
                (ASC {matchedAscDirection();} | DESC {matchedDescDirection();})?
                {finishedOrderByItem();}
    ;

groupByClause
    : GROUP BY { matchedGroupBy(); }
        groupByItem (COMMA groupByItem)*
        ;

groupByItem
    : stateFieldPathExpression
                { finishedGroupByItem(); }
    ;

havingClause
    : HAVING { matchedHaving(); }
        conditionalExpression
    ;

/** */
class EJBQLLexer extends Lexer;
options {
        caseSensitive=false;
        caseSensitiveLiterals=false;
        k = 4;
        exportVocab=EJBQL;
        charVocabulary = '\3'..'\377';
}

// hexadecimal digit (again, note it's protected!)
protected
HEX_DIGIT
        : ('0'..'9'|'a'..'f')
        ;

WS : (' ' | '\t' | '\n' | '\r')+
        { $setType(Token.SKIP); } ;

LEFT_ROUND_BRACKET
        : '('
        ;

RIGHT_ROUND_BRACKET
        : ')'
        ;

COMMA
        : ','
        ;

TEXTCHAR
        : ('a'..'z' | '_' | '$') ('a'..'z' | '_' | '$' | '0'..'9')*
        ;

// a numeric literal
NUM_INT
        {boolean isDecimal=false;}
        : '.' {_ttype = DOT;}
                        (('0'..'9')+ (EXPONENT)? (FLOAT_SUFFIX)? { _ttype = NUM_FLOAT; })?
        | ( '0' {isDecimal = true;} // special case for just '0'
                        ( ('x')
                                ( // hex
                                        // the 'e'|'E' and float suffix stuff look
                                        // like hex digits, hence the (...)+ doesn't
                                        // know when to stop: ambig. ANTLR resolves
                                        // it correctly by matching immediately. It
                                        // is therefor ok to hush warning.
                                        options {
                                                warnWhenFollowAmbig=false;
                                        }
                                : HEX_DIGIT
                                )+
                        | ('0'..'7')+ // octal
                        )?
                | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
                )
                ( ('l')
                
                // only check to see if it's a float if looks like decimal so far
                | {isDecimal}?
                        ( '.' ('0'..'9')* (EXPONENT)? (FLOAT_SUFFIX)?
                        | EXPONENT (FLOAT_SUFFIX)?
                        | FLOAT_SUFFIX
                        )
                        { _ttype = NUM_FLOAT; }
                )?
        ;

// a couple protected methods to assist in matching floating point numbers
protected
EXPONENT
        : ('e') ('+'|'-')? ('0'..'9')+
        ;


protected
FLOAT_SUFFIX
        : 'f'|'d'
        ;

EQUALS
        : '='
        ;

GREATER_THAN
        : '>'
        ;

GREATER_THAN_EQUAL_TO
        : ">="
        ;

LESS_THAN
        : '<'
        ;

LESS_THAN_EQUAL_TO
        : "<="
        ;

NOT_EQUAL_TO
        : "<>"
        ;

REMOTE_INTERFACE_REFERENCE_OPERATOR
        : "=>"
        ;

MULTIPLY
        : "*"
        ;

DIVIDE
        : "/"
        ;

PLUS
        : "+"
        ;

MINUS
        : "-"
        ;

QUESTIONMARK
        : "?"
        ;

COLON
        : ":"
        ;

// Added Jan 9, 2001 JED
// string literals
STRING_LITERAL_DOUBLE_QUOTED
        : '"' (ESC|~('"'|'\\'))* '"'
        ;

STRING_LITERAL_SINGLE_QUOTED
        : ('\'' '\\' '\'') => ('\'' '\\' '\'')
        | '\'' (ESC|~('\''|'\\') | ("''"))* '\''
        ;

// Added Jan 9, 2001 JED
// escape sequence -- note that this is protected; it can only be called
// from another lexer rule -- it will not ever directly return a token to
// the parser
// There are various ambiguities hushed in this rule. The optional
// '0'...'9' digit matches should be matched here rather than letting
// them go back to STRING_LITERAL to be matched. ANTLR does the
// right thing by matching immediately; hence, it's ok to shut off
// the FOLLOW ambig warnings.
protected
ESC
        : '\\'
                ( '_'
                | 'n'
                | 'r'
                | 't'
                | 'b'
                | 'f'
                | '"'
                | '\''
                | '\\'
                | ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
                | ('0'..'3')
                        (
                                options {
                                        warnWhenFollowAmbig = false;
                                }
                        : ('0'..'7')
                                (
                                        options {
                                                warnWhenFollowAmbig = false;
                                        }
                                : '0'..'7'
                                )?
                        )?
                | ('4'..'7')
                        (
                                options {
                                        warnWhenFollowAmbig = false;
                                }
                        : ('0'..'9')
                        )?
                )
        ;



--Boundary_(ID_wa1/TFSRytggBq0TjeuHdA)--


Content-type: message/rfc822

Date: Thu, 27 Oct 2005 01:10:24 +0530
From: Sanjeeb Kumar Sahoo <Sanjeeb.Sahoo_at_Sun.COM>
Subject: Re: [Fwd: Re: persistence-api changes for new packaging proposal]
To: Tom Ware <tom.ware_at_oracle.com>
Cc: "persistence_at_glassfish.dev.java.net" <persistence_at_glassfish.dev.java.net>
Message-id: <435FDBA8.2090309_at_Sun.COM>
MIME-version: 1.0
Content-type: text/plain; charset=ISO-8859-1; format=flowed
Content-transfer-encoding: 7BIT

Tom Ware wrote:

>
>
> Sanjeeb Kumar Sahoo wrote:
>
>> Hi Tom,
>> Tom Ware wrote:
>>
>>> Sahoo,
>>>
>>> Here is my plan.
>>>
>>> I will implement a TopLink version that will handle both
>>> PersistenceInfo (the old class) and PersistenceUnitInfo (the new
>>> class). That way we can do a more seamless transition.
>>>
>>> I am attaching my version of PersistenceUnitInfo(cut and pasted
>>> from the spec) and one class it is dependant on. I believe it can
>>> be checked at in any time.
>>>
>> I have checked them in this morning after adding CDDL headers.
>
>
> Thank you.
>
>>
>>> After it is checked in, we can do the TopLink part of the work in 4
>>> phases.
>>>
>>> 1. Check in the TopLink version that implements both versions
>>
>>
>>
>> I have asked Shelly to update CTS to new spec and run one round of
>> CTS. That way we would know if there was any regression in packaging
>> changes that I had committed. After that you can do this change. What
>> do you suggest
>
>
> Let me know when we are ready.
>
>>
>>> 2. Check in the Glassfish version that uses the new TopLink
>>> implementation
>>
>>
>>
>> I have the changes in my local workspace. I can check them in after
>> you make change #1.
>
>
> ok
>
>>
>>> 3. Remove the dependance on the old version from TopLink
>>> 4. Delete the PersistenceInfo class.
>>
>>
>>
>> #3 & #4 can be done after #2 either by you or me.
>
>
> ok. I suggest I do #3 and you do #4.

Sure. One thing I don't want to miss. When you do #3, please also stop
using javax.persistence.spi.InstrumentableClassLoader in
entity-persistence? That class need to be removed from that package. I
shall do that after making necessary changes in container.

Thanks,
Sahoo

>>
>> Thanks,
>> Sahoo
>>
>>>
>>> Let me know what you think,
>>> Tom
>>>
>>> Sanjeeb Kumar Sahoo wrote:
>>>
>>>> Hi Team,
>>>> This is my plans for making changes in glassfish to the latest
>>>> packaging changes:
>>>>
>>>> 1) I will use the latest proposal (the one sent by Linda
>>>> yesterday). I will update persistence.xsd so that CTS tests can be
>>>> migrated from par to jar as well as to new schema at the same time.
>>>>
>>>> 2) Not all features from the new packaging spec will be supported
>>>> in the initial check in. We will support the persistence unit to be
>>>> part of ejb-jar (stand alone as well as embedded), embedded war and
>>>> embedded library jar. The rest will be implemented subsequently.
>>>>
>>>> 3) To minimize the amount of changes in one check in, we will not
>>>> update the javax.persistence.spi interfaces in the first check in.
>>>> So to start with we don't have to change the part of TopLink
>>>> Essential that runs inside container. All the supported features
>>>> would work fine. Once the first phase of container changes are
>>>> made, in the second phase both container and TopLink Essential will
>>>> be modified to use the new SPI.
>>>> I hope to check in the first set of changes by Monday (subject to
>>>> getting review comments from all reviewers).
>>>> The second phase of changes would include update to the SPIs. This
>>>> will be done mid next week (*Tom, please confirm, whether this is
>>>> OK with you or not*). This will be transparent to users.
>>>>
>>>> Thanks,
>>>> Sahoo
>>>>
>>>> ------------------------------------------------------------------------
>>>>
>>>>
>>>> Subject:
>>>> Re: persistence-api changes for new packaging proposal
>>>> From:
>>>> Tom Ware <tom.ware_at_oracle.com>
>>>> Date:
>>>> Thu, 20 Oct 2005 13:25:48 -0400
>>>> To:
>>>> Sanjeeb Kumar Sahoo <Sanjeeb.Sahoo_at_Sun.COM>
>>>>
>>>> To:
>>>> Sanjeeb Kumar Sahoo <Sanjeeb.Sahoo_at_Sun.COM>
>>>>
>>>>
>>>>
>>>>
>>>> Sanjeeb Kumar Sahoo wrote:
>>>>
>>>>> Tom Ware wrote:
>>>>>
>>>>>> What do you mean by "the latest proposal"? Are you referring to
>>>>>> the version of the proposal you sent me (dated 9/12/05)?
>>>>>>
>>>>> No. There was a new proposal sent out yesterday by Linda and Mike.
>>>>> Have you not seen it?
>>>>>
>>>> Ok, I'll use that one.
>>>>
>>>>>> As I mentioned in my earlier email, the changes we have to make
>>>>>> in order to be functional on the application server are minimal.
>>>>>> Essentially, we just need to update our implementation of
>>>>>> PersistenceInfo so that it will compile. You mentioned yesterday
>>>>>> that you thought we could come initial work without the change to
>>>>>> javax.persistence.PersitenceInfo.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> I would prefer this way as opposed to changing both container and
>>>>> provider at the same time. What do you say?
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> That's fine with me.
>>>>
>>>>>
>>>>> Thanks,
>>>>> Sahoo
>>>>>
>>>>>>
>>>>>> -Tom
>>>>>>
>>>>>> Sanjeeb Kumar Sahoo wrote:
>>>>>>
>>>>>>> Hi Tom,
>>>>>>> First we need to agree on the persistence-api changes. The
>>>>>>> latest proposal now contains the schema and changed APIs. Do you
>>>>>>> plan to use them or do you have some other version? In any case,
>>>>>>> if you have the .java files and .xsd files, please send them to me.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Sahoo
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>
>>



Content-type: message/rfc822

Date: Thu, 27 Oct 2005 15:46:25 +0200
From: Michael Bouschen <Michael.Bouschen_at_Sun.COM>
Subject: EJBQL NOT queries
To: Tom Ware <tom.ware_at_oracle.com>
Cc: persistence_at_glassfish.dev.java.net
Message-id: <4360DA31.5020908_at_sun.com>
MIME-version: 1.0
Content-type: multipart/mixed; boundary="Boundary_(ID_a3iEpGJpnwBUebHIzUUvSQ)"

This is a multi-part message in MIME format.

--Boundary_(ID_a3iEpGJpnwBUebHIzUUvSQ)
Content-type: text/plain; charset=us-ascii; format=flowed
Content-transfer-encoding: 7BIT

Hi Tom,

I looked into EJBQL queries using the NOT operator in the WHERE clause
and I found two cases where the generated SQL is not correct:
(1) ... WHERE NOT (NOT (c.name = 'Michael Bouschen'))
(2) ... WHERE NOT c.name <> 'Michael Bouschen'
The SQL WHERE clause for both queries misses a NOT operator:
   ... WHERE NOT ((NAME = 'Michael Bouschen'))

I think (I hope) I fixed the problem, you find a fix attached below.
Here are some details about the fix. Problem (1) is caused by method
handleRightRoundBracket calling finishedConstructingNode instead of
finishedExpression. Only the latter takes care of any pending not
operations to be added before the helper instance is closed. The reason
for (2) is that the ParseTreeNodeConstructor does not support having two
NOT operations in the same context, method handleNot overwrites any
notNode registered before. An expression "x<>y" is mapped to NOT x=y, so
query (2) is mapped to a query with two NOT operators. I fixed the code
in ParseTreeNodeConstructor.handleNot.

Please have a look. Thanks!

Regards Michael

--Boundary_(ID_a3iEpGJpnwBUebHIzUUvSQ)
Content-type: text/plain; name=ParseTreeNodeConstructor.java
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=ParseTreeNodeConstructor.java

/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the "License"). You may not use this file except
 * in compliance with the License.
 *
 * You can obtain a copy of the license at
 * glassfish/bootstrap/legal/CDDLv1.0.txt or
 * https://glassfish.dev.java.net/public/CDDLv1.0.html.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * HEADER in each file and include the License file at
 * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
 * add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your
 * own identifying information: Portions Copyright [yyyy]
 * [name of copyright owner]
 */
// Copyright (c) 1998, 2005, Oracle. All rights reserved.
package oracle.toplink.essentials.internal.parsing;


// TopLink imports
import oracle.toplink.essentials.queryframework.*;

/**
 * INTERNAL
 * <p><b>Purpose</b>: Construct Nodes for the parse tree
 * <p><b>Responsibilities</b>:<ul>
 * <li> Add Parameters to the parse tree
 * <li> Handle the construction of nodes for the parse tree
 * <li> Spawn a new constrcutor as needed
 * <li> Finish the construction of nodes when signaled
 * </ul>
 * @author Jon Driscoll and Joel Lucuik
 * @since TopLink 4.0
 */
public class ParseTreeNodeConstructor {
    public ParseTreeConstructor treeConstructor;
    protected Node currentNode;
    public ParseTreeNodeConstructor parentConstructor;
    private NotNode notNode = null;
    public Node schemaIdentifierNode;
    public Node lastPlacedNode;

    //boolean indicating that brackets have been encountered, immediately following
    //a +, -. This triggers a precedence override
    public boolean bracketsOverrideMultiplyOrDivide = false;

    /**
     * Return a new, initialized ParseTreeNodeConstructor
     */
    public ParseTreeNodeConstructor() {
        super();
    }

    /**
     * Return a new, initialized ParseTreeNodeConstructor
     */
    public ParseTreeNodeConstructor(ParseTreeConstructor newTreeConstructor) {
        super();
        setTreeConstructor(newTreeConstructor);
    }

    /**
     * INTERNAL
     * Add this parameter to the parse tree
     */
    public void addParameter(String theParameter) {
        getParseTree().addParameter(theParameter);
    }

    /**
     * INTERNAL
     * Answer the node for the local variable (left most).
     */
    public Node buildLeftMostLocalVariableNode(String variableName) {
        return new LocalVariableNode(variableName);

    }

    /**
     * INTERNAL
     * Answer a new node for the local variable.

     */
    public Node buildLocalVariableNode(String variableName) {
        return new LocalVariableNode(variableName);
    }

    /**
     * INTERNAL
     * Create a new helper to construct the incoming nodes. Answer the new helper
     */
    public ParseTreeNodeConstructor createHelper() {
        ParseTreeNodeConstructor helper = new ParseTreeNodeConstructor(this.getTreeConstructor());
        getTreeConstructor().setNodeConstructor(helper);
        helper.setParentConstructor(this);
        return helper;
    }

    /**
     * INTERNAL
     * Finish the ABS clause by passing control to my parent constructor
     */
    public void finishedAbs() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finish the ABS variable clause by passing control to my parent constructor
     */
    public void finishedAbsVariable() {
        finishedExpression();
    }

    /**
     * Finish the AND clause by passing control to my parent constructor
     */
    public void finishedAnd() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finished the Aggregate node
     */
    public void finishedAggregate() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finished the first arithmetic expression in the MOD. Finish the expression
     * , then start another helper.
     */
    public void finishedFirstArithmeticExpressionInMOD() {
        finishedConstructingNode();
    }

    /**
     * INTERNAL
     * Finished the second arithmetic expression in the MOD. Finish the expression.
     */
    public void finishedSecondArithmeticExpressionInMOD() {
        finishedConstructingNode();
    }

    /**
     * Finish the Expression, by finishing the node, and tying up loose ends
     */
    public void finishedExpression() {
        finishedConstructingNode();
        if (hasParentConstructor()) {
            getParentConstructor().finishPendingNodes();
        } else {
            finishPendingNodes();
        }
    }

    /**
     * Finish the BETWEEN..AND clause by passing control to my parent constructor
     */
    public void finishedBetweenAnd() {
        finishedExpression();
    }

    /**
     * Finish the >, >=, <, <=, =, <> clause(s)
     */
    public void finishedComparisonExpression() {
        finishedExpression();
    }

    /**
     * Finish the Concat expression by passing control to my parent constructor
     */
    public void finishedConcat() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * The current node has been finished, notify the parent constructor
     */
    public void finishedConstructingNode() {
        if (!hasParentConstructor()) {
            return;
        }
        getParentConstructor().helperDone(this);
    }

    /**
     * INTERNAL
     * Finish the escape clause
     */
    public void finishedEscape() {
        finishedExpression();
    }

    /**
     * Finish the *, /
     */
    public void finishedMultiplyOrDivide() {
        if (getCurrentNode().isMultiplyNode() || getCurrentNode().isDivideNode()) {
            finishedExpression();
        }

        //we don't care about brackets any more, because we're done with *, /
        bracketsOverrideMultiplyOrDivide = false;
    }

    /**
     * INTERNAL
     * The Locate is finished
     */
    public void finishedLocate() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * The Locate Literal is finished. A helper is needed to handle the
     * next node.
     */
    public void finishedLocateLiteral() {
        createHelper();
    }

    /**
     * INTERNAL
     * The Locate Variable is finished
     */
    public void finishedLocateVariable() {
        finishedExpression();
    }

    /**
     * Finish the >, >=, <, <= clause(s) by passing control to my parent constructor
     */
    public void finishedNumericOther() {
        finishedExpression();
    }

    /**
     * Finish the IN clause by passing control to my parent constructor
     */
    public void finishedIn() {
        getCurrentNode().setComplete(true);
        finishedExpression();
    }

    /**
     * Finish the IN clause, that is the IN within the FROM.
     */
    public void finishedInClauseInFrom() {
    }

    /**
     * Finish the JOIN clause.
     */
    public void finishedJoinClause() {
    }

    /**
     * Finish the LENGTH clause by passing control to my parent constructor
     */
    public void finishedLength() {
        finishedExpression();
    }

    /**
     * Finish the LENGTH variable clause by passing control to my parent constructor
     */
    public void finishedLengthVariable() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * The LIKE node is now finished...
     */
    public void finishedLike() {
        finishedExpression();
    }

    /**
     * Finish the MEMBER-OF clause by passing control to my parent constructor
     */
    public void finishedMemberOf() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * The null node is now finished
     */
    public void finishedNull() {
        finishedExpression();
    }

    /**
     * Finish the OR clause by passing control to my parent constructor
     */
    public void finishedOr() {
        finishedExpression();
    }

    /**
     * Clear the current node as ther may be multiple order by items
     */
    public void finishedOrderByItem() {
        getParentConstructor().placeNode(getCurrentNode());
        setCurrentNode(null);
    }

    /**
     * Clear the current node as ther may be multiple group by items
     */
    public void finishedGroupByItem() {
        getParentConstructor().placeNode(getCurrentNode());
        setCurrentNode(null);
    }

    /**
     * INTERNAL
     * Finish the SELECT clause
     */
    public void finishedSelect() {
        finishedExpression();
    }

    /**
     * Finished a set_to tree branch. Add it to the set node
     */
    public void finishedEqualsAssignment() {
        finishedExpression();
    }

    /**
     * Finish the LOWER clause by passing control to my parent constructor
     */
    public void finishedLower() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finish the LOWER variable clause by passing control to my parent constructor
     */
    public void finishedLowerVariable() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finish the Single valued path expression of a MOD
     */
    public void finishedModSingleValuedPathExpression() {
        finishedExpression();
    }

    /**
     * INTERNAl
     * Finish the SQRT variable clause by passing control to my parent constructor
     */
    public void finishedSqrtVariable() {
        finishedExpression();
    }

    /**
     * Finish the SUBSTRING clause by passing control to my parent constructor
     */
    public void finishedSubstring() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finish the SUBSTRING variable clause by passing control to my parent constructor
     */
    public void finishedSubstringVariable() {
        finishedExpression();
    }

    /**
     * Finish the UPPER clause by passing control to my parent constructor
     */
    public void finishedUpper() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finish the UPPER variable clause by passing control to my parent constructor
     */
    public void finishedUpperVariable() {
        finishedExpression();
    }

    /**
     * Finish the TRIM clause by passing control to my parent constructor
     */
    public void finishedTrim() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finish the trim character by passing control to my parent constructor
     */
    public void finishedTrimChar() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Finish the trim variable by passing control to my parent constructor
     */
    public void finishedTrimVariable() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Return the parseTreeContext
     */
    public ParseTreeContext getParseTreeContext() {
        return getTreeConstructor().getContext();
    }

    /**
     * INTERNAL
     * getCurrentNode()
     * Answer the current node not yet fully populated
     */
    public Node getCurrentNode() {
        return currentNode;
    }

    /**
     * INTERNAL
     * Answer the NotNode
     */
    private NotNode getNotNode() {
        return notNode;
    }

    /**
     * INTERNAL
     * Return the parent constructor of this constructor
     */
    public ParseTreeNodeConstructor getParentConstructor() {
        return parentConstructor;
    }

    /**
     * INTERNAL
     * Return the parent parse tree
     */
    public EJBQLParseTree getParseTree() {
        if (hasParentConstructor()) {
            return getParentConstructor().getParseTree();
        } else {
            return (EJBQLParseTree)getTreeConstructor().getParseTree();
        }
    }

    public Node getSchemaIdentifierNode() {
        return schemaIdentifierNode;
    }

    public ParseTreeConstructor getTreeConstructor() {
        return treeConstructor;
    }

    /**
     * INTERNAL
     * Handle an 'ABS' on the input stream
     */
    public void handleAbs() {
        AbsNode absNode = new AbsNode();
        placeNode(absNode);
        createHelper();
    }

    /**
     * Event handler for the 'AND' token
     */
    public void handleAnd() {
        AndNode andNode = new AndNode();
        placeNode(andNode);
        createHelper();
    }

    /**
     * Event handler for the 'AND' after the 'BETWEEN' token
     */
    public void handleAndAfterBetween() {
        finishedConstructingNode();
    }

    /**
     * INTERNAL
     * Event handler for 'ASC'
     */
    public void handleAsc() {
        SortDirectionNode node = new SortDirectionNode();
        node.useAscending();
        placeNode(node);
    }

    /**
     * INTERNAL
     * Event handler for 'AVG'
     */
    public void handleAvg() {
        AggregateNode node = new AggregateNode();
        node.useAvg();
        placeNode(node);
        createHelper();
    }

    /**
     * Event handler for the 'BETWEEN' token
     */
    public void handleBetween() {
        BetweenNode betweenNode = new BetweenNode();
        placeNode(betweenNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'CONCAT' on the input stream
     */
    public void handleConcat() {
        ConcatNode concatNode = new ConcatNode();
        placeNode(concatNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'COUNT' on the input stream
     */
    public void handleCount() {
        CountNode node = new CountNode();
        placeNode(node);
        createHelper();
    }

    /**
     * Event handler for a COMMA after the 'CONCAT' token
     */
    public void handleCommaAfterConcat() {
        finishedConstructingNode();
    }

    /**
     * INTERNAL
     * Handle a 'DESC' on the input stream
     */
    public void handleDesc() {
        SortDirectionNode node = new SortDirectionNode();
        node.useDescending();
        placeNode(node);
    }

    /**
     * INTERNAL
     * Handle a DISTINCT on the input stream
     */
    public void handleDistinct() {
        getParseTree().setDistinctState(ObjectLevelReadQuery.USE_DISTINCT);
    }

    /**
     * INTERNAL
     * Handle a '/' on the input stream
     */
    public void handleDivide() {
        placeMultiplyOrDivideNode(new DivideNode());
    }

    /**
     * Event handler for the 'DOT' token
     */
    public void handleDot() {
        DotNode dotNode = new DotNode();
        placeNode(dotNode);
    }

    /**
     * INTERNAL
     * Event handler for the '=' token
     */
    public void handleEqualsComparison() {
        EqualsNode equalsNode = new EqualsNode();
        placeNode(equalsNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the escape token
     */
    public void handleEscape() {
        EscapeNode node = new EscapeNode();
        placeNode(node);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the EMPTY token
     *
     * Place a new EmpyCollectionComparisonNode. Indicate to this node
     * if there is a NOT involved.
     */
    public void handleEmpty() {
        EmptyCollectionComparisonNode emptyNode = new EmptyCollectionComparisonNode();
        if (hasNotNode()) {
            setNotNode(null);
            emptyNode.indicateNot();
        }
        placeNode(emptyNode);
    }

    /**
     * INTERNAL
     * Handle a 'FALSE' being found on the input stream
     */
    public void handleFalse() {
        BooleanLiteralNode falseNode = new BooleanLiteralNode(false);
        placeNode(falseNode);
    }

    /**
     * INTERNAL
     * A float was foundon the input stream
     */
    public void handleFloat(Object theFloat) {
        FloatLiteralNode floatNode = new FloatLiteralNode(theFloat);
        placeNode(floatNode);
    }

    /**
     * INTERNAL
     * Handle a 'FROM' being found on the input stream.
     */
    public void handleFrom() {
        FromNode node = new FromNode();
        node.setContext(getParseTreeContext());
        placeNode(node);
    }

    /**
     * INTERNAL
     * Event handler for the '>' token
     */
    public void handleGreaterThan() {
        GreaterThanNode greaterThanNode = new GreaterThanNode();
        placeNode(greaterThanNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the ">=" token
     */
    public void handleGreaterThanEqualTo() {
        GreaterThanEqualToNode greaterThanEqualToNode = new GreaterThanEqualToNode();
        placeNode(greaterThanEqualToNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the 'GROUP BY' token. Create a new groupByNode and place it
     */
    public void handleGroupBy() {
        GroupByNode groupByNode = new GroupByNode();
        placeNode(groupByNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the 'HAVING' token. Create a new havingNode and place it
     */
    public void handleHaving() {
        HavingNode havingNode = new HavingNode();
        placeNode(havingNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the "IN" token
     */
    public void handleIn() {
        InNode inNode = new InNode();

        // if a NOT was encountered, indicate it in the IN node
        if (hasNotNode()) {
            inNode.indicateNot();
            setNotNode(null);
        }

        placeNode(inNode);
    }

    /**
     * INTERNAL
     * Event handler for an input parameter
     */
    public void handleInputParameter(String theParameter) {
        ParameterNode parameterNode = new ParameterNode(theParameter);
        placeNode(parameterNode);
        parameterNode.addParameterToTree();
    }

    /**
     * Event handler for an Integer
     */
    public void handleInteger(Integer newInteger) {
        IntegerLiteralNode integerNode = new IntegerLiteralNode(newInteger);
        placeNode(integerNode);
    }

    /**
     * INTERNAL
     * Event handler for a leftmost local variable. The node will have "leftMost" indicated.
     */
    public void handleLeftMostLocalVariable(String variableName) {
        placeNode(buildLeftMostLocalVariableNode(variableName));
    }

    /**
     * Event handler for the '(' token
     */
    public void handleLeftRoundBracket() {
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'LENGTH' on the input stream
     */
    public void handleLength() {
        LengthNode lengthNode = new LengthNode();
        placeNode(lengthNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the '<' token
     */
    public void handleLessThan() {
        LessThanNode lessThanNode = new LessThanNode();
        placeNode(lessThanNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the '<=' token
     */
    public void handleLessThanEqualTo() {
        LessThanEqualToNode lessThanEqualToNode = new LessThanEqualToNode();
        placeNode(lessThanEqualToNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a like being found on the input stream.
     * Create a new LikeNode and place it
     */
    public void handleLike() {
        LikeNode likeNode = new LikeNode();
        placeNode(likeNode);
    }

    /**
     * INTERNAL
     * Event handler for a local variable
     */
    public void handleLocalVariable(String variableName) {
        placeNode(buildLocalVariableNode(variableName));
    }

    /**
     * INTERNAL
     * Handle a LOCATE being found
     */
    public void handleLocate() {
        LocateNode node = new LocateNode();
        placeNode(node);
    }

    /**
     * INTERNAL
     * Handle a 'MAX' on the input stream
     */
    public void handleMax() {
        AggregateNode node = new AggregateNode();
        node.useMax();
        placeNode(node);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'MEMBER-OF' on the input stream
     */
    public void handleMemberOf() {
        MemberOfNode memberOfNode = new MemberOfNode();
        if (hasNotNode()) {
            setNotNode(null);
            memberOfNode.indicateNot();
        }
        placeNode(memberOfNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'MIN' on the input stream
     */
    public void handleMin() {
        AggregateNode node = new AggregateNode();
        node.useMin();
        placeNode(node);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a '-' on the input stream
     */
    public void handleMinus() {
        placeNode(new MinusNode());
    }

    /**
     * INTERNAL
     * Handle a 'MOD' on the input stream
     */
    public void handleMod() {
        ModNode node = new ModNode();
        placeNode(node);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a '*' on the input stream
     */
    public void handleMultiply() {
        placeMultiplyOrDivideNode(new MultiplyNode());
    }

    /**
     * INTERNAL
     * Event handler for the 'NOT' token
     */
    public void handleNot() {
        if (hasNotNode()) {
            // This is the second not operation in the same scope => skip
            setNotNode(null);
        }
        else {
            NotNode notNode = new NotNode();
            setNotNode(notNode);
        }
    }

    /**
     * INTERNAL
     * Handle a 'NULL' being found on the input stream
     */
    public void handleNull() {
        NullComparisonNode nullComparisonNode = new NullComparisonNode();
        placeNode(nullComparisonNode);
        //Handle "NOT NULL"
        if (hasNotNode()) {
            placeNode(getNotNode());
            setNotNode(null);
        }
    }

    /**
     * INTERNAL
     * Event handler for the 'OR' token. Create a new orNode and place it
     */
    public void handleOr() {
        OrNode orNode = new OrNode();
        placeNode(orNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the 'ORDER BY' token. Create a new orderByNode and place it
     */
    public void handleOrderBy() {
        OrderByNode orderByNode = new OrderByNode();
        placeNode(orderByNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Hanlde an order by item being found
     */
    public void handleOrderByItem() {
        OrderByItemNode node = new OrderByItemNode();
        placeNode(node);
    }

    /**
     * INTERNAL
     * Handle a '+' on the input stream
     */
    public void handlePlus() {
        placeNode(new PlusNode());
    }

    /**
     * Event handler for the ')' token
     */
    public void handleRightRoundBracket() {
        finishedExpression();
    }

    /**
     * INTERNAL
     * Handle a SELECT
     */
    public void handleSelect() {
        SelectNode node = new SelectNode();
        placeNode(node);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a SET
     */
    public void handleSet() {
        SetNode setNode = new SetNode();
        setNode.placeNodeOnTree(getTreeConstructor().getParseTree());
        createHelper();
    }

    /**
     * INTERNAL
     * Event handler for the set_to token
     */
    public void handleEqualsAssignment() {
        EqualsAssignmentNode equalsAssignmentNode = new EqualsAssignmentNode();
        placeNode(equalsAssignmentNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'SQRT' on the input stream
     */
    public void handleSqrt() {
        SqrtNode sqrtNode = new SqrtNode();
        placeNode(sqrtNode);
        createHelper();
    }

    /**
     * INTERNAL:
     * Handle the start of a set_to branch
     */
    public void handleStartEqualsAssignment() {
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'SUM' on the input stream
     */
    public void handleSum() {
        AggregateNode node = new AggregateNode();
        node.useSum();
        placeNode(node);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a string literal being encountered on the input stream
     */
    public void handleString(String theString) {
        StringLiteralNode stringLiteralNode = new StringLiteralNode(theString);
        placeNode(stringLiteralNode);
    }

    /**
     * INTERNAL
     * Handle a 'SUBSTRING' on the input stream
     */
    public void handleSubstring() {
        SubstringNode substringNode = new SubstringNode();
        placeNode(substringNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'UPPER' on the input stream
     */
    public void handleUpper() {
        UpperNode upperNode = new UpperNode();
        placeNode(upperNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'LOWER' on the input stream
     */
    public void handleLower() {
        LowerNode lowerNode = new LowerNode();
        placeNode(lowerNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'TRIM' on the input stream
     */
    public void handleTrim() {
        TrimNode trimNode = new TrimNode();
        placeNode(trimNode);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a 'TRUE' being found on the input stream
     */
    public void handleTrue() {
        BooleanLiteralNode trueNode = new BooleanLiteralNode(true);
        placeNode(trueNode);
    }

    /**
     * INTERNAL
     * Handle an UPDATE
     */
    public void handleUpdate() {
        UpdateNode node = new UpdateNode();
        node.setContext(getParseTreeContext());
        placeNode(node);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a DELETE
     */
    public void handleDelete() {
        DeleteNode node = new DeleteNode();
        node.setContext(getParseTreeContext());
        placeNode(node);
        createHelper();
    }

    /**
     * INTERNAL
     * Handle a WHERE being encountered on the input stream
     * Clear out the variables from the FROM and SELECT
     */
    public void handleWhere() {
        setCurrentNode(null);
    }

    public boolean hasNotNode() {
        return getNotNode() != null;
    }

    public boolean hasParentConstructor() {
        return parentConstructor != null;
    }

    /**
     * Helper is done. Place its current node. Get rid of the helper.
     * If this set of brackets surrounds a + or -, then trigger the precedence override,
     * so that *, / don't take precedence any more.
     */
    public void helperDone(ParseTreeNodeConstructor child) {
        placeNode(child.getCurrentNode());
        this.getTreeConstructor().setNodeConstructor(this);
        checkForBracketsOverridingMultiplyOrDivide();
    }

    public void finishPendingNodes() {
        //take care of the NOT, if there is one
        if (hasNotNode()) {
            placeNode(getNotNode());
            setNotNode(null);
        }
    }

    /**
     * INTERNAL
     * Ask the node to put itself where it belongs in relation to the current root.
     * If there's no current node, make the new node the root and current node.
     */
    public void placeNode(Node newNode) {
        setLastPlacedNode(newNode);

        newNode.setNodeConstructor(this);
        if (getCurrentNode() != null) {
            getCurrentNode().placeNode(newNode);
        }

        // If the newNode should replace the current node then do it
        if (shouldReplaceCurrent(newNode)) {
            setCurrentNode(newNode);
            setRoot(newNode);
        }
    }

    /**
     * INTERNAL
     * We need to check for a precedence handling.
     * Consider:
     * a + b * c VS
     * (a + b) * c
     *
     * We need to set a trigger to indicate that the * does not take precedence in the second
     * case
     */
    public void checkForBracketsOverridingMultiplyOrDivide() {
        if (getCurrentNode().isPlusNode() || getCurrentNode().isMinusNode()) {
            bracketsOverrideMultiplyOrDivide = true;
        }
    }

    /**
     * INTERNAL
     * Place the MultiplyNode or DivideNode taking into consideration the current node.
     * If the current node is a PlusNode or a Minus Node, then we must adjust for precedence,
     * unless brackets override.
     * To adjust for precendence, we steal the node that should have rightfully been the Multiply or Divide Node's,
     * and create a helper to finish the Multiply or Divide Node.
     * If the current node is something else, place normally.
     */
    public void placeMultiplyOrDivideNode(Node multiplyOrDivideNode) {
        if (bracketsOverrideMultiplyOrDivide) {
            placeNode(multiplyOrDivideNode);
            return;
        }
        if (getCurrentNode().isPlusNode() || getCurrentNode().isMinusNode()) {
            multiplyOrDivideNode.stealNodeFrom(getCurrentNode());
            createHelper().placeNode(multiplyOrDivideNode);
        } else {
            placeNode(multiplyOrDivideNode);
        }
    }

    public void setCurrentNode(Node newCurrentNode) {
        currentNode = newCurrentNode;
    }

    public void setLastPlacedNode(Node newLastPlacedNode) {
        lastPlacedNode = newLastPlacedNode;
    }

    private void setNotNode(NotNode newNotNode) {
        notNode = newNotNode;
    }

    public void setParentConstructor(ParseTreeNodeConstructor newParentConstructor) {
        parentConstructor = newParentConstructor;
    }

    /**
     * INTERNAL
     * Set the root node to the passed node. Ignore if I have a parent (which mean I'm a helper)
     */
    public void setRoot(Node theNode) {
        if (hasParentConstructor()) {
            return;
        }
        getTreeConstructor().setRoot(theNode);
    }

    public void setTreeConstructor(ParseTreeConstructor newTreeConstructor) {
        treeConstructor = newTreeConstructor;
    }

    /**
     * INTERNAL
     * Answer true if there's no current node yet, or the current node is now within
     * the subtree of the newNode.
     */
    public boolean shouldReplaceCurrent(Node newNode) {
        return (getCurrentNode() == null) || (newNode.containsNode(getCurrentNode()));
    }
}

--Boundary_(ID_a3iEpGJpnwBUebHIzUUvSQ)--