All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.lightblue.metadata.EntitySchema Maven / Gradle / Ivy

There is a newer version: 2.18.0
Show newest version
/*
 Copyright 2013 Red Hat, Inc. and/or its affiliates.

 This file is part of lightblue.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see .
 */
package com.redhat.lightblue.metadata;

import com.redhat.lightblue.metadata.constraints.IdentityConstraint;
import com.redhat.lightblue.metadata.constraints.ArrayElementIdConstraint;
import com.redhat.lightblue.util.Error;
import com.redhat.lightblue.util.MutablePath;
import com.redhat.lightblue.util.Path;
import com.redhat.lightblue.util.JsonCompare;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Version specific bits of metadata.
 *
 * @author nmalik
 */
public class EntitySchema extends MetadataObject {
    private static final Logger LOGGER = LoggerFactory.getLogger(EntitySchema.class);

    private final String name;
    private Version version;
    private MetadataStatus status;
    private final ArrayList statusChangeLog;
    //hooks
    private final EntityAccess access;
    private final ArrayList constraints;
    private Fields fields;
    private FieldTreeNode fieldRoot;

    protected class RootNode implements FieldTreeNode {

        private static final long serialVersionUID = 1L;

        @Override
        public String getName() {
            return "";
        }

        @Override
        public Type getType() {
            return null;
        }

        @Override
        public boolean hasChildren() {
            return true;
        }

        @Override
        public Iterator getChildren() {
            return fields.getFields();
        }

        @Override
        public FieldTreeNode resolve(Path p) {
            return fields.resolve(p);
        }

        @Override
        public FieldTreeNode resolve(Path p, int level) {
            return fields.resolve(p, level);
        }

        @Override
        public FieldTreeNode getParent() {
            return null;
        }

        @Override
        public Path getFullPath() {
            return Path.EMPTY;
        }

        @Override
        public MutablePath getFullPath(MutablePath mp) {
            return Path.EMPTY.mutableCopy();
        }
    };

    public EntitySchema(String name) {
        this.name = name;
        this.fieldRoot = new RootNode();
        this.fields = new Fields(fieldRoot);
        this.statusChangeLog = new ArrayList<>();
        this.access = new EntityAccess();
        this.constraints = new ArrayList<>();
    }

    /**
     * Copy ctor with shallow copy
     */
    protected EntitySchema(EntitySchema source) {
        this.name = source.name;
        this.version = source.version;
        this.status = source.status;
        this.statusChangeLog = source.statusChangeLog;
        this.access = source.access;
        this.constraints = source.constraints;
        this.fields = source.fields;
        this.fieldRoot = source.fieldRoot;
        super.shallowCopyFrom(source);
    }

    /**
     * Gets the value of name
     *
     * @return the value of name
     */
    public String getName() {
        return this.name;
    }

    /**
     * Return the status of this particular version of the entity
     */
    public MetadataStatus getStatus() {
        return status;
    }

    /**
     * Sets the status of this particular version of the entity
     */
    public void setStatus(MetadataStatus status) {
        this.status = status;
    }

    /**
     * Returns the status change log
     */
    @SuppressWarnings("unchecked")
    public List getStatusChangeLog() {
        return (List) statusChangeLog.clone();
    }

    /**
     * Sets the status change log
     */
    public void setStatusChangeLog(Collection log) {
        statusChangeLog.clear();
        if (log != null) {
            statusChangeLog.addAll(log);
        }
    }

    /**
     * Gets the value of version
     *
     * @return the value of version
     */
    public Version getVersion() {
        return this.version;
    }

    /**
     * Sets the value of version
     *
     * @param argVersion Value to assign to this.version
     */
    public void setVersion(Version argVersion) {
        this.version = argVersion;
    }

    /**
     * Gets the value of access
     *
     * @return the value of access
     */
    public EntityAccess getAccess() {
        return this.access;
    }

    /**
     * Returns a deep copy list of constraints
     */
    @SuppressWarnings("unchecked")
    public List getConstraints() {
        return (List) constraints.clone();
    }

    /**
     * Sets the constraints
     */
    public void setConstraints(Collection constraints) {
        this.constraints.clear();
        if (constraints != null) {
            this.constraints.addAll(constraints);
        }
    }

    /**
     * Gets the value of fields
     *
     * @return the value of fields
     */
    public Fields getFields() {
        return this.fields;
    }

    protected void setFields(Fields fields) {
        this.fields = fields;
    }

    public FieldTreeNode getFieldTreeRoot() {
        return fieldRoot;
    }

    protected void setFieldTreeRoot(FieldTreeNode fieldRoot) {
        this.fieldRoot = fieldRoot;
    }

    public FieldCursor getFieldCursor() {
        return new FieldCursor(new Path(), getFieldTreeRoot());
    }

    public FieldCursor getFieldCursor(Path p) {
        if (p.numSegments() == 0) {
            return getFieldCursor();
        } else {
            FieldTreeNode tn = resolve(p);
            if (tn != null) {
                return new FieldCursor(p, tn);
            } else {
                return null;
            }
        }
    }

    public FieldTreeNode resolve(Path p) {
        Error.push(name);
        try {
            return fields.resolve(p);
        } catch (Error e) {
            // rethrow lightblue error
            throw e;
        } catch (Exception e) {
            // throw new Error (preserves current error context)
            LOGGER.error(e.getMessage(), e);
            throw Error.get(MetadataConstants.ERR_ILL_FORMED_METADATA, e.getMessage());
        } finally {
            Error.pop();
        }
    }

    /**
     * Returns the full field name relative to the current entity
     */
    public Path getEntityRelativeFieldName(FieldTreeNode field) {
        return field.getFullPath();
    }

    /**
     * Returns a map where the key is the array field name, and value is a
     * List listing the identity fields for that array
     */
    public Map> getArrayIdentities() {
        FieldCursor cursor = getFieldCursor();
        Map> idMap = new HashMap<>();
        while (cursor.next()) {
            FieldTreeNode fn = cursor.getCurrentNode();
            if (fn instanceof SimpleField) {
                for (FieldConstraint fc : ((SimpleField) fn).getConstraints()) {
                    if (fc instanceof ArrayElementIdConstraint) {
                        Path fieldName = cursor.getCurrentPath();
                        int lastAny = findLastAnyIndex(fieldName);
                        if (lastAny != -1) {
                            Path arrayName = fieldName.prefix(lastAny);
                            Path idName = fieldName.suffix(-(lastAny + 1));
                            List ids = idMap.get(arrayName);
                            if (ids == null) {
                                idMap.put(arrayName, ids = new ArrayList<>());
                            }
                            ids.add(idName);
                        }
                    }
                }
            }
        }
        return idMap;
    }

    /**
     * Builds a document comparator for comparing documents of this type. That
     * involves registering all array element identities with the comparator so
     * array comparisons can be done corectly and efficiently.
     */
    public JsonCompare getDocComparator() {
        Map> idMap = getArrayIdentities();
        JsonCompare cmp = new JsonCompare();
        for (Map.Entry> entry : idMap.entrySet()) {
            cmp.addArrayIdentity(entry.getKey(), entry.getValue().toArray(new Path[entry.getValue().size()]));
        }
        return cmp;
    }

    private int findLastAnyIndex(Path p) {
        for (int i = p.numSegments() - 1; i >= 0; i--) {
            if (p.head(i).equals(Path.ANY)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Returns the identity fields for this entity. It does not descend down the
     * relations.
     */
    public Field[] getIdentityFields() {
        FieldCursor cursor = getFieldCursor();
        TreeMap fieldMap = new TreeMap<>();
        getIdentityFields(fieldMap, cursor);
        Field[] ret = new Field[fieldMap.size()];
        int i = 0;
        for (Field f : fieldMap.values()) {
            ret[i++] = f;
        }
        return ret;
    }

    private void getIdentityFields(TreeMap fieldMap, FieldCursor cursor) {
        if (cursor.firstChild()) {
            do {
                FieldTreeNode fn = cursor.getCurrentNode();
                if (fn instanceof ObjectField) {
                    getIdentityFields(fieldMap, cursor);
                } else if (fn instanceof SimpleField) {
                    SimpleField f = (SimpleField) fn;
                    for (FieldConstraint fc : f.getConstraints()) {
                        if (fc instanceof IdentityConstraint) {
                            fieldMap.put(getEntityRelativeFieldName(f), f);
                            break;
                        }
                    }
                }
            } while (cursor.nextSibling());
            cursor.parent();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy