Author: arminw
Date: Tue Mar 20 19:27:10 2007
New Revision: 520720

URL: http://svn.apache.org/viewvc?view=rev&rev=520720
Log:
fix for OJB-133

Added:
    
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/AttributeTokenizer.java
Modified:
    
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java
    
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java

Modified: 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java
URL: 
http://svn.apache.org/viewvc/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java?view=diff&rev=520720&r1=520719&r2=520720
==============================================================================
--- 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java
 (original)
+++ 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java
 Tue Mar 20 19:27:10 2007
@@ -22,8 +22,8 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.StringTokenizer;
 
+import org.apache.ojb.broker.PersistenceBrokerException;
 import org.apache.ojb.broker.PersistenceBrokerSQLException;
 import org.apache.ojb.broker.accesslayer.JoinSyntaxTypes;
 import org.apache.ojb.broker.metadata.ClassDescriptor;
@@ -48,7 +48,7 @@
 import org.apache.ojb.broker.query.SelectionCriteria;
 import org.apache.ojb.broker.query.SqlCriteria;
 import org.apache.ojb.broker.query.UserAlias;
-import org.apache.ojb.broker.util.SqlHelper;
+import org.apache.ojb.broker.util.AttributeTokenizer;
 import org.apache.ojb.broker.util.logging.Logger;
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 
@@ -107,7 +107,11 @@
     public SqlQueryStatement(SqlQueryStatement parent, Platform pf, 
ClassDescriptor cld, Query query, Logger logger)
     {
         super(pf, logger);
-
+        if(cld.isAbstract() && !query.getWithExtents())
+        {
+            throw new PersistenceBrokerException("Can't query objects of 
abstract class/interface '"
+                    + cld.getClassNameOfObject() + "' with disabled 'extents' 
- Query.setWithExtents(false)");
+        }
         m_parentStatement = parent;
         m_query = (QueryByCriteria) query;
         m_searchCld = cld;
@@ -186,14 +190,13 @@
      */
     protected AttributeInfo getAttributeInfo(String attr, boolean 
useOuterJoins, UserAlias aUserAlias, Map pathClasses)
     {
+        AttributeTokenizer attrTok = new AttributeTokenizer(attr);
         AttributeInfo result;
-        StringTokenizer st = SqlHelper.tokenizeAttribute(attr);
         result = new AttributeInfo(attr);
-
-        while (st.hasMoreTokens())
+        while (attrTok.hasNext())
         {
-            String token = st.nextToken();
-            if (SqlHelper.isAttribute(token))
+            String token = attrTok.next();
+            if (attrTok.currentIsAttribute())
             {
                 result.add(getSingleAttributeInfo(token, useOuterJoins, 
aUserAlias, pathClasses));
             }
@@ -201,8 +204,9 @@
             {
                 result.add(token);
             }
+//            System.out.println("attr=" + attr + ", current=" + 
attrTok.current() + ", currentIsAttr="
+//                    + attrTok.currentIsAttribute());
         }
-
         return result;
     }
 
@@ -360,18 +364,27 @@
     {
         FieldDescriptor fld = null;
 
-        // Search Join Structure for attribute
-        // TODO BRJ: imo we have to consider 'superClass' joins only
+        /*
+            Search Join Structure for attribute
+            BRJ: imo we have to consider 'superClass' joins only
+            arminw: If a report query with aggreate function is used, it can be
+            necessary to resolve a join:
+            ReportQueryByCriteria q = 
QueryFactory.newReportQuery(BookReview.class, crit);
+            q.setAttributes(new String[]{"name", "sum(author.books)"});
+            in this case we need to resolve the path 1:1 to Author and 1:n to 
Book list.
+            Seems that OJB-94 doesn't appear again after changing these lines.
+        */
         if (aTableAlias.joins != null)
         {
             Iterator itr = aTableAlias.joins.iterator();
             while (itr.hasNext())
             {
                 Join join = (Join) itr.next();
-                if ("superClass".equals(join.name))
-                {
-                    fld = getFieldDescriptor(join.right, attrName);
-                }
+//                if ("superClass".equals(join.name))
+//                {
+//                    fld = getFieldDescriptor(join.right, attrName);
+//                }
+                fld = getFieldDescriptor(join.right, attrName);
                 if (fld != null)
                 {
                     break;
@@ -1460,7 +1473,7 @@
             Class clazz = (Class) iter.next();
             Class superClazz = clazz.getSuperclass();
 
-            if (superClazz != null && 
resultClass.equals(superClazz.getSuperclass()))
+            if (superClazz != null && resultClass != null && 
resultClass.equals(superClazz.getSuperclass()))
             {
                 continue; // skip if we already have a super superclass 
             }
@@ -1727,7 +1740,7 @@
         */
        private void buildJoinTreeForColumn(String aColName, boolean 
useOuterJoin, UserAlias aUserAlias, Map pathClasses)
        {
-               String pathName = SqlHelper.cleanPath(aColName);
+               String pathName = new 
AttributeTokenizer(aColName).getCleanPath();
                int sepPos = pathName.lastIndexOf(".");
 
                if (sepPos >= 0)

Modified: 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java
URL: 
http://svn.apache.org/viewvc/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java?view=diff&rev=520720&r1=520719&r2=520720
==============================================================================
--- 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java
 (original)
+++ 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java
 Tue Mar 20 19:27:10 2007
@@ -42,7 +42,7 @@
 import org.apache.ojb.broker.locking.IsolationLevels;
 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
 import org.apache.ojb.broker.util.ClassHelper;
-import org.apache.ojb.broker.util.SqlHelper;
+import org.apache.ojb.broker.util.AttributeTokenizer;
 import org.apache.ojb.broker.util.configuration.Configuration;
 import org.apache.ojb.broker.util.configuration.Configurator;
 import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
@@ -841,10 +841,11 @@
     }
 
     /**
-     * return the FieldDescriptor for the Attribute referenced in the path<br>
-     * the path may contain simple attribut names, functions and path 
expressions
-     * using relationships <br>
+     * Return the [EMAIL PROTECTED] FieldDescriptor} for the attribute 
referenced in the path.
+     * The path may contain simple attribut names, functions and path 
expressions
+     * using relationships <br/>
      * ie: name, avg(price), adress.street
+     *
      * @param aPath the path to the attribute
      * @param pathHints a Map containing the class to be used for a segment or 
<em>null</em>
      * if no segment was used.
@@ -867,18 +868,6 @@
         return fld;
     }
 
-    /**
-     * return the FieldDescriptor for the Attribute referenced in the path<br>
-     * the path may contain simple attribut names, functions and path 
expressions
-     * using relationships <br>
-     * ie: name, avg(price), adress.street
-     * @param aPath the path to the attribute
-     * @return the FieldDescriptor or null (ie: for m:n queries)
-     */
-    public FieldDescriptor getFieldDescriptorForPath(String aPath)
-    {
-        return getFieldDescriptorForPath(aPath, null);
-    }
 /*
 arminw:
 TODO: this feature doesn't work, so remove this in future
@@ -1182,12 +1171,13 @@
     }
 
     /**
-     * return all AttributeDescriptors for the path<br>
+     * Return all AttributeDescriptors for the path<br>
      * ie: partner.addresses.street returns a Collection of 3 
AttributeDescriptors
      * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
      * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
      * (ObjectReferenceDescriptor, CollectionDescriptor)
-     * @param aPath the cleaned path to the attribute
+     *
+     * @param aPath the path to the attribute
      * @return ArrayList of AttributeDescriptors
      */
     public ArrayList getAttributeDescriptorsForPath(String aPath)
@@ -1201,14 +1191,15 @@
      * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
      * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
      * (ObjectReferenceDescriptor, CollectionDescriptor)
-     * @param aPath the cleaned path to the attribute
+     *
+     * @param aPath the path to the attribute
      * @param pathHints a Map containing the class to be used for a segment or 
<em>null</em>
      * if no segment was used.
      * @return ArrayList of AttributeDescriptors
      */
     public ArrayList getAttributeDescriptorsForPath(String aPath, Map 
pathHints)
     {
-        return getAttributeDescriptorsForCleanPath(SqlHelper.cleanPath(aPath), 
pathHints);
+        return getAttributeDescriptorsForCleanPath(new 
AttributeTokenizer(aPath).getCleanPath(), pathHints);
     }
 
     /**
@@ -1217,7 +1208,8 @@
      * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
      * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
      * (ObjectReferenceDescriptor, CollectionDescriptor)
-     * @param aPath the cleaned path to the attribute
+     *
+     * @param aPath the "cleaned path" (without function expressions) to the 
attribute
      * @param pathHints a Map containing the class to be used for a segment or 
<em>null</em>
      * if no segment is used.
      * @return ArrayList of AttributeDescriptors

Added: 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/AttributeTokenizer.java
URL: 
http://svn.apache.org/viewvc/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/AttributeTokenizer.java?view=auto&rev=520720
==============================================================================
--- 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/AttributeTokenizer.java
 (added)
+++ 
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/AttributeTokenizer.java
 Tue Mar 20 19:27:10 2007
@@ -0,0 +1,332 @@
+package org.apache.ojb.broker.util;
+
+/* Copyright 2002-2007 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.Map;
+
+import org.apache.commons.collections.map.LRUMap;
+
+/**
+ * This class help:
+ * <ul>
+ *     <li>
+ * to split query-attribute strings into token
+ * </li>
+ *     <li>
+ * to identify the type of the next or current token - an attribute, a 
function or delimiter.
+ * <br/>
+ * Attribute string: 'abs(sum(author.book.pages))' will be split to
+ * <br/>
+ * 'abs'-->noneAttr, '('-->noneAttr, 'sum'-->nonAttr, 
'author.book.pages'-->Attr ...
+ * </li>
+ *     <li>
+ * to delete functions and keywords from the query-attribute to get the "clean 
path" of the
+ * attribute string - see [EMAIL PROTECTED] #getCleanPath()}
+ * </li>
+ * </ul>
+ *
+ * @version $Id$
+ */
+public final class AttributeTokenizer
+{
+    /**
+     * Delimiters used to tokenize attributes.
+     */
+    private static final String DELIMITERS = "( ),+-/*";
+    private static final String STR_OPEN_BRAKE = "(";
+    private static final String STR_AS = "as";
+    private static final String STR_BLANK = " ";
+    private static final String STR_DISTINCT = "distinct";
+
+    private static final Map tokenListsMap = new LRUMap(500);
+
+    private final String attribute;
+    private final List tokenList;
+    private final int tokenListSize;
+    private int index;
+    private String cleanPath;
+
+    public AttributeTokenizer(String attribute)
+    {
+        this.attribute = attribute;
+        this.tokenList = getTokenList();
+        this.tokenListSize = this.tokenList.size();
+        reset();
+    }
+
+    /**
+     * Lookup the token list of the associated attribute string
+     * (Internal a LRUMap is used to cache the token lists of attributes)
+     *
+     * @return The token list of the attribute.
+     */
+    private List getTokenList()
+    {
+        List result = (List) tokenListsMap.get(attribute);
+        if(result == null)
+        {
+            result = new ArrayList();
+            StringTokenizer st = new StringTokenizer(attribute, DELIMITERS, 
true);
+            while(st.hasMoreTokens())
+            {
+                result.add(st.nextToken());
+            }
+            tokenListsMap.put(attribute, result);
+        }
+        return result;
+    }
+
+    /**
+     * Reset this class to initial state.
+     */
+    public void reset()
+    {
+        index = -1;
+    }
+
+    /**
+     * Return the current token string. Don't call this in initial state,
+     * at least the first [EMAIL PROTECTED] #next()} call has to be done.
+     *
+     * @return Return the current token string.
+     */
+    public String current()
+    {
+        return getToken(index);
+    }
+
+    /**
+     * Tests if there are more tokens available.
+     * If this method returns <tt>true</tt>, then a subsequent call to
+     * [EMAIL PROTECTED] #next() <tt>nextToken</tt>} will successfully
+     * return a token.
+     *
+     * @return  <code>true</code> if and only if there is at least one token 
string
+     *          in the attribute after the current position; <code>false</code>
+     *          otherwise.
+     */
+    public boolean hasNext()
+    {
+        return tokenListSize > 0 && index < tokenListSize - 1;
+    }
+
+    /**
+     * Returns the next token from the attribute string.
+     *
+     * @return The next token from the attribute string.
+     */
+    public String next()
+    {
+        skip();
+        return current();
+    }
+
+    /**
+     * Skip the next token from the attribute string.
+     */
+    public void skip()
+    {
+        ++index;
+    }
+
+    /**
+     * Answer <em>true</em> if the next token string is a query-attribute.
+     *
+     * @return The result of the attribute check.
+     */
+    public boolean nextIsAttribute()
+    {
+        boolean result = hasNext();
+        // expect all single word expressions are attributes
+        if(result && tokenListSize > 1)
+        {
+            int nextIndex = index + 1;
+            result = !isDelimiter(nextIndex) && !isFunction(nextIndex) && 
!isKeyword(nextIndex);
+        }
+        return result;
+    }
+
+    /**
+     * Answer <em>true</em> if the current token string is a query-attribute.
+     *
+     * @return The result of the attribute check.
+     */
+    public boolean currentIsAttribute()
+    {
+        boolean result = index > -1;
+        // expect all single word expressions are attributes
+        if(result && tokenListSize > 1)
+        {
+            result = !isDelimiter(index) && !isFunction(index) && 
!isKeyword(index);
+        }
+        return result;
+    }
+
+    /**
+     * Remove functions/keywords, '(' and ')' from path.
+     * <br/>
+     * <pre>
+     * attribute-str: 'id' --> 'id'
+     * attribute-str: 'sum(id)' --> 'id'
+     * attribute-str: 'sum ( id) ' --> 'id'
+     * attribute-str: '  sum ( id  ) ' --> 'id'
+     * attribute-str: 'abs(sum(id))' --> 'id'
+     * attribute-str: 'abs (sum(id  ))' --> 'id'
+     * attribute-str: 'count(distinct author.books.pages)' --> 
'author.books.pages'
+     * </pre>
+     *
+     * @return The "clean path" of the attribute string.
+     */
+    public String getCleanPath()
+    {
+        if(cleanPath == null)
+        {
+            int oldIndex = index;
+
+            try
+            {
+                reset();
+                String result = attribute;
+                while (hasNext())
+                {
+                    if (nextIsAttribute())
+                    {
+                        result = next();
+                        break;
+                    }
+                    else
+                    {
+                        // skip
+                        skip();
+                    }
+                }
+                cleanPath = result;
+            }
+            finally
+            {
+                index = oldIndex;
+            }
+        }
+        return cleanPath;
+    }
+
+    private boolean isFunction(int index)
+    {
+        String current = getToken(index);
+        return STR_OPEN_BRAKE.equals(getNextNonBlankToken(index))
+                && !(STR_OPEN_BRAKE.equals(current) || 
STR_BLANK.equals(current));
+    }
+
+    private boolean isKeyword(int index)
+    {
+        String token = getToken(index);
+        return (STR_AS.equals(token) || STR_DISTINCT.equals(token)) && 
!isDelimiter(getNextNonBlankToken(index));
+    }
+
+    private boolean isDelimiter(int index)
+    {
+        return isDelimiter(getToken(index));
+    }
+
+    private boolean isDelimiter(String str)
+    {
+        return str != null && DELIMITERS.indexOf(str) > -1;
+    }
+
+    private boolean isBlank(String str)
+    {
+        return str != null && STR_BLANK.equals(str);
+    }
+
+    private String getToken(int index)
+    {
+        return index < tokenListSize ? (String) tokenList.get(index) : null;
+    }
+
+    private String getNextNonBlankToken(int index)
+    {
+        String result = null;
+        for(int i = index + 1; i < tokenListSize; i++)
+        {
+            String str = (String) tokenList.get(i);
+            if(!isBlank(str))
+            {
+                result = str;
+                break;
+            }
+        }
+        return result;
+    }
+
+// arminw:
+// only useful for development!!
+//
+//    public static void main(String[] args)
+//    {
+//        printClean("id");
+//        printClean("sum(id)");
+//        printClean("sum ( id) ");
+//        printClean("  sum ( id  ) ");
+//        printClean("abs(sum(id))");
+//        printClean("abs (sum(id  ))");
+//        printClean("count(distinct id)");
+//        printClean("  count   (   distinct   id  )  ");
+//        printClean("  count   (   distinct   distinct  )  ");
+//        printClean("  count   (   distinct   as  )  ");
+//        printClean("((  count   (   distinct   as  )  ))");
+//        printClean("sum(curdate.sum)");
+//        printClean("abs(as)");
+//
+//        System.out.println("------------------------");
+//        printAttr("id");
+//        printAttr("sum(id)");
+//        printAttr("sum ( id) ");
+//        printAttr("  sum ( id  ) ");
+//        printAttr("abs(sum(id))");
+//        printAttr("abs (sum(id  ))");
+//        printAttr("count(distinct id)");
+//        printAttr("  count   (   distinct   id  )  ");
+//        printAttr("  count   (   distinct   distinct  )  ");
+//        printAttr("  count   (   distinct   as  )  ");
+//        printAttr("((  count   (   distinct   as  )  ))");
+//        printAttr("sum(curdate.sum)");
+//        printAttr("abs(as)");
+//
+//    }
+//
+//    private static void printClean(String str)
+//    {
+//        AttributeTokenizer t = new AttributeTokenizer(str);
+//        System.out.println("str: '" + t.attribute + "' --> '" + 
t.getCleanPath()+"'");
+//    }
+//
+//    private static void printAttr(String str)
+//    {
+//        AttributeTokenizer t = new AttributeTokenizer(str);
+//        System.out.println("## String: " + t.attribute);
+//        while(t.hasNext())
+//        {
+//            System.out.println("hasNext=" + t.hasNext() + ", nextIsAttr=" + 
t.nextIsAttribute()+ ", next=" + t.next()
+//                    + ", current=" + t.current() + ", currentIsAttr=" + 
t.currentIsAttribute());
+//        }
+//        System.out.println("--------------------------");
+//    }
+
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to