protected ForeignKey createForeignKey()

in openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingInfo.java [1084:1243]


    protected ForeignKey createForeignKey(MetaDataContext context,
        String prefix, List<Column> given, ForeignKeyDefaults def, Table table,
        ClassMapping cls, ClassMapping rel, boolean inversable, boolean adapt) {
        assertTable(context, table);
        if (prefix == null)
            prefix = "generic";

        // collect the foreign key columns and their targets
        Object[][] joins = createJoins(context, prefix, table, cls, rel,
            given, def, inversable, adapt);
        _join = JOIN_FORWARD;

        // establish local table using any join between two columns; if we only
        // find constant joins, then keep default local table (directionless)
        Table local = table;
        Table foreign = rel.getTable();
        Table tmp;
        boolean constant = false;
        boolean localSet = false;
        for (Object[] objects : joins) {
            if (objects[1] instanceof Column) {
                tmp = ((Column) objects[0]).getTable();
                if (!localSet) {
                    local = tmp;
                    localSet = true;
                }
                else if (tmp != local)
                    throw new MetaDataException(_loc.get(prefix
                            + "-mult-fk-tables", context, local, tmp));
                foreign = ((Column) objects[1]).getTable();

                if (objects[2] == Boolean.TRUE)
                    _join = JOIN_INVERSE;
            }
            else
                constant = true;
        }

        // if this is not a constant join, look for existing foreign key
        // on local columns
        ForeignKey exist = null;
        if (!constant && local.getForeignKeys().length > 0) {
            Column[] cols = new Column[joins.length];
            Column[] pks = new Column[joins.length];
            for (int i = 0; i < joins.length; i++) {
                cols[i] = (Column) joins[i][0];
                pks[i] = (Column) joins[i][1];
            }

            ForeignKey[] fks = local.getForeignKeys();
            for (ForeignKey fk : fks) {
                if (fk.getConstantColumns().length == 0
                        && fk.getConstantPrimaryKeyColumns().length == 0
                        && fk.columnsMatch(cols, pks)) {
                    exist = fk;
                    break;
                }
            }
        }

        MappingRepository repos = (MappingRepository) context.getRepository();
        DBDictionary dict = repos.getDBDictionary();
        if (exist != null) {
            // make existing key logical?
            if (!_canFK) {
                if (exist.getDeleteAction() != ForeignKey.ACTION_NONE && !adapt)
                    throw new MetaDataException(_loc.get(prefix
                        + "-fk-exists", context));
                exist.setDeleteAction(ForeignKey.ACTION_NONE);
            }

            if (_fk != null && _fk.isDeferred() && !exist.isDeferred()) {
                Log log = repos.getLog();
                if (log.isWarnEnabled())
                    log.warn(_loc.get(prefix + "-defer-fk", context));
            }

            // allow user-given info to override existing key if we're adapting;
            // template info cannot override existing key
            if (adapt && _fk != null) {
                if (_fk.getUpdateAction() != ForeignKey.ACTION_NONE)
                    exist.setUpdateAction(_fk.getUpdateAction());
                if (_fk.getDeleteAction() != ForeignKey.ACTION_NONE)
                    exist.setDeleteAction(_fk.getDeleteAction());
            }
            setIOFromJoins(exist, joins);
            return exist;
        }

        DBIdentifier name = DBIdentifier.NULL;
        int delAction = ForeignKey.ACTION_NONE;
        int upAction = ForeignKey.ACTION_NONE;
        boolean deferred = false;
        boolean fill = repos.getMappingDefaults().defaultMissingInfo();
        ForeignKey tmplate = (def == null) ? null
            : def.get(local, foreign, _join == JOIN_INVERSE);
        if (_fk != null && (tmplate == null || (!adapt && !fill))) {
            // if not adapting or no template info use given data
            name = _fk.getIdentifier();
            delAction = _fk.getDeleteAction();
            upAction = _fk.getUpdateAction();
            deferred = _fk.isDeferred();
        } else if (_canFK && (adapt || fill)) {
            if (_fk == null && tmplate != null) {
                // no user given info; use template data
                name = tmplate.getIdentifier();
                delAction = tmplate.getDeleteAction();
                upAction = tmplate.getUpdateAction();
                deferred = tmplate.isDeferred();
            } else if (_fk != null && tmplate != null) {
                // merge user and template data, always letting user info win
                name = _fk.getIdentifier();
                if (DBIdentifier.isNull(name) && !DBIdentifier.isNull(tmplate.getIdentifier()))
                    name = tmplate.getIdentifier();
                delAction = _fk.getDeleteAction();
                if (delAction == ForeignKey.ACTION_NONE)
                    delAction = tmplate.getDeleteAction();
                upAction = _fk.getUpdateAction();
                if (upAction == ForeignKey.ACTION_NONE)
                    upAction = tmplate.getUpdateAction();
                deferred = _fk.isDeferred();
            }
        }

        if (!dict.supportsDeleteAction(delAction)
            || !dict.supportsUpdateAction(upAction)) {
            Log log = repos.getLog();
            if (log.isWarnEnabled())
                log.warn(_loc.get(prefix + "-unsupported-fk-action", context));
            delAction = ForeignKey.ACTION_NONE;
            upAction = ForeignKey.ACTION_NONE;
        }
        if (deferred && !dict.supportsDeferredConstraints) {
            Log log = repos.getLog();
            if (log.isWarnEnabled())
                log.warn(_loc.get(prefix + "-create-defer-fk",
                    context, dict.platform));
            deferred = false;
        }

        // create foreign key with merged info
        ForeignKey fk = local.addForeignKey(name);
        fk.setDeleteAction(delAction);
        fk.setUpdateAction(upAction);
        fk.setDeferred(deferred);

        // add joins to key
        Column col;
        for (Object[] join : joins) {
            col = (Column) join[0];
            if (join[1] instanceof Column)
                fk.join(col, (Column) join[1]);
            else if ((join[2] == Boolean.TRUE) != (_join == JOIN_INVERSE))
                fk.joinConstant(join[1], col);
            else
                fk.joinConstant(col, join[1]);
        }
        setIOFromJoins(fk, joins);
        return fk;
    }