Package org.jpox.store.mapped.expression

Source Code of org.jpox.store.mapped.expression.ObjectLiteral$Index

/**********************************************************************
Copyright (c) 2003 Erik Bengtson and others. All rights reserved.
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.

Contributors:
2003 Andy Jefferson - coding standards
2007 Andy Jefferson - rewritten equality expression to allow for PC mapping recursion
    ...
**********************************************************************/
package org.jpox.store.mapped.expression;

import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;

import org.jpox.ClassLoaderResolver;
import org.jpox.ObjectManager;
import org.jpox.ObjectManagerHelper;
import org.jpox.StateManager;
import org.jpox.api.ApiAdapter;
import org.jpox.exceptions.JPOXException;
import org.jpox.exceptions.JPOXUserException;
import org.jpox.identity.OID;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.IdentityType;
import org.jpox.store.fieldmanager.FieldManager;
import org.jpox.store.fieldmanager.SingleValueFieldManager;
import org.jpox.store.mapped.DatastoreAdapter;
import org.jpox.store.mapped.DatastoreClass;
import org.jpox.store.mapped.MappedStoreManager;
import org.jpox.store.mapped.mapping.EmbeddedMapping;
import org.jpox.store.mapped.mapping.JavaTypeMapping;
import org.jpox.store.mapped.mapping.PersistenceCapableMapping;
import org.jpox.util.JPOXLogger;

/**
* Representation of an Object literal in a query.
*
* @version $Revision: 1.43 $
**/
public class ObjectLiteral extends ObjectExpression implements Literal
{
    private Object value;

    /** Raw value that this literal represents. */
    Object rawValue;

    // passed by parameters or variable in a query
    private String mappingClass;
   
    /**
     * Creates an Object literal
     * @param qs the QueryExpression
     * @param mapping the mapping
     * @param value the Object value
     */   
    public ObjectLiteral(QueryExpression qs, JavaTypeMapping mapping, Object value)
    {
        super(qs);

        st.appendParameter(mapping, value);
        this.mapping = mapping;
        this.value = value;
    }
   
    /**
     * Creates an Object literal
     * @param qs the QueryExpression
     * @param mapping the mapping
     * @param value the Object value
     * @param mappingClass the declared mapped class
     */   
    public ObjectLiteral(QueryExpression qs, JavaTypeMapping mapping, Object value, String mappingClass)
    {
        super(qs);

        st.appendParameter(mapping, value);
        this.value = value;
        this.mapping = mapping;
        this.mappingClass = mappingClass;
    }   

    public Object getValue()
    {
        return value;
    }

    /**
     * Method called when the query contains "object == value".
     * @param expr The expression
     * @return The resultant expression for this query relation
     */
    public BooleanExpression eq(ScalarExpression expr)
    {
        if (expr instanceof ObjectLiteral)
        {
            // Other side is a literal so just do an object comparison
            return new BooleanLiteral(qs, mapping, value.equals(((ObjectLiteral)expr).value));
        }
        else if (expr instanceof BooleanBitColumnExpression)
        {
            return null;
        }
        else if (expr instanceof ObjectExpression)
        {
            BooleanExpression bExpr = getEqualityExpressionForObjectExpression((ObjectExpression)expr);
            return bExpr;
        }
        else
        {
            return super.eq(expr);
        }
    }

    /**
     * Method called when the query contains "object NOTEQUALS value".
     * @param expr The expression
     * @return The resultant expression for this query relation
     */
    public BooleanExpression noteq(ScalarExpression expr)
    {
        if (expr instanceof ObjectLiteral)
        {
            return new BooleanLiteral(qs, mapping, !value.equals(((ObjectLiteral)expr).value));
        }
        else if (expr instanceof ObjectExpression)
        {
            BooleanExpression bExpr = getEqualityExpressionForObjectExpression((ObjectExpression)expr);
            bExpr = new BooleanExpression(this, OP_NOTEQ, bExpr);
            return bExpr;
        }
        else
        {
            return super.noteq(expr);
        }
    }

    /**
     * Convenience method to generate an equality expression with the passed ObjectExpression.
     * Used by the eq() and noteq() methods.
     * @param expr The ObjectExpression
     * @return The BooleanExpression for equality.
     */
    private BooleanExpression getEqualityExpressionForObjectExpression(ObjectExpression expr)
    {
        BooleanExpression bExpr = null;
        if (value == null)
        {
            bExpr = expr.eq(new NullLiteral(qs));
        }
        else
        {
            MappedStoreManager storeMgr = qs.getStoreManager();
            DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
            ClassLoaderResolver clr = qs.getClassLoaderResolver();
            if (value instanceof OID)
            {
                // Object is an OID
                JavaTypeMapping m = dba.getMapping(((OID)value).getKeyValue().getClass(), storeMgr, clr);
                ScalarExpression oidExpr =  m.newLiteral(qs,((OID)value).getKeyValue());
                bExpr = expr.expressionList.getExpression(0).eq(oidExpr);
            }
            else
            {
                ApiAdapter api = qs.getStoreManager().getApiAdapter();
                AbstractClassMetaData cmd = storeMgr.getOMFContext().getMetaDataManager().getMetaDataForClass(value.getClass(), clr);
                if (cmd == null)
                {
                    // if there is no metadata, we either have an SingleFieldIdentity, application identity, or any object
                    if (storeMgr.getApiAdapter().isSingleFieldIdentityClass(value.getClass().getName()))
                    {
                        // Object is SingleFieldIdentity
                        JavaTypeMapping m = dba.getMapping(api.getTargetClassForSingleFieldIdentity(value), storeMgr, clr);
                        ScalarExpression oidExpr =  m.newLiteral(qs, api.getTargetKeyForSingleFieldIdentity(value));
                        bExpr = expr.expressionList.getExpression(0).eq(oidExpr);
                    }
                    else
                    {
                        String pcClassName = storeMgr.getClassNameForObjectID(value, clr, null);
                        if (pcClassName != null)
                        {
                            // Object is an application identity
                            cmd = storeMgr.getOMFContext().getMetaDataManager().getMetaDataForClass(pcClassName, clr);
                            bExpr = eqApplicationIdentity(value, null, expr, null, storeMgr, clr);
                        }
                        else
                        {
                            // Value not PersistenceCapable nor an identity, so return nothing "(1 = 0)"
                            bExpr = new BooleanLiteral(qs, mapping, false).eq(new BooleanLiteral(qs, mapping, true));
                        }
                    }
                }
                else
                {
                    // Value is a PersistenceCapable
                    if (cmd.getIdentityType() == IdentityType.APPLICATION)
                    {
                        // Application identity
                        if (api.getIdForObject(value) != null)
                        {
                            // Persistent PC object (FCO)
                            // Cater for composite PKs and parts of PK being PC mappings, and recursion
                            JavaTypeMapping[] pkMappingsApp = new JavaTypeMapping[expr.expressionList.size()];
                            Object[] pkFieldValues = new Object[expr.expressionList.size()];
                            int position = 0;
                            for (int i=0;i<cmd.getNoOfPrimaryKeyMembers();i++)
                            {
                                AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(cmd.getPKMemberPositions()[i]);
                                Object fieldValue = getFieldValue(mmd, value);
                                JavaTypeMapping mapping = dba.getMapping(fieldValue.getClass(), storeMgr, clr);
                                if (mapping instanceof PersistenceCapableMapping)
                                {
                                    position = populatePrimaryKeyMappingsValuesForPCMapping(pkMappingsApp,
                                        pkFieldValues, position, (PersistenceCapableMapping)mapping,
                                        cmd, mmd, fieldValue, storeMgr, clr);
                                }
                                else
                                {
                                    pkMappingsApp[position] = mapping;
                                    pkFieldValues[position] = fieldValue;
                                    position++;
                                }
                            }

                            for (int i=0; i<expr.expressionList.size(); i++)
                            {
                                ScalarExpression source = expr.expressionList.getExpression(i);
                                ScalarExpression target = pkMappingsApp[i].newLiteral(qs, pkFieldValues[i]);
                                if (bExpr == null)
                                {
                                    bExpr = source.eq(target);
                                }
                                else
                                {
                                    bExpr = bExpr.and(source.eq(target));
                                }
                            }
                        }
                        else
                        {
                            // PC object with no id (embedded, or transient maybe)
                            for (int i=0; i<expr.expressionList.size(); i++)
                            {
                                // Query should return nothing (so just do "(1 = 0)")
                                JPOXLogger.QUERY.warn(LOCALISER.msg("037003", value));
                                bExpr = new BooleanLiteral(qs, mapping, false).eq(new BooleanLiteral(qs, mapping, true));
                                // It is arguable that we should compare the id with null (as below)
                                /*bExpr = expr.eq(new NullLiteral(qs));*/
                            }
                        }
                    }
                    else
                    {
                        // Datastore identity
                        for (int i=0; i<expr.expressionList.size(); i++)
                        {
                            ScalarExpression source = expr.expressionList.getExpression(i);
                            OID objectId = (OID)api.getIdForObject(value);
                            if (objectId == null)
                            {
                                // PC object with no id (embedded, or transient maybe)
                                // Query should return nothing (so just do "(1 = 0)")
                                JPOXLogger.QUERY.warn(LOCALISER.msg("037003", value));
                                bExpr = new BooleanLiteral(qs, mapping, false).eq(new BooleanLiteral(qs, mapping, true));
                                // It is arguable that we should compare the id with null (as below)
                                /*bExpr = expr.eq(new NullLiteral(qs));*/
                            }
                            else
                            {
                                JavaTypeMapping m = dba.getMapping(objectId.getKeyValue().getClass(), storeMgr, clr);
                                ScalarExpression oidExpr = m.newLiteral(qs, objectId.getKeyValue());
                                bExpr = source.eq(oidExpr);
                            }
                        }
                    }
                }
                if (expr.conditionExpr != null)
                {
                    bExpr = new BooleanExpression(expr.conditionExpr, OP_AND, bExpr);
                }
            }
        }
        return bExpr;
    }

    /**
     * Convenience method to populate PK mappings/values allowing for recursion where a PK field is itself
     * a PCMapping, that itself has PK mappings, which in turn may include PCMappings.
     * The pkMappings/pkFieldValues arrays are already created and we populate from "position".
     * @param pkMappings The array of pk mappings to be populated
     * @param pkFieldValues The array of pk field values to be populated
     * @param position The current position needing populating
     * @param pcMapping The PC mapping we are processing
     * @param cmd ClassMetaData for the owning class with this PCMapping field
     * @param mmd Field metadata for the field that this PCMapping represents
     * @param fieldValue The value for the PCMapping field in the owning object
     * @param storeMgr Store Manager
     * @param clr ClassLoader resolver
     * @return The current position (after our processing)
     */
    private int populatePrimaryKeyMappingsValuesForPCMapping(JavaTypeMapping[] pkMappings, Object[] pkFieldValues,
            int position, PersistenceCapableMapping pcMapping,
            AbstractClassMetaData cmd, AbstractMemberMetaData mmd, Object fieldValue,
            MappedStoreManager storeMgr, ClassLoaderResolver clr)
    {
        JavaTypeMapping[] subMappings = pcMapping.getJavaTypeMapping();
        if (subMappings.length == 0)
        {
            // Embedded PC has no PK so must be embedded-only so use mapping from owner table
            DatastoreClass table = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
            JavaTypeMapping ownerMapping = table.getFieldMapping(mmd);
            EmbeddedMapping embMapping = (EmbeddedMapping)ownerMapping;
            for (int k=0;k<embMapping.getNumberOfJavaTypeMappings();k++)
            {
                JavaTypeMapping subMapping = embMapping.getJavaTypeMapping(k);
                pkMappings[position] = subMapping;
                pkFieldValues[position] = getFieldValue(subMapping.getFieldMetaData(), fieldValue);
                position++;
            }
        }
        else
        {
            AbstractClassMetaData pcCmd = storeMgr.getOMFContext().getMetaDataManager().getMetaDataForClass(pcMapping.getType(), clr);
            int[] pcPkPositions = pcCmd.getPKMemberPositions();
            for (int k=0;k<subMappings.length;k++)
            {
                AbstractMemberMetaData pcMmd = pcCmd.getMetaDataForManagedMemberAtAbsolutePosition(pcPkPositions[k]);
                if (subMappings[k] instanceof PersistenceCapableMapping)
                {
                    Object val = getFieldValue(pcMmd, fieldValue);
                    position = populatePrimaryKeyMappingsValuesForPCMapping(pkMappings, pkFieldValues, position,
                        (PersistenceCapableMapping)subMappings[k], pcCmd, pcMmd, val, storeMgr, clr);
                }
                else
                {
                    Object val = getFieldValue(pcMmd, fieldValue);
                    pkMappings[position] = subMappings[k];
                    pkFieldValues[position] = val;
                    position++;
                }
            }
        }
        return position;
    }

    /**
     * Internal class to track indexes. Just used to pass references between calls
     * and increment the index value
     */
    private static class Index
    {
        int index;
    }
   
    /**
     * Create an equality expression for an application identity using reflection to retrieve values
     * and generate the mappings
     * @param id the id
     * @param bExpr the boolean equals expression
     * @param expr the object expression
     * @param index the current index in the source expression
     * @param storeMgr the StoreManager
     * @param clr the ClassLoaderResolver
     * @return the equals expression
     */
    private BooleanExpression eqApplicationIdentity(Object id, BooleanExpression bExpr, ScalarExpression expr,
            Index index, MappedStoreManager storeMgr, ClassLoaderResolver clr)
    {
        if( index == null)
        {
            index = new Index();
        }
        for (int i=0;i<id.getClass().getDeclaredFields().length;i++)
        {
            Object value = getFieldValue(id,id.getClass().getDeclaredFields()[i].getName());
            String pcClassName = storeMgr.getClassNameForObjectID(value, clr, null);
            if( pcClassName != null )
            {
                // if it is a PersistenceCapable ID, we run recursivelly this operation  
                if( bExpr == null )
                {
                    bExpr = eqApplicationIdentity(value, bExpr, expr, index, storeMgr, clr);
                }
                else
                {
                    bExpr = bExpr.and(eqApplicationIdentity(value, bExpr, expr, index, storeMgr, clr));
                }
            }
            else
            {
                //if a simple value, we simply apply the equals
                ScalarExpression source = expr.getExpressionList().getExpression(index.index);
                JavaTypeMapping mapping = storeMgr.getDatastoreAdapter().getMapping(value.getClass(), storeMgr, clr);
                ScalarExpression target = mapping.newLiteral(qs, value);
                if( bExpr == null )
                {
                    bExpr = source.eq(target);
                }
                else
                {
                    bExpr = bExpr.and(source.eq(target));
                }
                if( target.getExpressionList().size() == 0 )
                {
                    //TODO why getExpressionList().size() == 0
                    index.index++;
                }
                else
                {
                    index.index += target.getExpressionList().size();
                }
            }
        }
        return bExpr;
    }
    /**
     * Reads a field of an object passed by parameter to the query
     * @param subfieldName Name of the subfield
     * @param innerJoin whether to inner join
     * @return a new ScalarExpression from the field value
     */   
    public ScalarExpression accessField(String subfieldName, boolean innerJoin)
    {
        Object fieldValue = null;
        try
        {
            AbstractClassMetaData acmd = qs.getStoreManager().getOMFContext().getMetaDataManager().getMetaDataForClass(this.mappingClass,
                qs.getClassLoaderResolver());
            if( acmd == null )
            {
                //no pc classes
                fieldValue = getFieldValue(value, subfieldName);
            }
            else
            {
                AbstractMemberMetaData fmd =acmd.getMetaDataForMember(subfieldName);
                if( fmd == null )
                {
                    throw new JPOXUserException("Cannot access field "+subfieldName+" on type "+this.mappingClass);
                }
                fieldValue = getFieldValue(fmd, value);
            }
        }
        catch (Exception e)
        {
            fieldValue = getFieldValue(value, subfieldName);
        }

        try
        {
            if (fieldValue == null)
            {
                return new NullLiteral(this.qs);
            }
            DatastoreAdapter dba = qs.getStoreManager().getDatastoreAdapter();
            JavaTypeMapping mapping;
            if (mappingClass != null && subfieldName == null)
            {
                mapping = dba.getMapping(qs.getClassLoaderResolver().classForName(mappingClass), qs.getStoreManager(),
                    qs.getClassLoaderResolver());
            }
            else
            {
                mapping = dba.getMapping(fieldValue.getClass(), qs.getStoreManager(), qs.getClassLoaderResolver());               
            }
            return mapping.newLiteral(qs,fieldValue);
        }
        catch (SecurityException e)
        {
            throw new JPOXUserException("Cannot access field: "+subfieldName,e);
        }
        catch (IllegalArgumentException e)
        {
            throw new JPOXUserException("Cannot access field: "+subfieldName,e);
        }
        catch (Exception e)
        {
            throw new JPOXUserException("Cannot access field: "+subfieldName+" " +e,e);
        }      
    }

    public String toString()
    {
        return super.toString() + " = " + value.toString();
    }
   
    /**
     * Helper method to retrieve the java.lang.reflect.Field
     * @param clazz the Class instance of the declaring class or interface
     * @param fieldName the field name
     * @return The field
     */
    private Field getDeclaredFieldPrivileged(final Class clazz, final String fieldName)
    {
        if ((clazz == null) || (fieldName == null))
        {
            return null;
        }

        return (Field) AccessController.doPrivileged(
            new PrivilegedAction()
            {
                public Object run ()
                {
                    Class seekingClass = clazz;
                    do
                    {
                      try
                      {
                          return seekingClass.getDeclaredField(fieldName);
                      }
                      catch (SecurityException ex)
                      {
                          throw new JPOXException("CannotGetDeclaredField",ex).setFatal();
                      }
                      catch (NoSuchFieldException ex)
                      {
                          // do nothing, we will return null later if no
                          // field is found in this class or superclasses
                      }
                      catch (LinkageError ex)
                      {
                          throw new JPOXException("ClassLoadingError",ex).setFatal();
                      }
                      seekingClass = seekingClass.getSuperclass();
                    } while(seekingClass != null);

                    //no field found
                    return null;
                }
            }
            );
    }

    /**
     * Get the field value of a managed field/property.
     * @param fmd metadata for the field/property
     * @param object the pc object
     * @return The field value
     */
    private Object getFieldValue(AbstractMemberMetaData fmd, Object object)
    {
        ObjectManager om = ObjectManagerHelper.getObjectManager(object);
        if (om == null)
        {
            return getFieldValue(object, fmd.getName());
        }
        StateManager sm = om.findStateManager(object);
        FieldManager fm = new SingleValueFieldManager();

        if (!fmd.isPrimaryKey())
        {
            // we expect that primary key field are non null
            om.getApiAdapter().isLoaded(sm, fmd.getAbsoluteFieldNumber());
        }
        sm.provideFields(new int[] {fmd.getAbsoluteFieldNumber()},fm);

        return fm.fetchObjectField(fmd.getAbsoluteFieldNumber());
    }

    private Object getFieldValue(Object object, String fieldName)
    {
        Object fieldValue;
        final Field field = getDeclaredFieldPrivileged(object.getClass(), fieldName);
        if (field == null)
        {
            throw new JPOXUserException("Cannot access field: " + fieldName + " in type " + object.getClass());
        }

        try
        {
            // if the field is not accessible, try to set the accessible flag.
            if (!field.isAccessible())
            {
                try
                {
                    AccessController.doPrivileged(
                        new PrivilegedAction()
                        {
                            public Object run()
                            {
                                field.setAccessible(true);
                                return null;
                            }
                        });
                }
                catch (SecurityException ex)
                {
                    throw new JPOXException("Cannot access field: " + fieldName,ex).setFatal();
                }
            }
            fieldValue = field.get(object);
        }
        catch (IllegalArgumentException e2)
        {
            throw new JPOXUserException("Cannot access field: " + fieldName,e2);
        }
        catch (IllegalAccessException e2)
        {
            throw new JPOXUserException("Cannot access field: " + fieldName,e2);
        }
        return fieldValue;
    }

    /**
     * Method to save a "raw" value that this literal represents.
     * This value differs from the literal value since that is of the same type as this literal.
     * @param val The raw value
     */
    public void setRawValue(Object val)
    {
        this.rawValue = val;
    }

    /**
     * Accessor for the "raw" value that this literal represents.
     * This value differs from the literal value since that is of the same type as this literal.
     * @return The raw value
     */
    public Object getRawValue()
    {
        return rawValue;
    }
}
TOP

Related Classes of org.jpox.store.mapped.expression.ObjectLiteral$Index

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.