Package org.jpox.store.rdbms.query

Source Code of org.jpox.store.rdbms.query.ResultMetaDataROF

/**********************************************************************
Copyright (c) 2007 Andy Jefferson 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:
    ...
**********************************************************************/
package org.jpox.store.rdbms.query;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jpox.FetchPlan;
import org.jpox.ObjectManager;
import org.jpox.StateManager;
import org.jpox.exceptions.JPOXDataStoreException;
import org.jpox.exceptions.JPOXUserException;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.IdentityType;
import org.jpox.metadata.QueryResultMetaData;
import org.jpox.metadata.QueryResultMetaData.PersistentTypeMapping;
import org.jpox.store.FieldValues;
import org.jpox.store.mapped.DatastoreClass;
import org.jpox.store.mapped.DatastoreField;
import org.jpox.store.mapped.MappedStoreManager;
import org.jpox.store.mapped.StatementExpressionIndex;
import org.jpox.store.mapped.mapping.JavaTypeMapping;
import org.jpox.store.query.ResultObjectFactory;
import org.jpox.store.rdbms.RDBMSManager;
import org.jpox.store.rdbms.fieldmanager.ResultSetGetter;
import org.jpox.util.JPOXLogger;
import org.jpox.util.Localiser;

/**
* ResultObjectFactory that operates using a QueryResultMetaData and returns objects based on the definition.
* A QueryResultMetaData allows for a row of a ResultSet to be returned as a mix of :-
* <ul>
* <li>a number of persistent objects (made up of several ResultSet columns)</li>
* <li>a number of Objects (from individual ResultSet columns)</li>
* </ul>
* Each call to getObject() will then return a set of objects as per the MetaData definition.
* <h3>ResultSet to object mapping</h3>
* Each row of the ResultSet has a set of columns, and these columns are either used for direct outputting
* back to the user as a "simple" object, or as a field in a persistent object. So you could have a situation
* like this :-
* <pre>
* ResultSet Column   Output Object
* ================   =============
* COL1               PC1.field1
* COL2               PC1.field2
* COL3               Simple Object
* COL4               PC2.field3
* COL5               PC2.field1
* COL6               PC2.field2
* COL7               Simple Object
* COL8               PC1.field3
* ...
* </pre>
* So this example will return an Object[4] ... Object[0] = instance of PC1, Object[1] = instance of PC2,
* Object[2] = simple object, Object[3] = simple object.
* When creating the instance of PC1 we take the ResultSet columns (COL1, COL2, COL8).
* When creating the instance of PC2 we take the ResultSet columns (COL5, COL6, COL4).
*
* @version $Revision: 1.9 $
*/
public class ResultMetaDataROF implements ResultObjectFactory
{
    /** Localisation of messages. */
    protected static final Localiser LOCALISER = Localiser.getInstance("org.jpox.store.rdbms.Localisation",
        RDBMSManager.class.getClassLoader());

    /** MetaData defining the result from the Query. */
    QueryResultMetaData queryResultMetaData = null;
    String[] columnNames = null;

    private boolean ignoreCache = false;

    /**
     * Constructor.
     * @param qrmd MetaData defining the results from the query.
     */
    public ResultMetaDataROF(QueryResultMetaData qrmd)
    {
        this.queryResultMetaData = qrmd;
    }

    /**
     * Accessor for the object(s) from a row of the ResultSet.
     * @param om ObjectManager
     * @param rs ResultSet
     * @return The object(s) for this row of the ResultSet.
     */
    public Object getObject(ObjectManager om, Object rs)
    {
        List returnObjects = new ArrayList();
        if( columnNames == null )
        {
            try
            {
                //obtain column names
                ResultSetMetaData rsmd = ((ResultSet)rs).getMetaData();
                int columnCount = rsmd.getColumnCount();
                columnNames = new String[columnCount];
                for( int i=0; i<columnCount; i++)
                {
                    columnNames[i] = rsmd.getColumnName(i+1);
                }
            }
            catch(SQLException ex)
            {
                throw new JPOXDataStoreException("Error obtaining objects",ex);
            }
        }

        // A). Process persistent types
        PersistentTypeMapping[] persistentTypes = queryResultMetaData.getPersistentTypeMappings();
        MappedStoreManager storeMgr = (MappedStoreManager)om.getStoreManager();
        if (persistentTypes != null)
        {
            int startColumnIndex = 0;
            for (int i=0;i<persistentTypes.length;i++)
            {
                int[] fieldNumbers;   
                StatementExpressionIndex[] statementExpressionIndex;
                Set columnsInThisType = new HashSet();
                AbstractMemberMetaData[] fmds = new AbstractMemberMetaData[columnNames.length];
                Map fieldColumns = new HashMap();
                DatastoreClass dc = storeMgr.getDatastoreClass(persistentTypes[i].getClassName(),om.getClassLoaderResolver());
                AbstractClassMetaData acmd = om.getMetaDataManager().getMetaDataForClass(persistentTypes[i].getClassName(), om.getClassLoaderResolver());
                Object id = null;
                for (int j=startColumnIndex;j<columnNames.length;j++)
                {
                    if( columnsInThisType.contains(columnNames[j]) )
                    {
                        //already added this column, so must be another persistent type
                        startColumnIndex = j;
                        break;
                    }

                    boolean found = false;
                    if (acmd.getIdentityType() == IdentityType.DATASTORE)
                    {
                        DatastoreField df = dc.getDataStoreObjectIdMapping().getDataStoreMapping(0).getDatastoreField();
                        if( df.getIdentifier().getIdentifier().equals(columnNames[j]))
                        {
                            //add +1 because result sets in jdbc starts with 1
                            int datastoreIdentityExpressionIndex = j+1;
                            //get object id if datastore identifier
                            if( dc.getDataStoreObjectIdMapping() != null )
                            {
                                id = dc.getDataStoreObjectIdMapping().getObject(om, rs, new int[] {datastoreIdentityExpressionIndex});
                            }
                            found=true;
                        }
                    }
                    for(int k=0; k<acmd.getNoOfManagedMembers()+acmd.getNoOfInheritedManagedMembers() && !found; k++)
                    {
                        AbstractMemberMetaData apmd = acmd.getMetaDataForManagedMemberAtAbsolutePosition(k);
                        if( persistentTypes[i].getColumnForField(apmd.getName())!=null )
                        {
                            if(persistentTypes[i].getColumnForField(apmd.getName()).equals(columnNames[j]))
                            {
                                fieldColumns.put(columnNames[j], apmd);
                                columnsInThisType.add(columnNames[j]);
                                fmds[j] = apmd;
                                found = true;
                            }
                        }
                        else
                        {
                            JavaTypeMapping mapping = dc.getFieldMapping(apmd);
                            for(int l=0; l<mapping.getDataStoreMappings().length && !found; l++)
                            {
                                DatastoreField df = mapping.getDataStoreMapping(l).getDatastoreField();
                                if( df.getIdentifier().getIdentifier().equals(columnNames[j]))
                                {
                                    fieldColumns.put(columnNames[j], apmd);
                                    columnsInThisType.add(columnNames[j]);
                                    fmds[j] = apmd;
                                    found = true;
                                }
                            }
                        }
                    }
                    if( !columnsInThisType.contains(columnNames[j]) )
                    {
                       
                        //column not found in this type, so must be another persistent type
                        startColumnIndex = j;
                        break;
                    }
                }
               
                //build StatementExpressionIndex
                Set fields = new HashSet();
                fields.addAll(fieldColumns.values());
                statementExpressionIndex = new StatementExpressionIndex[acmd.getNoOfManagedMembers() + acmd.getNoOfInheritedManagedMembers()];
                fieldNumbers = new int[fields.size()];
                Iterator it = fields.iterator();
                int j=0;
                while (it.hasNext())
                {
                    AbstractMemberMetaData apmd = (AbstractMemberMetaData)it.next();
                    fieldNumbers[j] = apmd.getAbsoluteFieldNumber();
                    statementExpressionIndex[fieldNumbers[j]] = new StatementExpressionIndex();
                    List indexes = new ArrayList();
                    for( int k=0; k<fmds.length; k++)
                    {
                        if( fmds != null && fmds[k] == apmd)
                        {
                            indexes.add(new Integer(k));
                        }
                    }
                    int[] indxs = new int[indexes.size()];
                    for( int k=0; k<indxs.length; k++)
                    {
                        //add +1 because result sets in jdbc starts with 1
                        indxs[k] = ((Integer)indexes.get(k)).intValue()+1;
                    }
                   
                    statementExpressionIndex[fieldNumbers[j]].setExpressionIndex(indxs);
                    statementExpressionIndex[fieldNumbers[j]].setMapping(dc.getFieldMapping(apmd));
                    j++;
                   
                }
                Object obj = null;
                Class type = om.getClassLoaderResolver().classForName(persistentTypes[i].getClassName());
                if (acmd.getIdentityType() == IdentityType.APPLICATION)
                {
                    obj = getObjectByAID(om, (ResultSet)rs, fieldNumbers, acmd, type, false, statementExpressionIndex);
                }
                else if (acmd.getIdentityType() == IdentityType.DATASTORE)
                {
                    obj = getObjectById(om, (ResultSet)rs, fieldNumbers, acmd, id, type, statementExpressionIndex);
                }
                returnObjects.add(obj);
            }
           
        }

        // B). Process simple columns
        String[] columns = queryResultMetaData.getScalarColumns();
        if (columns != null)
        {
            for (int i=0;i<columns.length;i++)
            {
                try
                {
                    Object obj = getResultObject((ResultSet)rs, columns[i]);
                    returnObjects.add(obj);
                }
                catch (SQLException sqe)
                {
                    String msg = LOCALISER.msg("059027", sqe.getMessage());
                    JPOXLogger.QUERY.error(msg);
                    throw new JPOXUserException(msg, sqe);
                }
            }
        }

        if (returnObjects.size() == 0)
        {
            // No objects so user must have supplied incorrect MetaData
            return null;
        }
        else if (returnObjects.size() == 1)
        {
            // Return Object
            return returnObjects.get(0);
        }
        else
        {
            // Return Object[]
            return returnObjects.toArray(new Object[returnObjects.size()]);
        }
    }
   
   
   
    /**
     * Convenience method to read the value of a column out of the ResultSet.
     * @param rs ResultSet
     * @param columnName Name of the column
     * @return Value for the column for this row.
     * @throws SQLException Thrown if an error occurs on reading
     */
    private Object getResultObject(final ResultSet rs, String columnName)
    throws SQLException
    {
        return rs.getObject(columnName);
    }
   
    /**
     * Returns a PC instance from a ResultSet row with an application identity.
     * @param om ObjectManager
     * @param rs The ResultSet
     * @param fieldNumbers Numbers of the fields (of the class) found in the ResultSet
     * @param cmd MetaData for the class
     * @param pcClass PersistenceCapable class
     * @param requiresInheritanceCheck Whether we need to check the inheritance level of the returned object
     * @return The object with this application identity
     */
    private Object getObjectByAID(final ObjectManager om, final ResultSet rs, final int[] fieldNumbers,
            AbstractClassMetaData cmd, Class pcClass, boolean requiresInheritanceCheck, StatementExpressionIndex[] statementExpressionIndex)
    {
        final StatementExpressionIndex[] stmtExprIndex = statementExpressionIndex;           
        return om.findObjectUsingAID(pcClass, new FieldValues()
        {
            public void fetchFields(StateManager sm)
            {
                sm.replaceFields(fieldNumbers, new ResultSetGetter(sm, rs, stmtExprIndex), false);
            }
            public void fetchNonLoadedFields(StateManager sm)
            {
                sm.replaceNonLoadedFields(fieldNumbers, new ResultSetGetter(sm, rs, stmtExprIndex));
            }
            public FetchPlan getFetchPlanForLoading()
            {
                return om.getFetchPlan();
            }
        }, ignoreCache, requiresInheritanceCheck);
    }

    /**
     * Returns a PC instance from a ResultSet row with a datastore identity.
     * @param om ObjectManager
     * @param rs The ResultSet
     * @param fieldNumbers Numbers of the fields (of the class) found in the ResultSet
     * @param cmd MetaData for the class
     * @param oid The object id
     * @param pcClass The PersistenceCapable class (where we know the instance type required, null if not)
     * @return The Object
     */
    private Object getObjectById(final ObjectManager om, final ResultSet rs, final int[] fieldNumbers,
            AbstractClassMetaData cmd, Object oid, Class pcClass, StatementExpressionIndex[] statementExpressionIndex)
    {
        final StatementExpressionIndex[] stmtExprIndex = statementExpressionIndex;
        if (pcClass == null)
        {
            return om.findObject(oid, new FieldValues()
            {
                public void fetchFields(StateManager sm)
                {
                    sm.replaceFields(fieldNumbers, new ResultSetGetter(sm, rs, stmtExprIndex), false);
                }
                public void fetchNonLoadedFields(StateManager sm)
                {
                    sm.replaceNonLoadedFields(fieldNumbers, new ResultSetGetter(sm, rs, stmtExprIndex));
                }
                public FetchPlan getFetchPlanForLoading()
                {
                    return om.getFetchPlan();
                }
            });
        }
        else
        {
            return om.findObject(oid, new FieldValues()
            {
                public void fetchFields(StateManager sm)
                {
                    sm.replaceFields(fieldNumbers, new ResultSetGetter(sm, rs, stmtExprIndex), false);
                }
                public void fetchNonLoadedFields(StateManager sm)
                {
                    sm.replaceNonLoadedFields(fieldNumbers, new ResultSetGetter(sm, rs, stmtExprIndex));
                }
                public FetchPlan getFetchPlanForLoading()
                {
                    return om.getFetchPlan();
                }
            }, pcClass, ignoreCache);
        }
    }
   
}
TOP

Related Classes of org.jpox.store.rdbms.query.ResultMetaDataROF

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.