FetchGroupBuilder.java :  » Testing » PolePosition-0.20 » com » versant » core » metadata » Java Open Source

Java Open Source » Testing » PolePosition 0.20 
PolePosition 0.20 » com » versant » core » metadata » FetchGroupBuilder.java

/*
 * Copyright (c) 1998 - 2005 Versant Corporation
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Versant Corporation - initial API and implementation
 */
package com.versant.core.metadata;

import com.versant.core.common.Debug;
import com.versant.core.metadata.parser.JdoElement;
import com.versant.core.metadata.parser.JdoExtension;
import com.versant.core.metadata.parser.JdoExtensionKeys;

import java.util.*;

import com.versant.core.common.BindingSupportImpl;

/**
 * This is used by MetaDataBuilder to construct fetch groups. Putting all
 * the fetch group stuff in one file should add some much needed sanity.
 */
public class FetchGroupBuilder {

    private final ModelMetaData jmd;
    private final boolean sendCurrentForFGWithSecFields;
    private final boolean readObjectBeforeWrite;

    public FetchGroupBuilder(ModelMetaData jmd,
            boolean sendCurrentForFGWithSecFields, boolean readObjectBeforeWrite) {
        this.jmd = jmd;
        this.sendCurrentForFGWithSecFields = sendCurrentForFGWithSecFields;
        this.readObjectBeforeWrite = readObjectBeforeWrite;
    }

    protected StoreFetchGroup createStoreFetchGroup() {
        return null;
    }

    /**
     * Return the first fetch-group extension in a or null if none.
     */
    public JdoExtension findFetchGroupExt(JdoExtension[] a) {
        if (a == null) return null;
        int n = a.length;
        for (int i = 0; i < n; i++) {
            if (a[i].key == JdoExtensionKeys.FETCH_GROUP) return a[i];
        }
        return null;
    }

    /**
     * Build all the fetch groups. This must be called once all the fields for
     * each class have been created (including fake fields etc.).
     */
    public void buildFetchGroups(boolean quiet) {
        ClassMetaData[] classes = jmd.classes;
        int clen = classes.length;

        // create all the groups with their field arrays
        if (Debug.DEBUG) System.out.println("MDB-FGB: Creating fetch groups");
        for (int i = 0; i < clen; i++) {
            ClassMetaData cmd = classes[i];
            try {
                if (cmd.pcSuperMetaData == null) createFetchGroups(cmd, quiet);
            } catch (RuntimeException e) {
                cmd.addError(e, quiet);
            }
        }

        // resolve next-fetch-group references etc
        if (Debug.DEBUG) {
            System.out.println(
                    "MDB-FGB: Resolving next-fetch-group references");
        }
        for (int i = 0; i < clen; i++) {
            ClassMetaData cmd = classes[i];
            try {
                processFetchGroups(cmd);
            } catch (RuntimeException e) {
                cmd.addError(e, quiet);
            }
        }

        // Set the sendFieldsOnFetch on FetchGroup's with secondaryField's
        // if required by the DataStore for the class. Also sets the
        // hasPrimaryFields flag on all FetchGroups.
        for (int i = 0; i < clen; i++) {
            ClassMetaData cmd = classes[i];
            // todo Commenting out these lines appeared to make no difference
//             if (cmd.pcSuperMetaData != null && cmd.vdsClass == null) {
//               continue;
//            }
            FetchGroup[] fetchGroups = cmd.fetchGroups;
            if (fetchGroups == null) {
                continue;
            }
            for (int j = fetchGroups.length - 1; j >= 0; j--) {
                FetchGroup fg = fetchGroups[j];
                if (sendCurrentForFGWithSecFields && !fg.hasPrimaryFields(true)
                        && fg.hasSecondaryFields()) {
                    fg.setSendFieldsOnFetch(true);
                }
                if (fg.hasPrimaryFields(false)) {
                    fg.setHasPrimaryFields(true);
                }
            }
        }
    }

    /**
     * Create all groups for cmd with their field arrays and then recursively
     * create groups for its subclasses.
     */
    private void createFetchGroups(ClassMetaData cmd, boolean quiet) {
        if (cmd.fields == null) {
            return; // no fields due to some previous error
        }

        ArrayList groups = cmd.fgTmp = new ArrayList();
        HashMap nameGroupMap = cmd.nameGroupMap = new HashMap();

        FetchGroup dfg = createDefaultFetchGroup(cmd);
        groups.add(dfg);
        nameGroupMap.put(dfg.name, dfg);

        FetchGroup retrieveFG = createRetrieveFetchGroup(cmd);
        groups.add(retrieveFG);
        nameGroupMap.put(retrieveFG.name, retrieveFG);

        FetchGroup allColsFG = createAllColumnsFetchGroup(cmd);
        groups.add(allColsFG);
        nameGroupMap.put(allColsFG.name, allColsFG);

        FetchGroup dfgNoFakes = createFetchGroupDefaultNoFakes(cmd);
        groups.add(dfgNoFakes);
        nameGroupMap.put(dfgNoFakes.name, dfgNoFakes);

        // if you add new groups here add a corresponding line to the block
        // towards the end of this method that caches special groups in
        // ClassMetaData
        addNotNull(createRefFetchGroup(cmd), groups, nameGroupMap);
        addNotNull(createDepFetchGroup(cmd), groups, nameGroupMap);
        addNotNull(createReqFetchGroup(cmd), groups, nameGroupMap);
        addNotNull(createManagedManyToManyFetchGroup(cmd), groups,
                nameGroupMap);

        // find all the user defined groups
        JdoElement[] elements = cmd.jdoClass.elements;
        int elementsLen = elements.length;
        for (int j = 0; j < elementsLen; j++) {
            JdoElement element = elements[j];
            if (!(element instanceof JdoExtension)) continue;
            JdoExtension e = (JdoExtension)element;
            if (e.key != JdoExtensionKeys.FETCH_GROUP) continue;
            FetchGroup g = new FetchGroup(cmd, e.getString(), createStoreFetchGroup());
            try {
                if (g.name.equals(FetchGroup.DFG_NAME)) {
                    throw BindingSupportImpl.getInstance().runtime("The group name '" + FetchGroup.DFG_NAME +
                            "' is reserved for the " +
                            "default fetch group\n" + e.getContext());
                }
                if (g.name.equals(FetchGroup.REF_NAME)) {
                    throw BindingSupportImpl.getInstance().runtime("The group name '" + FetchGroup.REF_NAME +
                            "' is reserved internal use\n" +
                            e.getContext());
                }
                if (nameGroupMap.containsKey(g.name)) {
                    throw BindingSupportImpl.getInstance().runtime("There is already a group called: '" + g.name + "'\n" +
                            e.getContext());
                }
                nameGroupMap.put(g.name, g);
                g.extension = e;
                processFetchGroupFields(cmd, g, quiet);
                groups.add(g);
            } catch (RuntimeException e1) {
                cmd.addError(e1, quiet);
            }
        }

        // create an empty group for each group from our parent class that
        // has not been extended i.e. group defined here with same name
        if (cmd.pcSuperMetaData != null) {
            List list = cmd.pcSuperMetaData.fgTmp;
            for (int i = 0; i < list.size(); i++) {
                FetchGroup sg = (FetchGroup)list.get(i);
                if (nameGroupMap.containsKey(sg.name)) continue;
                FetchGroup g = new FetchGroup(cmd, sg.name, createStoreFetchGroup());
                g.fields = new FetchGroupField[0];
                groups.add(g);
                nameGroupMap.put(g.name, g);
            }
        }

        // Fill in the fetchGroup for all fields creating new groups for fields
        // without a group that are not in the default fetch group. If the
        // field is a pass1 field then the optimistic locking field (if any)
        // is included in the group.
        FieldMetaData[] fields = cmd.fields;
        int fieldsLen = fields.length;
        for (int i = 0; i < fieldsLen; i++) {
            FieldMetaData fmd = fields[i];
            if (fmd.jdoField != null && fmd.jdoField.extensions != null) {
                try {
                    JdoExtension e = findFetchGroupExt(fmd.jdoField.extensions);
                    if (e != null) {
                        String gname = e.getString();
                        fmd.fetchGroup = (FetchGroup)nameGroupMap.get(gname);
                        if (fmd.fetchGroup == null) {
                            throw BindingSupportImpl.getInstance().runtime("No such fetch-group: '" + gname + "'\n" +
                                    e.getContext());
                        }
                    }
                } catch (RuntimeException e1) {
                    fmd.addError(e1, quiet);
                }
            }
            if (fmd.fetchGroup == null) {
                if (fmd.defaultFetchGroup) {
                    fmd.fetchGroup = dfg;
                } else {
                    String name = "_" + fmd.name + cmd.qname;
                    for (int j = 2; nameGroupMap.containsKey(name); j++) {
                        name = "_" + fmd.name + j;
                    }
                    FetchGroup g = new FetchGroup(cmd, name, createStoreFetchGroup());

                    ArrayList a = new ArrayList();
                    if (fmd.isEmbeddedRef()) {
                        //must add the fake fields  to the fg
                        if (fmd.embeddedFmds != null) {
                            for (int j = 0; j < fmd.embeddedFmds.length; j++) {
                                FieldMetaData embeddedFmd = fmd.embeddedFmds[j];
                                a.add(new FetchGroupField(embeddedFmd));
                            }
                        }
                    } else {
                        FetchGroupField fgf = createFetchGroupFieldWithPrefetch(fmd);
                        a.add(fgf);
                    }

                    // classes with storeAllFields set also read all fields
                    // so there is no need to add the optimistic locking field
                    // to fetch groups
                    if (fmd.primaryField && !cmd.storeAllFields
                            && cmd.optimisticLockingField != null) {
                        a.add(new FetchGroupField(cmd.optimisticLockingField));
                    }

                    g.fields = new FetchGroupField[a.size()];
                    a.toArray(g.fields);

                    groups.add(g);
                    nameGroupMap.put(g.name, g);
                    fmd.fetchGroup = g;
                }
            }
        }

        // dig out some popular fetchgroups for quick access
        cmd.refFetchGroup = (FetchGroup)nameGroupMap.get(FetchGroup.REF_NAME);
        cmd.depFetchGroup = (FetchGroup)nameGroupMap.get(FetchGroup.DEP_NAME);
        cmd.reqFetchGroup = (FetchGroup)nameGroupMap.get(FetchGroup.REQ_NAME);
        cmd.managedManyToManyFetchGroup = (FetchGroup)nameGroupMap.get(
                FetchGroup.MANY_TO_MANY_NAME);

        // process all of our subclasses
        ClassMetaData[] pcSubclasses = cmd.pcSubclasses;
        if (pcSubclasses != null) {
            for (int i = pcSubclasses.length - 1; i >= 0; i--) {
                createFetchGroups(cmd.pcSubclasses[i], quiet);
            }
        }

        if (cmd.pcSuperMetaData == null) {
            Collections.sort(cmd.fgTmp);
            if (cmd.pcSubclasses != null) {
                doSubFGs(cmd);
            }

        }

        if (cmd.pcSuperMetaData == null) {
            createFGArrays(cmd);
        }
    }

    /**
     * Create a FGF for a field with prefetching enabled if that makes sense
     * for the store.
     */
    protected FetchGroupField createFetchGroupFieldWithPrefetch(
            FieldMetaData fmd) {
        return new FetchGroupField(fmd);
    }

    private void addNotNull(FetchGroup g, ArrayList groups,
            HashMap nameGroupMap) {
        if (g != null) {
            groups.add(g);
            nameGroupMap.put(g.name, g);
        }
    }

    private void doSubFGs(ClassMetaData cmd) {
        ClassMetaData[] subCmds = cmd.pcSubclasses;
        if (subCmds == null) return;
        ArrayList list = new ArrayList();
        for (int i = 0; i < subCmds.length; i++) {
            ClassMetaData subCmd = subCmds[i];
            Collections.sort(subCmd.fgTmp);
            list.clear();
            for (int j = 0; j < cmd.fgTmp.size(); j++) {
                FetchGroup fetchGroup = (FetchGroup)cmd.fgTmp.get(j);
                FetchGroup subFG = (FetchGroup)subCmd.nameGroupMap.get(
                        fetchGroup.name);
                if (j == 0) {
                    if (!fetchGroup.name.equals(FetchGroup.DFG_NAME) || !subFG.name.equals(
                            FetchGroup.DFG_NAME)) {
                        throw BindingSupportImpl.getInstance().internal(
                                "DFG broken");
                    }
                }
                list.add(subFG);
            }
            subCmd.fgTmp.removeAll(list);
            list.addAll(subCmd.fgTmp);
            subCmd.fgTmp.clear();
            subCmd.fgTmp.addAll(list);
            doSubFGs(subCmd);
        }
    }

    private void createFGArrays(ClassMetaData cmd) {
        indexFGs(cmd);
        ClassMetaData[] cmds = cmd.pcSubclasses;
        if (cmds == null) return;
        for (int i = 0; i < cmds.length; i++) {
            ClassMetaData aCmd = cmds[i];
            createFGArrays(aCmd);
        }
    }

    private void indexFGs(ClassMetaData cmd) {
        int ng = cmd.fgTmp.size();
        FetchGroup[] fga = cmd.fetchGroups = new FetchGroup[ng];
        FetchGroup[] sfga = cmd.sortedFetchGroups = new FetchGroup[ng];
        cmd.fgTmp.toArray(fga);
        cmd.fgTmp.toArray(sfga);
        Arrays.sort(sfga);
        for (int i = fga.length - 1; i >= 0; i--) {
            if (fga[i].index == -1) {
                fga[i].index = i;
            }
        }
    }

    /**
     * Create the default fetch group for cmd.
     */
    private FetchGroup createDefaultFetchGroup(ClassMetaData cmd) {
        FieldMetaData[] fields = cmd.fields;
        FetchGroup g = new FetchGroup(cmd, FetchGroup.DFG_NAME, createStoreFetchGroup());
        int n = fields.length;
        ArrayList a = new ArrayList(n);
        for (int i = 0; i < n; i++) {
            FieldMetaData fmd = fields[i];
            if (!fmd.defaultFetchGroup || fmd.primaryKey) continue;
            FetchGroupField fgf = new FetchGroupField(fmd);
            a.add(fgf);
        }
        n = a.size();
        g.fields = new FetchGroupField[n];
        a.toArray(g.fields);
        return g;
    }

    /**
     * This creates a fetch group that contains only default fetch group fields
     * but no fake fields must be added here.
     */
    private FetchGroup createFetchGroupDefaultNoFakes(ClassMetaData cmd) {
        FetchGroup g = new FetchGroup(cmd, FetchGroup.DFG_NAME_NO_FAKES, createStoreFetchGroup());
        FieldMetaData[] fields = cmd.fields;
        int n = fields.length;
        ArrayList a = new ArrayList(n);
        for (int i = 0; i < n; i++) {
            FieldMetaData fmd = fields[i];
            if (fmd.defaultFetchGroup && !fmd.fake) {
                FetchGroupField fgf = new FetchGroupField(fmd);
                a.add(fgf);
            }
        }
        n = a.size();
        g.fields = new FetchGroupField[n];
        a.toArray(g.fields);
        return g;
    }

    /**
     * Create the retrieve fetch group for cmd.
     */
    private FetchGroup createRetrieveFetchGroup(ClassMetaData cmd) {
        FetchGroup g = new FetchGroup(cmd, FetchGroup.RETRIEVE_NAME, createStoreFetchGroup());
        FieldMetaData[] fields = cmd.fields;
        int n = fields.length;
        ArrayList a = new ArrayList(n);
        for (int i = 0; i < n; i++) {
            FieldMetaData fmd = fields[i];
            if (fmd.persistenceModifier != MDStatics.PERSISTENCE_MODIFIER_PERSISTENT) continue;
            FetchGroupField fgf = createFetchGroupFieldWithPrefetch(fmd);
            a.add(fgf);
        }
        n = a.size();
        g.fields = new FetchGroupField[n];
        a.toArray(g.fields);
        return g;
    }

    /**
     * Create the all columns fetch group for cmd. This implementation just
     * creates a dummy empty fetch group.
     */
    protected FetchGroup createAllColumnsFetchGroup(ClassMetaData cmd) {
        FetchGroup g = new FetchGroup(cmd, FetchGroup.ALL_COLS_NAME, createStoreFetchGroup());
        g.fields = new FetchGroupField[0];
        return g;
    }

    /**
     * Create the ref fetch group for cmd or return null if cmd does not
     * have any fields that reference other objects. Polyref and collection
     * fields are included. This does not fill in the nextFetchGroup and
     * nextKeyFetchGroup for the fields as this can only be done once all
     * the groups have been created.
     */
    private FetchGroup createRefFetchGroup(ClassMetaData cmd) {
        FieldMetaData[] fields = cmd.fields;
        int n = fields.length;
        ArrayList a = new ArrayList(n);
        for (int i = 0; i < n; i++) {
            FieldMetaData fmd = fields[i];
            if (fmd.isDirectRef() && fmd.isFake() && fmd.inverseFieldMetaData != null) {
                continue;
            }
            switch (fmd.category) {
                case MDStatics.CATEGORY_POLYREF:
                    a.add(new FetchGroupField(fmd));
                    break;
                case MDStatics.CATEGORY_COLLECTION:
                case MDStatics.CATEGORY_MAP:
                    if (fmd.elementType == Object.class
                            || fmd.keyType == Object.class
                            || (fmd.elementType != null && fmd.elementType.isInterface())
                            || (fmd.keyType != null && fmd.keyType.isInterface())) {
                        a.add(new FetchGroupField(fmd));
                        break;
                    }
                default:
                    ClassMetaData refmd = fmd.getRefOrValueClassMetaData();
                    if (refmd != null || fmd.keyTypeMetaData != null) {
                        a.add(new FetchGroupField(fmd));
                    }
            }
        }
        n = a.size();
        if (n == 0) {
            return null;
        }
        FetchGroup g = new FetchGroup(cmd, FetchGroup.REF_NAME, createStoreFetchGroup());
        g.fields = new FetchGroupField[n];
        a.toArray(g.fields);
        return g;
    }

    /**
     * Create the dependent fetch group for cmd or return null if cmd does not
     * have any fields that reference dependent objects. This does not fill
     * in the nextFetchGroup and nextKeyFetchGroup for the fields as this can
     * only be done once all the groups have been created.
     */
    private FetchGroup createDepFetchGroup(ClassMetaData cmd) {
        FieldMetaData[] fields = cmd.fields;
        int n = fields.length;
        ArrayList a = new ArrayList(n);
        for (int i = 0; i < n; i++) {
            FieldMetaData fmd = fields[i];
            if (!fmd.dependentValues && !fmd.dependentKeys) continue;
            if (fmd.category != MDStatics.CATEGORY_POLYREF) {
                ClassMetaData refmd = fmd.getRefOrValueClassMetaData();
                if (refmd == null && fmd.keyTypeMetaData == null) continue;
            }
            a.add(new FetchGroupField(fmd));
        }
        n = a.size();
        if (n == 0) return null;
        FetchGroup g = new FetchGroup(cmd, FetchGroup.DEP_NAME, createStoreFetchGroup());
        g.fields = new FetchGroupField[n];
        a.toArray(g.fields);
        return g;
    }

    /**
     * Create the fetch group containing required all the fields that must
     * be filled in the original state when persisting changes to instances.
     * This includes all autoset version fields ans well as autoset timestamp
     * fields used to implement optimistic locking.
     */
    private FetchGroup createReqFetchGroup(ClassMetaData cmd) {
        FieldMetaData[] fields = cmd.fields;
        int n = fields.length;
        ArrayList a = new ArrayList(n);
        if (readObjectBeforeWrite) {
            for (int i = 0; i < n; i++) {
                FieldMetaData fmd = fields[i];
                if (fmd.primaryField) {
                    FetchGroupField fgf = new FetchGroupField(fmd);
                    fgf.doNotFetchObject = true;
                    a.add(fgf);
                }
            }
        } else {
            for (int i = 0; i < n; i++) {
                FieldMetaData fmd = fields[i];
                if (isReqField(cmd, fmd)) {
                    a.add(new FetchGroupField(fmd));
                }
            }
        }
        n = a.size();
        if (n == 0) return null;
        FetchGroup g = new FetchGroup(cmd, FetchGroup.REQ_NAME, createStoreFetchGroup());
        g.fields = new FetchGroupField[n];
        a.toArray(g.fields);
        return g;
    }

    /**
     * Is fmd required before changes to an instance can be persisted?
     */
    private boolean isReqField(ClassMetaData cmd, FieldMetaData fmd) {
        if (fmd.autoSet == MDStatics.AUTOSET_NO) {
            return false;
        }
        if (fmd.typeCode == MDStatics.DATE) {
            return fmd == cmd.optimisticLockingField;
        }
        return true;
    }

    /**
     * Create the fetch group containing all the managed many-to-many fields
     * and all the required fields. No group is created if there are no
     * managed many-to-many fields.
     */
    private FetchGroup createManagedManyToManyFetchGroup(ClassMetaData cmd) {
        int manyToManyCount = 0;
        FieldMetaData[] fields = cmd.fields;
        int n = fields.length;
        ArrayList a = new ArrayList(n);
        for (int i = 0; i < n; i++) {
            FieldMetaData fmd = fields[i];
            if (fmd.isManyToMany && fmd.managed || isReqField(cmd, fmd)) {
                if (fmd.isManyToMany) manyToManyCount++;
                a.add(new FetchGroupField(fmd));
            }
        }
        if (manyToManyCount == 0) return null;
        FetchGroup g = new FetchGroup(cmd, FetchGroup.MANY_TO_MANY_NAME, createStoreFetchGroup());
        g.fields = new FetchGroupField[a.size()];
        a.toArray(g.fields);
        return g;
    }

    /**
     * Process the groups extension to find all of its fields. This does
     * not resolve next-fetch-group extensions as this can only be done
     * when all groups have been created.
     */
    private void processFetchGroupFields(ClassMetaData cmd, FetchGroup g,
            boolean quite) {
        JdoExtension e = g.extension;
        HashSet fieldNameSet = new HashSet(17);
        ArrayList fields = new ArrayList();
        JdoExtension[] nested = e.nested;
        if (nested == null) return;
        int nn = nested.length;
        boolean noFgFields = true;
        for (int k = 0; k < nn; k++) {
            JdoExtension ne = nested[k];
            if (ne.key != JdoExtensionKeys.FIELD_NAME) continue;
            String fname = ne.getString();
            if (fieldNameSet.contains(fname)) {
                throw BindingSupportImpl.getInstance().runtime("Field is already in group: '" + fname + "'\n" +
                        ne.getContext());
            }
            noFgFields = false;
            //don't add pk fields to fg's
            FieldMetaData fmd = cmd.getFieldMetaData(fname);
            if (fmd == null) {
                cmd.addError(BindingSupportImpl.getInstance().runtime("Field does not exist: '" + fname + "'\n" +
                        ne.getContext()), quite);
                continue;
            }
            if (fmd.primaryKey) continue;
//            if (fmd.jdbcField.isSharedWithPK()) continue;


            fieldNameSet.add(fname);
            FetchGroupField f = new FetchGroupField(fmd);
            f.extension = ne;
            fields.add(f);
        }


        //add the fields that should be in all the fg's
        FieldMetaData[] fmds = cmd.fields;
        int n = fmds.length;
        for (int i = 0; i < n; i++) {
            FieldMetaData fmd = fmds[i];
            if (!fmd.secondaryField && fmd.includeInAllFGs() && !fieldNameSet.contains(
                    fmd.name)) {
                fieldNameSet.add(fmd.name);
                FetchGroupField fgf = new FetchGroupField(fmd);
                fields.add(fgf);
            }
        }

        int nf = fields.size();
        if (noFgFields && nf == 0) {
            throw BindingSupportImpl.getInstance().runtime("Fetch group does not contain any fields: '" + g.name + "'\n" +
                    e.getContext());
        }
        g.fields = new FetchGroupField[nf];
        fields.toArray(g.fields);
    }

    /**
     * Process extensions for all fields in all groups. This resolves
     * next-fetch-group and next-key-fetch-group references.
     */
    private void processFetchGroups(ClassMetaData cmd) {
        processRefFetchGroup(cmd);
        FetchGroup[] groups = cmd.fetchGroups;
        if (groups == null) {
            return;
        }
        FetchGroup dep = cmd.refFetchGroup;
        int ng = groups.length;
        for (int i = 0; i < ng; i++) {
            FetchGroup group = groups[i];
            if (group == dep) continue;
            FetchGroupField[] fields = group.fields;
            if (fields == null) continue;
            int nf = fields.length;
            for (int j = 0; j < nf; j++) {
                FetchGroupField f = fields[j];
                ClassMetaData refmd = f.fmd.getRefOrValueClassMetaData();
                ClassMetaData keymd = f.fmd.keyTypeMetaData;
                JdoExtension[] nested = f.extension == null ? null : f.extension.nested;
                if (nested != null) {
                    int nl = nested.length;
                    for (int k = 0; k < nl; k++) {
                        JdoExtension e = nested[k];
                        switch (e.key) {
                            case JdoExtensionKeys.NEXT_FETCH_GROUP:
                                processNextFetchGroup(f, e, refmd);
                                break;
                            case JdoExtensionKeys.NEXT_KEY_FETCH_GROUP:
                                processNextKeyFetchGroup(f, e, keymd);
                                break;
                            default:
                                if (e.isCommon()) {
                                    MetaDataBuilder.throwUnexpectedExtension(e);
                                }
                        }
                        ;
                    }
                }
                if (f.nextFetchGroup == null && refmd != null && refmd.fetchGroups != null) {
                    f.nextFetchGroup = refmd.fetchGroups[0];
                }
                if (f.nextKeyFetchGroup == null && keymd != null && keymd.fetchGroups != null) {
                    f.nextKeyFetchGroup = keymd.fetchGroups[0];
                }
            }
        }
    }

    private void processNextFetchGroup(FetchGroupField f, JdoExtension e,
            ClassMetaData refmd) {
        if (f.nextFetchGroup != null) {
            throw BindingSupportImpl.getInstance().runtime("Only one next-fetch-group extension is allowed\n" +
                    e.getContext());
        }
        if (refmd == null) {
            throw BindingSupportImpl.getInstance().runtime("Field does not reference a PC class\n" +
                    e.getContext());
        }
        FetchGroup g = refmd.getFetchGroup(e.getString());
        if (g == null) {
            throw BindingSupportImpl.getInstance().runtime("Fetch group '" + e.getString() + "' not found in class " +
                    refmd.qname + "\n" +
                    e.getContext());
        }
        f.nextFetchGroup = g;
    }

    private void processNextKeyFetchGroup(FetchGroupField f, JdoExtension e,
            ClassMetaData keymd) {
        if (f.nextKeyFetchGroup != null) {
            throw BindingSupportImpl.getInstance().runtime("Only one next-key-fetch-group extension is allowed\n" +
                    e.getContext());
        }
        if (keymd == null) {
            throw BindingSupportImpl.getInstance().runtime("Field key does not reference a PC class\n" +
                    e.getContext());
        }
        FetchGroup g = keymd.getFetchGroup(e.getString());
        if (g == null) {
            throw BindingSupportImpl.getInstance().runtime("Fetch group '" + e.getString() + "' not found in class " +
                    keymd.qname + "\n" +
                    e.getContext());
        }
        f.nextKeyFetchGroup = g;
    }

    /**
     * Fill in the nextFetchGroup and nextKeyFetchGroup references for
     * all the fields in the refFetchGroup for cmd (if any). Only dependent
     * object references are followed.
     */
    private void processRefFetchGroup(ClassMetaData cmd) {
        FetchGroup g = cmd.refFetchGroup;
        if (g == null) return;
        FetchGroupField[] fields = g.fields;
        int nf = fields.length;
        for (int j = 0; j < nf; j++) {
            FetchGroupField f = fields[j];
            FieldMetaData fmd = f.fmd;
            // only follow dependent object references for this group
            if (fmd.dependentValues) {
                ClassMetaData refmd = fmd.getRefOrValueClassMetaData();
                if (refmd != null) f.nextFetchGroup = refmd.refFetchGroup;
            }
            if (fmd.dependentKeys) {
                ClassMetaData keymd = fmd.keyTypeMetaData;
                if (keymd != null) f.nextKeyFetchGroup = keymd.refFetchGroup;
            }
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.