Package org.datanucleus.store.mapped.expression

Source Code of org.datanucleus.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.datanucleus.store.mapped.expression;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ObjectManager;
import org.datanucleus.StateManager;
import org.datanucleus.api.ApiAdapter;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.identity.OID;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.IdentityType;
import org.datanucleus.store.fieldmanager.FieldManager;
import org.datanucleus.store.fieldmanager.SingleValueFieldManager;
import org.datanucleus.store.mapped.DatastoreClass;
import org.datanucleus.store.mapped.MappedStoreManager;
import org.datanucleus.store.mapped.mapping.EmbeddedMapping;
import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
import org.datanucleus.store.mapped.mapping.PersistenceCapableMapping;
import org.datanucleus.util.ClassUtils;
import org.datanucleus.util.NucleusLogger;

/**
* Representation of an Object literal in a query.
**/
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();
            ClassLoaderResolver clr = qs.getClassLoaderResolver();
            if (value instanceof OID)
            {
                // Object is an OID
                JavaTypeMapping m = storeMgr.getMappingManager().getMappingWithDatastoreMapping(
                    ((OID)value).getKeyValue().getClass(), false, false, 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 = storeMgr.getMappingManager().getMappingWithDatastoreMapping(
                            api.getTargetClassForSingleFieldIdentity(value), false, false, 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, cmd);
                        }
                        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 = storeMgr.getMappingManager().getMappingWithDatastoreMapping(
                                    fieldValue.getClass(), false, false, 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)")
                                NucleusLogger.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)")
                                NucleusLogger.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 = storeMgr.getMappingManager().getMappingWithDatastoreMapping(
                                    objectId.getKeyValue().getClass(), false, false, 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.getMemberMapping(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.getMemberMetaData(), 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
     * @param acmd MetaData for the class the object id represents
     * @return the equals expression
     */
    private BooleanExpression eqApplicationIdentity(Object id, BooleanExpression bExpr, ScalarExpression expr,
            Index index, MappedStoreManager storeMgr, ClassLoaderResolver clr, AbstractClassMetaData acmd)
    {
        if (index == null)
        {
            index = new Index();
        }

        String[] pkFieldNames = acmd.getPrimaryKeyMemberNames();
        for (int i=0;i<pkFieldNames.length;i++)
        {
            Object value = ClassUtils.getValueOfFieldByReflection(id, pkFieldNames[i]);
            String pcClassName = storeMgr.getClassNameForObjectID(value, clr, null);
            if (pcClassName != null)
            {
                // This part is the id of a PC class (compound identity), so recurse
                AbstractClassMetaData scmd = storeMgr.getOMFContext().getMetaDataManager().getMetaDataForClass(pcClassName, clr);
                if (bExpr == null)
                {
                    bExpr = eqApplicationIdentity(value, bExpr, expr, index, storeMgr, clr, scmd);
                }
                else
                {
                    bExpr = bExpr.and(eqApplicationIdentity(value, bExpr, expr, index, storeMgr, clr, scmd));
                }
            }
            else
            {
                //if a simple value, we simply apply the equals
                ScalarExpression source = expr.getExpressionList().getExpression(index.index);
                JavaTypeMapping mapping = storeMgr.getMappingManager().getMappingWithDatastoreMapping(
                    value.getClass(), false, false, 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 = ClassUtils.getValueOfFieldByReflection(value, subfieldName);
            }
            else
            {
                AbstractMemberMetaData fmd =acmd.getMetaDataForMember(subfieldName);
                if( fmd == null )
                {
                    throw new NucleusUserException("Cannot access field "+subfieldName+" on type "+this.mappingClass);
                }
                fieldValue = getFieldValue(fmd, value);
            }
        }
        catch (Exception e)
        {
            fieldValue = ClassUtils.getValueOfFieldByReflection(value, subfieldName);
        }

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

    public String toString()
    {
        return super.toString() + " = " + value.toString();
    }
   
    /**
     * 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 = qs.getStoreManager().getApiAdapter().getObjectManager(object);
        if (om == null)
        {
            return ClassUtils.getValueOfFieldByReflection(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());
    }

    /**
     * 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.datanucleus.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.