You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by wi...@apache.org on 2007/07/19 02:45:53 UTC

svn commit: r557437 - in /openjpa/trunk: openjpa-jdbc-5/src/main/java/org/apache/openjpa/jdbc/meta/ openjpa-jdbc-5/src/main/java/org/apache/openjpa/meta/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ openjpa-jdbc/src/main/java/org/apa...

Author: wisneskid
Date: Wed Jul 18 17:45:51 2007
New Revision: 557437

URL: http://svn.apache.org/viewvc?view=rev&rev=557437
Log:
OPENJPA-240  XMLMapping Query support for persistent field maps to XML column.

Added:
    openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/jdbc/meta/XMLMappingRepository.java
    openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/meta/
    openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/meta/XMLClassMetaData.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMapping.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMetaData.java
Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EndsWithExpression.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValue.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValueImpl.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/StartsWithExpression.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java

Added: openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/jdbc/meta/XMLMappingRepository.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/jdbc/meta/XMLMappingRepository.java?view=auto&rev=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/jdbc/meta/XMLMappingRepository.java (added)
+++ openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/jdbc/meta/XMLMappingRepository.java Wed Jul 18 17:45:51 2007
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.    
+ */
+package org.apache.openjpa.jdbc.meta;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.XMLClassMetaData;
+import org.apache.openjpa.meta.XMLMapping;
+
+/**
+ * Repository of object/relational mapping information.
+ *  (extended to include XML mapping metadata for XML columns)
+ *  
+ * @author Catalina Wei
+ * @since 1.0.0
+ */
+public class XMLMappingRepository extends MappingRepository {
+    // xml mapping
+    protected final XMLMapping[] EMPTY_XMLMETAS;
+    private final Map _xmlmetas = new HashMap();
+
+    public XMLMappingRepository() {
+        super();
+        EMPTY_XMLMETAS = newXMLClassMetaDataArray(0);
+    }
+    
+    public synchronized XMLClassMetaData addXMLClassMetaData(FieldMetaData fmd, 
+        String name) {        
+        XMLClassMetaData meta = newXMLClassMetaData(fmd, name);
+        addXMLClassMetaData(fmd.getDeclaredType(), meta);
+        return meta;
+    }
+    
+    public XMLMapping getXMLClassMetaData(Class cls) {
+        synchronized(_xmlmetas) {
+            if (_xmlmetas.isEmpty())
+                return null;
+            else
+                return (XMLClassMetaData) _xmlmetas.get(cls);
+        }
+    }
+    
+    public XMLMapping getXMLMetaData(FieldMetaData fmd) {
+        XMLMapping xmlmeta = null;
+        if (XMLClassMetaData.isXMLMapping(fmd.getDeclaredType())) {
+            xmlmeta = getXMLClassMetaData(fmd.getDeclaredType());
+            if (xmlmeta == null)
+                xmlmeta = addXMLClassMetaData(fmd, fmd.getName());
+        }
+        return xmlmeta;
+    }
+    
+    public synchronized void addXMLClassMetaData(Class cls, XMLMapping meta) {
+        _xmlmetas.put(cls, meta);
+    }    
+    
+    protected XMLClassMetaData newXMLClassMetaData(FieldMetaData fmd, String name) {
+        return new XMLClassMetaData(fmd.getDeclaredType(), name, this);
+    }
+        
+    protected XMLMapping[] newXMLClassMetaDataArray(int length) {
+        return new XMLClassMetaData[length];
+    }
+}

Added: openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/meta/XMLClassMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/meta/XMLClassMetaData.java?view=auto&rev=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/meta/XMLClassMetaData.java (added)
+++ openjpa/trunk/openjpa-jdbc-5/src/main/java/org/apache/openjpa/meta/XMLClassMetaData.java Wed Jul 18 17:45:51 2007
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.    
+ */
+package org.apache.openjpa.meta;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Member;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.openjpa.jdbc.meta.XMLMappingRepository;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.meta.XMLMapping;
+import org.apache.openjpa.meta.XMLMetaData;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Contains metadata about a persistent field that maps to an xml column.
+ * This metadata is loaded at runtime when query involves predicates
+ * that navigate through xpath.
+ *
+ * @author Catalina Wei
+ * @since 1.0.0
+ */
+public class XMLClassMetaData implements XMLMapping     
+{
+    private Class _type;
+    private int _code = JavaTypes.OBJECT;
+    private int _xmltype = XMLTYPE;
+    private String _name = null;
+    private String _xmlname = null;
+    private String _xmlnamespace = null;
+    private boolean _isXMLRootElement = false;
+    private HashMap _fieldMap = new HashMap();
+    
+    /**
+     * Constructor.
+     * 
+     * @param type the class that contains XmlType annotation.
+     * @name  the persistent field name that maps to xml column
+     * @param repo the meta repository.
+     */
+    public XMLClassMetaData(Class type, String name, XMLMappingRepository repos) {
+       _type = type;
+       _isXMLRootElement = _type.getAnnotation(XmlRootElement.class) != null;
+       if (_isXMLRootElement) {
+           _xmlname = ((XmlRootElement) _type.getAnnotation
+                   (XmlRootElement.class)).name();
+           _xmlnamespace = ((XmlRootElement) _type.getAnnotation
+                   (XmlRootElement.class)).namespace();
+       }
+       else {
+           _xmlname = ((XmlType) _type.getAnnotation
+                   (XmlType.class)).name();
+           _xmlnamespace = ((XmlType) _type.getAnnotation
+                   (XmlType.class)).namespace();
+           _name = name;
+       }
+       populateFromReflection(_type, repos);
+    }
+    
+    /**
+     * Constructor. Supply described type and repository.
+     * 
+     * @param type the class that contains XmlType annotation.
+     * @param repo the meta repository.
+     */
+    protected XMLClassMetaData(Class type, XMLMappingRepository repos) {
+        _type = type;
+        _isXMLRootElement = _type.getAnnotation(XmlRootElement.class) != null;
+        if (_isXMLRootElement) {
+            _xmlname = ((XmlRootElement) _type.getAnnotation
+                    (XmlRootElement.class)).name();
+            _xmlnamespace = ((XmlRootElement) _type.getAnnotation
+                    (XmlRootElement.class)).namespace();
+        }
+        else {
+            _xmlname = ((XmlType) _type.getAnnotation
+                    (XmlType.class)).name();
+            _xmlnamespace = ((XmlType) _type.getAnnotation
+                    (XmlType.class)).namespace();           
+        }
+        populateFromReflection(_type, repos);
+        repos.addXMLClassMetaData(type, this);
+    }
+
+    /**
+     * Given a class type return true if XmlType annotation exists
+     * @param type
+     * @return true if XmlType annotation is present else false.
+     */
+    public static boolean isXMLMapping(Class type) {
+        return type.isAnnotationPresent(XmlType.class);
+    }
+    
+    public void setName(String name) {
+        _name = name;
+    }
+    
+    public String getName() {
+        return _name;
+    }    
+    
+    public void setXmlname(String name) {
+        _xmlname = name;
+    }
+    
+    public String getXmlname() {
+        return _isXMLRootElement ? null : _xmlname;
+    }
+
+    public void setXmlnamespace(String name) {
+        // avoid JAXB XML bind default name
+        if (!StringUtils.equals(defaultName, name))
+            _xmlnamespace = name;
+    }
+    
+    public String getXmlnamespace() {
+        return _xmlnamespace;
+    }
+
+    public boolean isXmlRootElement() {
+        return _isXMLRootElement;
+    }
+    
+    public boolean isXmlElement() {
+        return false;
+    }
+    
+    public boolean isXmlAttribute() {
+        return false;
+    }
+    
+    public XMLMapping getFieldMapping(String name) {
+        return (XMLMapping) _fieldMap.get(name);
+    }
+    
+    public void setType(Class type) {
+        _type = type;
+    }
+    
+    public Class getType() {
+        return _type;
+    }
+    
+    public int getTypeCode() {
+        return _code;
+    }
+
+    public void setXmltype(int type) {
+        _xmltype = type;
+    }
+    public int getXmltype() {
+        return _xmltype;
+    }
+
+    private synchronized void populateFromReflection(Class cls, 
+        XMLMappingRepository repos) {
+        Member[] members;
+        if (((XmlAccessorType)cls.getAnnotation(XmlAccessorType.class)).value()
+                == XmlAccessType.FIELD)
+            members = cls.getDeclaredFields();
+        else
+            members = cls.getDeclaredMethods();
+        for (int i = 0; i < members.length; i++) {
+            Member member = members[i];
+            AnnotatedElement el = (AnnotatedElement) member;
+            XMLMapping field = null;
+            if (el.getAnnotation(XmlElement.class) != null) {
+                String xmlname = el.getAnnotation(XmlElement.class).name();
+                // avoid JAXB XML bind default name
+                if (StringUtils.equals(defaultName, xmlname))
+                    xmlname = member.getName();
+                if (((Field) member).getType().
+                        isAnnotationPresent(XmlType.class)) {
+                    field = new XMLClassMetaData(((Field) member).getType(),
+                            repos);
+                    field.setXmltype(XMLTYPE);
+                    field.setXmlname(xmlname);
+                }
+                else {
+                    field = new XMLMetaData();
+                    field.setXmltype(ELEMENT);
+                    field.setXmlname(xmlname);
+                    field.setXmlnamespace(el.getAnnotation(XmlElement.class)
+                            .namespace());                    
+                }
+            }
+            else if (el.getAnnotation(XmlAttribute.class) != null) {
+                field = new XMLMetaData();
+                field.setXmltype(XMLMetaData.ATTRIBUTE);
+                String xmlname = el.getAnnotation(XmlAttribute.class).name();
+                // avoid JAXB XML bind default name
+                if (StringUtils.equals(defaultName, xmlname))
+                    xmlname = member.getName();
+                field.setXmlname("@"+xmlname);
+                field.setXmlnamespace(el.getAnnotation(XmlAttribute.class)
+                        .namespace());                
+            }
+            field.setName(member.getName());
+            field.setType(((Field) member).getType());                
+            _fieldMap.put(member.getName(), field);
+        }        
+    }
+}

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java Wed Jul 18 17:45:51 2007
@@ -41,6 +41,10 @@
         return false;
     }
 
+    public boolean isXPath() {
+        return false;
+    }
+
     public Object toDataStoreValue(Select sel, ExpContext ctx, ExpState state, 
         Object val) {
         return val;

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java Wed Jul 18 17:45:51 2007
@@ -31,6 +31,7 @@
 import org.apache.openjpa.kernel.exps.ExpressionVisitor;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.XMLMapping;
 import org.apache.openjpa.util.InternalException;
 
 /**
@@ -203,5 +204,15 @@
         public ConstPathExpState(ExpState constantState) {
             this.constantState = constantState;
         }
+    }
+    
+    public void get(FieldMetaData fmd, XMLMapping meta) {
+    }
+
+    public void get(XMLMapping meta, String name) {
+    }
+
+    public XMLMapping getXmlMapping() {
+        return null;
     }
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EndsWithExpression.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EndsWithExpression.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EndsWithExpression.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EndsWithExpression.java Wed Jul 18 17:45:51 2007
@@ -28,6 +28,7 @@
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
 import org.apache.openjpa.jdbc.sql.Select;
 import org.apache.openjpa.kernel.exps.ExpressionVisitor;
+import org.apache.openjpa.meta.XMLMapping;
 
 /**
  * Test if one string ends with another.
@@ -192,6 +193,14 @@
         }
 
         public FieldMapping getFieldMapping() {
+            return null;
+        }
+        
+        public PCPath getXPath() {
+            return null;
+        }
+        
+        public XMLMapping getXmlMapping() {
             return null;
         }
     }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValue.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValue.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValue.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValue.java Wed Jul 18 17:45:51 2007
@@ -23,6 +23,7 @@
 import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.meta.XMLMapping;
 
 /**
  * The simplified public view of any non-operator in a query filter,
@@ -103,4 +104,16 @@
      * return null.
      */
     public FieldMapping getFieldMapping();
+    
+    /**
+     * If this is an XPath, return it,
+     * else return null;
+     */
+    public PCPath getXPath();
+    
+    /**
+     * If this is an XPath, return XML mapping metadata,
+     * else return null;
+     */
+    public XMLMapping getXmlMapping();
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValueImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValueImpl.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValueImpl.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/FilterValueImpl.java Wed Jul 18 17:45:51 2007
@@ -24,6 +24,7 @@
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
 import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.meta.XMLMapping;
 
 /**
  * Implementation of {@link FilterValue} that wraps a {@link Val}.
@@ -97,5 +98,16 @@
 
     public FieldMapping getFieldMapping() {
         return (isPath()) ? ((PCPath) _val).getFieldMapping(_state) : null;
+    }
+    
+    public PCPath getXPath() {
+        if (isPath() && ((PCPath) _val).isXPath())
+            return (PCPath) _val;
+        else
+            return null;
+    }
+    
+    public XMLMapping getXmlMapping() {
+        return (getXPath() == null) ? null : getXPath().getXmlMapping();
     }
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java Wed Jul 18 17:45:51 2007
@@ -40,6 +40,7 @@
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
 import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.meta.XMLMapping;
 import org.apache.openjpa.util.UserException;
 
 /**
@@ -55,6 +56,7 @@
     private static final int BOUND_VAR = 1;
     private static final int UNBOUND_VAR = 2;
     private static final int UNACCESSED_VAR = 3;
+    private static final int XPATH = 4;
 
     private static final Localizer _loc = Localizer.forPackage(PCPath.class);
 
@@ -66,6 +68,7 @@
     private String _varName = null;
     private Class _cast = null;
     private boolean _cid = false;
+    private FieldMetaData _xmlfield = null;
 
     /**
      * Return a path starting with the 'this' ptr.
@@ -168,7 +171,40 @@
     public boolean isKey() {
         return _key;
     }
-
+    
+    public boolean isXPath() {
+        return _type == XPATH;
+    }
+    
+    public String getXPath() {
+        StringBuffer xpath = new StringBuffer();
+        Action action;
+        Iterator itr = _actions.iterator();
+        
+        // Skip variable actions since they are not part of the xpath
+        // until we reach the first xpath action.
+        // The first xpath action maps to the root of an xml document.
+        do 
+            action = (Action) itr.next(); 
+        while (action.op != Action.GET_XPATH);
+        
+        // Skip XmlRootElement:
+        // We can't rely on the accuracy of the name of the root element,
+        // because it could be set to some default by JAXB XML Binding.
+        // The caller(DBDictionary) should start with "/*" or "/*/",
+        // we build the remaining xpath that follows the root element.
+        while (itr.hasNext()) {
+            action = (Action) itr.next();
+            if (((XMLMapping) action.data).getXmlname() != null)                 
+                xpath.append(((XMLMapping) action.data).getXmlname());
+            else
+                xpath.append("*");
+            if (itr.hasNext())
+                xpath.append("/");
+        }
+        return xpath.toString();
+    }
+    
     public String getPath() {
         if (_actions == null)
             return (_varName == null) ? "" : _varName + ".";
@@ -274,6 +310,36 @@
         _cast = null;
         _key = false;
     }
+    
+    public void get(FieldMetaData fmd, XMLMapping meta) {
+        if (_actions == null)
+            _actions = new LinkedList();
+        Action action = new Action();
+        action.op = Action.GET_XPATH;
+        action.data = meta;
+        _actions.add(action);
+        _cast = null;
+        _key = false;;
+        _type = XPATH;
+        _xmlfield = fmd;
+    }
+    
+    public void get(XMLMapping meta, String name) {
+        Action action = new Action();
+        action.op = Action.GET_XPATH;
+        action.data = meta.getFieldMapping(name);
+        _actions.add(action);
+        _cast = null;
+        _key = false;;
+        _type = XPATH;
+    }
+    
+    public XMLMapping getXmlMapping() {
+        Action act = (Action) _actions.getLast();
+        if (act != null)
+            return (XMLMapping) act.data;
+        return null;
+    }
 
     public synchronized void getKey() {
         if (_cid)
@@ -288,7 +354,8 @@
 
     public FieldMetaData last() {
         Action act = lastFieldAction();
-        return (act == null) ? null : (FieldMetaData) act.data;
+        return (act == null) ? null : isXPath() ? _xmlfield :
+            (FieldMetaData) act.data;
     }
 
     /**
@@ -298,6 +365,9 @@
         if (_actions == null)
             return null;
 
+        if (isXPath())
+            return (Action) _actions.getLast();
+        
         ListIterator itr = _actions.listIterator(_actions.size());
         Action prev;
         while (itr.hasPrevious()) {
@@ -313,6 +383,9 @@
         if (_cast != null)
             return _cast;
         Action act = lastFieldAction();
+        if (act != null && act.op == Action.GET_XPATH)
+            return ((XMLMapping) act.data).getType();
+        
         FieldMetaData fld = (act == null) ? null : (FieldMetaData) act.data;
         boolean key = act != null && act.op == Action.GET_KEY;
         if (fld != null) {
@@ -373,7 +446,8 @@
                     rel.getTable());
             } else {
                 // move past the previous field, if any
-                field = (FieldMapping) action.data;
+                field = (action.op == Action.GET_XPATH) ? (FieldMapping) _xmlfield :
+                    (FieldMapping) action.data;
                 if (pstate.field != null) {
                     // if this is the second-to-last field and the last is
                     // the related field this field joins to, no need to
@@ -416,6 +490,9 @@
                         from = from.getJoinablePCSuperclassMapping())
                         pstate.joins = from.joinSuperclass(pstate.joins, false);
                 }
+                // nothing more to do from here on as we encountered an xpath action
+                if (action.op == Action.GET_XPATH)
+                    break;
             }
         }
         if (_varName != null)
@@ -534,6 +611,8 @@
         PathExpState pstate = (PathExpState) state;
         FieldMapping field = (pstate.cmpfield != null) ? pstate.cmpfield 
             : pstate.field;
+        if (isXPath())
+            return val;
         if (field != null) {
             if (_key)
                 return field.toKeyDataStoreValue(val, ctx.store);
@@ -639,6 +718,9 @@
         // (e.g., during a bulk update)
         if (sel == null)
             sql.append(col.getName());
+        else if (_type == XPATH)
+            // if this is an xpath, append xpath string
+            sql.append(getXPath());
         else
             sql.append(sel.getColumnAlias(col, state.joins));
     }
@@ -716,6 +798,7 @@
         public static final int SUBQUERY = 4;
         public static final int UNBOUND_VAR = 5;
         public static final int CAST = 6;
+        public static final int GET_XPATH = 7;
 
         public int op = -1;
         public Object data = null;

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/StartsWithExpression.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/StartsWithExpression.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/StartsWithExpression.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/StartsWithExpression.java Wed Jul 18 17:45:51 2007
@@ -28,6 +28,7 @@
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
 import org.apache.openjpa.jdbc.sql.Select;
 import org.apache.openjpa.kernel.exps.ExpressionVisitor;
+import org.apache.openjpa.meta.XMLMapping;
 import serp.util.Numbers;
 
 /**
@@ -184,6 +185,15 @@
         public FieldMapping getFieldMapping() {
             return null;
         }
+        
+        public PCPath getXPath() {
+            return null;
+        }
+        
+        public XMLMapping getXmlMapping() {
+            return null;
+        }
+
     }
 
     /**
@@ -258,6 +268,14 @@
         }
 
         public FieldMapping getFieldMapping() {
+            return null;
+        }
+        
+        public PCPath getXPath() {
+            return null;
+        }
+        
+        public XMLMapping getXmlMapping() {
             return null;
         }
     }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java Wed Jul 18 17:45:51 2007
@@ -22,13 +22,17 @@
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
+import java.sql.Types;
 import java.util.Arrays;
 import java.util.StringTokenizer;
 import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
 import org.apache.openjpa.jdbc.schema.Sequence;
 import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.util.OpenJPAException;
 import org.apache.openjpa.util.UnsupportedException;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
 
 /**
  * Dictionary for IBM DB2 database.
@@ -491,5 +495,121 @@
 
     public int getDb2ServerType() {
         return db2ServerType;
+    }
+    
+    protected void appendLength(SQLBuffer buf, int type) {
+        if (type == Types.VARCHAR)
+            buf.append("(").append(Integer.toString(characterColumnSize)).
+                append(")");
+    }
+
+    /**
+     * If this dictionary supports XML type,
+     * use this method to append xml predicate.
+     * 
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison
+     * @param rhs the right hand side of the comparison
+     * @param lhsxml indicates whether the left operand maps to xml
+     * @param rhsxml indicates whether the right operand maps to xml
+     */
+    public void appendXmlComparison(SQLBuffer buf, String op, FilterValue lhs,
+        FilterValue rhs, boolean lhsxml, boolean rhsxml) {
+        super.appendXmlComparison(buf, op, lhs, rhs, lhsxml, rhsxml);
+        if (lhsxml && rhsxml)
+            appendXmlComparison2(buf, op, lhs, rhs);
+        else if (lhsxml)
+            appendXmlComparison1(buf, op, lhs, rhs);
+        else 
+            appendXmlComparison1(buf, op, rhs, lhs);
+    }
+
+    /**
+     * Append an xml comparison predicate.
+     *
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison (maps to xml column)
+     * @param rhs the right hand side of the comparison
+     */
+    private void appendXmlComparison1(SQLBuffer buf, String op, 
+            FilterValue lhs, FilterValue rhs) {
+        boolean castrhs = false;
+        Class rc = Filters.wrap(rhs.getType());
+        int type = 0;
+        if (rhs.isConstant()) {
+            type = getJDBCType(JavaTypes.getTypeCode(rc), false);
+            castrhs = true;
+        }
+        
+        appendXmlExists(buf, lhs);
+
+        buf.append(" ").append(op).append(" ");
+        
+        buf.append("$");
+        if (castrhs)
+            buf.append("Parm");
+        else
+            rhs.appendTo(buf);
+        
+        buf.append("]' PASSING ");
+        appendXmlVar(buf, lhs);
+        buf.append(", ");
+        
+        if (castrhs)
+            appendCast(buf, rhs, type);
+        else
+            rhs.appendTo(buf);
+        
+        buf.append(" AS \"");
+        if (castrhs)
+            buf.append("Parm");
+        else
+            rhs.appendTo(buf);
+        buf.append("\")");
+    }
+    
+    /**
+     * Append an xml comparison predicate. (both operands map to xml column)
+     *
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison (maps to xml column)
+     * @param rhs the right hand side of the comparison (maps to xml column)
+     */
+    private void appendXmlComparison2(SQLBuffer buf, String op, 
+            FilterValue lhs, FilterValue rhs) {
+        appendXmlExists(buf, lhs);
+        
+        buf.append(" ").append(op).append(" ");
+        
+        buf.append("$").append(rhs.getColumnAlias(
+            rhs.getFieldMapping().getColumns()[0])).
+            append("/*/");
+        rhs.appendTo(buf);
+        
+        buf.append("]' PASSING ");
+        appendXmlVar(buf, lhs);
+        buf.append(", ");
+        appendXmlVar(buf, rhs);
+        buf.append(")");
+    }
+    
+    private void appendXmlVar(SQLBuffer buf, FilterValue val) {
+        buf.append(val.getColumnAlias(
+            val.getFieldMapping().getColumns()[0])).
+            append(" AS ").
+            append("\"").append(val.getColumnAlias(
+            val.getFieldMapping().getColumns()[0])).
+            append("\"");        
+    }
+    
+    private void appendXmlExists(SQLBuffer buf, FilterValue val) {
+        buf.append("XMLEXISTS('");
+        buf.append("$").append(val.getColumnAlias(
+            val.getFieldMapping().getColumns()[0])).
+            append("/*[");
+        val.appendTo(buf);        
     }
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java Wed Jul 18 17:45:51 2007
@@ -84,6 +84,7 @@
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.jdbc.schema.Unique;
 import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.kernel.exps.Path;
 import org.apache.openjpa.lib.conf.Configurable;
 import org.apache.openjpa.lib.conf.Configuration;
 import org.apache.openjpa.lib.jdbc.ConnectionDecorator;
@@ -2456,6 +2457,12 @@
      */
     public void comparison(SQLBuffer buf, String op, FilterValue lhs,
         FilterValue rhs) {
+        boolean lhsxml = lhs.getXPath() != null;
+        boolean rhsxml = rhs.getXPath() != null;
+        if (lhsxml || rhsxml) {
+            appendXmlComparison(buf, op, lhs, rhs, lhsxml, rhsxml);
+            return;
+        }
         boolean castlhs = false;
         boolean castrhs = false;
         Class lc = Filters.wrap(lhs.getType());
@@ -2485,6 +2492,15 @@
     }
 
     /**
+     * If this dictionary supports XML type,
+     * use this method to append xml predicate.
+     */
+    public void appendXmlComparison(SQLBuffer buf, String op, FilterValue lhs,
+        FilterValue rhs, boolean lhsxml, boolean rhsxml) {
+        assertSupport(supportsXMLColumn, "SupportsXMLColumn");
+    }
+
+    /**
      * Append SQL for the given numeric value to the buffer, casting as needed.
      */
     protected void appendNumericCast(SQLBuffer buf, FilterValue val) {
@@ -2518,9 +2534,13 @@
         val.appendTo(buf);
         buf.append(mid);
         buf.append(getTypeName(type));
+        appendLength(buf, type);
         buf.append(post);
     }
     
+    protected void appendLength(SQLBuffer buf, int type) {        
+    }
+
     ///////////
     // DDL SQL
     ///////////

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java Wed Jul 18 17:45:51 2007
@@ -1038,4 +1038,63 @@
             return false;
         }
     }
+    
+    /**
+     * If this dictionary supports XML type,
+     * use this method to append xml predicate.
+     * 
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison
+     * @param rhs the right hand side of the comparison
+     */
+    public void appendXmlComparison(SQLBuffer buf, String op, FilterValue lhs,
+        FilterValue rhs, boolean lhsxml, boolean rhsxml) {
+        super.appendXmlComparison(buf, op, lhs, rhs, lhsxml, rhsxml);
+        if (lhsxml && rhsxml)
+            appendXmlComparison2(buf, op, lhs, rhs);
+        else if (lhsxml)
+            appendXmlComparison1(buf, op, lhs, rhs);
+        else 
+            appendXmlComparison1(buf, op, rhs, lhs);
+    }
+    
+    /**
+     * Append an xml comparison predicate
+     *
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison (maps to xml column)
+     * @param rhs the right hand side of the comparison
+     */
+    private void appendXmlComparison1(SQLBuffer buf, String op,
+        FilterValue lhs, FilterValue rhs) {
+        appendXmlExtractValue(buf, lhs);
+        buf.append(" ").append(op).append(" ");
+        rhs.appendTo(buf);
+    }
+    
+    /**
+     * Append an xml comparison predicate (both operands map to xml column)
+     *
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison (maps to xml column)
+     * @param rhs the right hand side of the comparison (maps to xml column)
+     */
+    private void appendXmlComparison2(SQLBuffer buf, String op, 
+        FilterValue lhs, FilterValue rhs) {
+        appendXmlExtractValue(buf, lhs);
+        buf.append(" ").append(op).append(" ");
+        appendXmlExtractValue(buf, rhs);
+    }
+    
+    private void appendXmlExtractValue(SQLBuffer buf, FilterValue val) {
+        buf.append("extractValue(").
+            append(val.getColumnAlias(
+            val.getFieldMapping().getColumns()[0])).
+            append(",'/*/");
+        val.appendTo(buf);
+        buf.append("')");
+    }
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java Wed Jul 18 17:45:51 2007
@@ -23,8 +23,11 @@
 import java.sql.SQLException;
 import java.sql.Types;
 
+import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
+import org.apache.openjpa.kernel.Filters;
 import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.JavaTypes;
 
 /**
  * Dictionary for MS SQLServer.
@@ -133,5 +136,98 @@
                 cols[i].setType(Types.CLOB);
         }
         return cols;
+    }
+    
+    protected void appendLength(SQLBuffer buf, int type) {
+        if (type == Types.VARCHAR)
+            buf.append("(").append(Integer.toString(characterColumnSize)).append(")");
+    }
+
+    /**
+     * If this dictionary supports XML type,
+     * use this method to append xml predicate.
+     * 
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison
+     * @param rhs the right hand side of the comparison
+     * @param lhsxml indicates whether the left operand maps to xml
+     * @param rhsxml indicates whether the right operand maps to xml
+     */
+    public void appendXmlComparison(SQLBuffer buf, String op, FilterValue lhs,
+        FilterValue rhs, boolean lhsxml, boolean rhsxml) {
+        super.appendXmlComparison(buf, op, lhs, rhs, lhsxml, rhsxml);
+        if (lhsxml && rhsxml)
+            appendXmlComparison2(buf, op, lhs, rhs);
+        else if (lhsxml)
+            appendXmlComparison1(buf, op, lhs, rhs);
+        else 
+            appendXmlComparison1(buf, op, rhs, lhs);
+    }
+    /**
+     * Append an xml comparison predicate
+     *
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison (maps to xml column)
+     * @param rhs the right hand side of the comparison
+     */
+    private void appendXmlComparison1(SQLBuffer buf, String op,
+        FilterValue lhs, FilterValue rhs) {
+        boolean castrhs = rhs.isConstant();
+        if (castrhs)
+            appendXmlValue(buf, lhs);
+        else
+            appendXmlExist(buf, lhs);
+        buf.append(" ").append(op).append(" ");
+        if (castrhs)
+            rhs.appendTo(buf);
+        else {
+            buf.append("sql:column(\"");
+            rhs.appendTo(buf);
+            buf.append("\")").
+                append("]') = 1");
+        }
+    }
+    
+    private void appendXmlExist(SQLBuffer buf, FilterValue lhs) {
+        buf.append(lhs.getColumnAlias(
+            lhs.getFieldMapping().getColumns()[0])).
+            append(".exist('").
+            append("/*[");
+        lhs.appendTo(buf);    
+    }
+    
+    /**
+     * Append an xml comparison predicate (both operands map to xml column)
+     *
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison (maps to xml column)
+     * @param rhs the right hand side of the comparison (maps to xml column)
+     */
+    private void appendXmlComparison2(SQLBuffer buf, String op, 
+        FilterValue lhs, FilterValue rhs) {
+        appendXmlValue(buf, lhs);
+        buf.append(" ").append(op).append(" ");
+        appendXmlValue(buf, rhs);
+    }
+    
+    private void appendXmlValue(SQLBuffer buf, FilterValue val) {
+        Class rc = Filters.wrap(val.getType());
+        int type = getJDBCType(JavaTypes.getTypeCode(rc), false);
+        boolean isXmlAttribute = (val.getXmlMapping() == null) ? false
+                : val.getXmlMapping().isXmlAttribute();
+        buf.append(val.getColumnAlias(
+            val.getFieldMapping().getColumns()[0])).
+            append(".value(").
+            append("'(/*/");
+        val.appendTo(buf);
+        if (!isXmlAttribute)
+            buf.append("/text()");
+        buf.append(")[1]','").
+            append(getTypeName(type));
+        appendLength(buf, type);
+        buf.append("')");
     }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java Wed Jul 18 17:45:51 2007
@@ -30,6 +30,8 @@
 import org.apache.openjpa.lib.util.Localizer.Message;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.meta.XMLMapping;
 import org.apache.openjpa.util.InternalException;
 import org.apache.openjpa.util.OpenJPAException;
 import org.apache.openjpa.util.UnsupportedException;
@@ -243,6 +245,27 @@
     protected Value traversePath(Path path, String field) {
         return traversePath(path, field, false, false);
     }
+    
+    protected Value traverseXPath(Path path, String field) {
+        XMLMapping meta = path.getXmlMapping();
+        if (meta.getFieldMapping(field) == null) {
+            throw parseException(EX_USER, "no-field",
+                    new Object[]{ meta.getType(), field }, null);
+        }
+        else {
+            // collection-valued xpath is not allowed
+            int type = meta.getFieldMapping(field).getTypeCode();
+            switch (type) {
+                case JavaTypes.ARRAY:
+                case JavaTypes.COLLECTION:
+                case JavaTypes.MAP:
+                    throw new UserException(_loc.get("collection-valued-path",
+                            field));
+            }
+        }
+        path.get(meta, field);
+        return path;
+    }
 
     /**
      * Traverse the given field in the given path.
@@ -272,6 +295,14 @@
             addAccessPath(meta);
             path.setMetaData(meta);
         }
+        else {
+            // xmlsupport xpath
+            XMLMapping xmlmeta = fmd.getRepository().getXMLMetaData(fmd);
+            if (xmlmeta != null) {
+                path.get(fmd, xmlmeta);
+                return path;
+            }
+        }
 
         if (meta != null || !pcOnly)
             path.get(fmd, allowNull);
@@ -309,11 +340,11 @@
 
         if (o1 && !o2) {
             val1.setImplicitType(c2);
-            if (val1.getMetaData() == null)
+            if (val1.getMetaData() == null && !val1.isXPath())
                 val1.setMetaData(val2.getMetaData());
         } else if (!o1 && o2) {
             val2.setImplicitType(c1);
-            if (val2.getMetaData() == null)
+            if (val2.getMetaData() == null && !val1.isXPath())
                 val2.setMetaData(val1.getMetaData());
         } else if (o1 && o2 && expected != null) {
             // we never expect a pc type, so don't bother with metadata

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java Wed Jul 18 17:45:51 2007
@@ -30,6 +30,7 @@
 import org.apache.openjpa.kernel.StoreContext;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.XMLMapping;
 
 /**
  * A path represents a traversal into fields of a candidate object.
@@ -184,4 +185,14 @@
             return ((Traversal) other).field.equals(field);
         }
 	}
+
+    public void get(FieldMetaData fmd, XMLMapping meta) {
+    }
+    
+    public void get(XMLMapping meta, String name) {
+    }
+    
+    public XMLMapping getXmlMapping() {
+        return null;
+    }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java Wed Jul 18 17:45:51 2007
@@ -19,6 +19,7 @@
 package org.apache.openjpa.kernel.exps;
 
 import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.XMLMapping;
 
 /**
  * A path represents a traversal into fields of a candidate object.
@@ -42,4 +43,28 @@
      * not contain a final field.
      */
     public FieldMetaData last();
+
+    /**
+     * Traverse into the given field that maps to xml column, and update
+     * the current object to that field value.
+     * 
+     * @param fmd field maps to xml column
+     * @param meta associated xml mapping
+     */
+    public void get(FieldMetaData fmd, XMLMapping meta);
+    
+    /**
+     * Traverse into the gevin xpath name of the current object, and update
+     * the current object to that xpath field.
+     * 
+     * @param meta
+     * @param name
+     */
+    public void get(XMLMapping meta, String name);
+    
+    /**
+     * Return the current XPath's xmlmapping metadata.
+     * @return Return xmlmapping
+     */
+    public XMLMapping getXmlMapping();
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java Wed Jul 18 17:45:51 2007
@@ -109,6 +109,10 @@
     public boolean isAggregate() {
         return false;
     }
+    
+    public boolean isXPath() {
+        return false;
+    }
 
     public void acceptVisit(ExpressionVisitor visitor) {
         visitor.enter(this);

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java Wed Jul 18 17:45:51 2007
@@ -52,6 +52,11 @@
     public boolean isAggregate();
 
     /**
+     * Return true if this value is an XML Path.
+     */
+    public boolean isXPath();
+    
+    /**
      * Return any associated persistent type.
      */
     public ClassMetaData getMetaData();

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java Wed Jul 18 17:45:51 2007
@@ -1088,7 +1088,7 @@
         if (fmd == null)
             return;
 
-        Class type = fmd.getType();
+        Class type = path.isXPath() ? path.getType() : fmd.getType();
         if (type == null)
             return;
 
@@ -1298,6 +1298,11 @@
         // walk through the children and assemble the path
         boolean allowNull = !inner;
         for (int i = 1; i < node.children.length; i++) {
+            if (path.isXPath()) {
+                for (int j = i; j <node.children.length; j++)
+                    path = (Path) traverseXPath(path, node.children[j].text);
+                return path;
+            }
             path = (Path) traversePath(path, node.children[i].text, pcOnly,
                 allowNull);
 

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java?view=diff&rev=557437&r1=557436&r2=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java Wed Jul 18 17:45:51 2007
@@ -1850,4 +1850,13 @@
 				&& StringUtils.equals (name, qk.name);	
 		}
 	}
+    
+    /**
+     * Return XML metadata for a given field metadata
+     * @param fmd
+     * @return null
+     */
+    public XMLMapping getXMLMetaData(FieldMetaData fmd) {
+        return null;
+    }
 }

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMapping.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMapping.java?view=auto&rev=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMapping.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMapping.java Wed Jul 18 17:45:51 2007
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.    
+ */
+package org.apache.openjpa.meta;
+
+import java.io.Serializable;
+
+/**
+ * Describe metadata about an xml type.
+ * 
+ * @author Catalina Wei
+ * @since 1.0.0
+ */
+public interface XMLMapping extends Serializable {
+    /**
+     * JAXB XML binding default name
+     */
+    public static final String defaultName = "##default";
+    public static final int XMLTYPE = 0;
+    public static final int ELEMENT = 1;
+    public static final int ATTRIBUTE = 2;
+
+    /**
+     * Return true if mapping on an XmlRootElement.
+     */
+    public boolean isXmlRootElement();
+
+    /**
+     * Return true if mapping on an XmlElement.
+     */
+    public boolean isXmlElement();
+
+    /**
+     * Return true if mapping on an XmlAttribute.
+     */
+    public boolean isXmlAttribute();
+    
+    /**
+     * Return XMLMapping for a given field.
+     * @param name the field name.
+     * @return XMLMapping.
+     */
+    public XMLMapping getFieldMapping(String name); 
+    
+    /**
+     * Set type.
+     */
+    public void setType(Class type);
+
+    /**
+     * Return type.
+     */
+    public Class getType();
+
+    /**
+     * Return type code.
+     */
+    public int getTypeCode();
+
+    /**
+     * Return the mapping name.
+     */
+    public String getName();
+
+    /**
+     * Return xml element tag name or xml attribute name.
+     */
+    public String getXmlname();
+
+    /**
+     * Return xml namespace.
+     */
+    public String getXmlnamespace();
+
+    /**
+     * Set field name.
+     * @param name the field name.
+     */
+    public void setName(String name);
+
+    /**
+     * Set xml element or attribute name.
+     * @param name the element name or attribute name
+     */
+    public void setXmlname(String name);
+
+    /**
+     * Set namespace.
+     * @param namespace
+     */
+    public void setXmlnamespace(String namespace);
+
+    /**
+     * Set xmltype
+     * @param type XMLTYPE, ELEMENT, or ATTRIBUTE
+     */
+    public void setXmltype(int type);
+
+    /**
+     * Return xmltype
+     * @return xmltype
+     */
+    public int getXmltype();
+}

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMetaData.java?view=auto&rev=557437
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMetaData.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/XMLMetaData.java Wed Jul 18 17:45:51 2007
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.    
+ */
+package org.apache.openjpa.meta;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Contains metadata about an xml element or attribute
+ *
+ * @author Catalina Wei
+ * @since 1.0.0
+ */
+public class XMLMetaData implements XMLMapping {
+
+    private String _name;
+    private String _xmlname = null;
+    private String _xmlnamespace = null;
+    private Class _decType = Object.class;
+    private int _decCode = JavaTypes.OBJECT;
+    private Class _type = Object.class;
+    private int _code = JavaTypes.OBJECT;
+    private int _xmltype;    
+
+    public XMLMetaData() {        
+    }
+    
+    public Class getType() {
+        return (_type == null) ? _decType : _type;
+    }
+
+    public void setType(Class type) {
+        _type = type;
+        if (type != null)
+            setTypeCode(JavaTypes.getTypeCode(type));
+    }
+
+    public int getTypeCode() {
+        return (_type == null) ? _decCode : _code;
+    }
+
+    // set JavaTypes code
+    public void setTypeCode(int code) {
+        _code = code;
+    }
+    
+    public void setName(String name) {
+        _name = name;
+    }
+    
+    public String getName() {
+        return _name;
+    }
+    
+    public void setXmlname(String name) {
+        _xmlname = name;
+    }
+    
+    public String getXmlname() {
+        return _xmlname;
+    }
+    
+    public void setXmlnamespace(String name) {
+        // avoid JAXB XML bind default name
+        if (!StringUtils.equals(defaultName, name))
+            _xmlnamespace = name;
+    }
+    
+    public String getXmlnamespace() {
+        return _xmlnamespace;
+    }
+    
+    public void setXmltype(int type) {
+        _xmltype = type;
+    }
+    
+    public int getXmltype() {
+        return _xmltype;
+    }
+    
+    public boolean isXmlRootElement() {
+        return false;
+    }
+    
+    public boolean isXmlElement() {
+        return _xmltype == ELEMENT;
+    }
+    
+    public boolean isXmlAttribute() {
+        return _xmltype == ATTRIBUTE;
+    }
+    
+    public XMLMapping getFieldMapping(String name) {
+        return null;
+    }
+}