Link.java :  » Database-ORM » ODAL » com » completex » objective » components » persistency » Java Open Source

Java Open Source » Database ORM » ODAL 
ODAL » com » completex » objective » components » persistency » Link.java
/**
 *  Objective Database Abstraction Layer (ODAL)
 *  Copyright (c) 2004, The ODAL Development Group
 *  All rights reserved.
 *  For definition of the ODAL Development Group please refer to LICENCE.txt file
 *
 *  Distributable under LGPL license.
 *  See terms of license at gnu.org.
 */
package com.completex.objective.components.persistency;

import com.completex.objective.components.persistency.core.impl.LinkIterator;
import com.completex.objective.util.PropertyMap;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * Represents tree structure used to create Query trees as well as PersistentObject trees.
 *
 * @author Gennady Krizhevsky
 */
public class Link extends ParentBase implements Parent, Serializable, Cloneable, Mappable {
    static final long serialVersionUID = 1L;
    public static final String SEP = "|";

    private transient Query query;
    private transient LifeCycleController lifeCycleController;
    protected transient int[] parentIndeces;
    protected transient int[] thisIndeces;
    private transient boolean lazyRetrieval;
    private transient boolean insertBeforeParent; /* it means also "update Before Parent" & "delete After Parent" */
    private transient boolean cascadeDelete;
    private transient boolean cascadeInsert;
    private transient boolean cascadeUpdate;
    private transient boolean treatNullAsRemove;
    private transient int dependencyIndex = -1;
    protected transient InlineMode inlineMode;
    private transient boolean retrieved;
    private transient boolean adHoc;

    private boolean endOfChain;
    private Object result;
    private String name;
    // Meta data:
    private List path = new LinkedList();
    private static final String TAG_PARENT_INDECES = "parentIndeces";
    private static final String TAG_THIS_INDECES = "thisIndeces";
    private static final String TAG_NAME = "name";
    public static final String TAG_QUERY = "query";
    public static final String TAG_QUERY_CLASS = "queryClass";

    public Link() {
    }

    public Link(Map map) {
        fromMap(map);
    }

    public Link(String name) {
        setName(name);
    }

    public Link(String name, Object result) {
        this.name = name;
        this.result = result;
    }

    public Link(String name, Object result, boolean adHoc) {
        this.name = name;
        this.result = result;
        this.adHoc = adHoc;
    }

    /**
     * @param query         Query object
     * @param parentIndeces parent indeces which values are mapped to corresponding "this indeces"
     * @param thisIndeces   "this indeces" indeces which values are mapped to corresponding parent ones
     */
    public Link(Query query, int[] parentIndeces, int thisIndeces []) {
        this(query, parentIndeces, thisIndeces, null);
    }

    /**
     * @param query         Query object
     * @param parentIndeces parent indeces which values are mapped to corresponding "this indeces"
     * @param thisIndeces   "this indeces" indeces of this link query's SingularResultFactory
     *                      which values are mapped to corresponding parent ones
     * @param name          link name - mandatory for PersistentObject trees
     */
    public Link(Query query, int[] parentIndeces, int thisIndeces [], String name) {
        this.query = query;
        this.parentIndeces = parentIndeces;
        this.name = name;
        if (parentIndeces == null) {
            addToPath(getName());
        } else {
            if (thisIndeces == null) {
                throw new IllegalArgumentException("thisIndeces == null");
            }
            if (thisIndeces.length != parentIndeces.length) {
                throw new IllegalArgumentException("thisIndeces.length != parentIndeces.length");
            }
            this.thisIndeces = thisIndeces;
        }
    }

    public Link(Link source) {
        this(source.query, source.parentIndeces, source.thisIndeces, source.name);
    }

    public Link copyAll(Link source) {
        this.query = source.query;
        this.lifeCycleController = source.lifeCycleController;
        this.parentIndeces = source.parentIndeces;
        this.thisIndeces = source.thisIndeces;
        this.lazyRetrieval = source.lazyRetrieval;
        this.insertBeforeParent = source.insertBeforeParent;
        this.cascadeDelete = source.cascadeDelete;
        this.cascadeInsert = source.cascadeInsert;
        this.cascadeUpdate = source.cascadeUpdate;
        this.treatNullAsRemove = source.treatNullAsRemove;
        this.dependencyIndex = source.dependencyIndex;
        this.inlineMode = source.inlineMode;
        this.endOfChain = source.endOfChain;
        this.result = source.result;
        this.name = source.name;
        this.path = source.path;
        return this;
    }

    /**
     * Returns itself
     *
     * @return itself
     */
    public Link toLink() {
        return this;
    }


    /**
     * Sets cascadeDelete = true; cascadeInsert = true; cascadeUpdate = true. Values are used in
     * PersistentObject trees
     *
     * @return itself
     */
    public Link setCascadeAll() {
        cascadeDelete = true;
        cascadeInsert = true;
        cascadeUpdate = true;
        return this;
    }

    /**
     * Unsets cascadeDelete = true; cascadeInsert = true; cascadeUpdate = true. Values are used in
     * PersistentObject trees
     *
     * @return itself
     */
    public Link unsetCascadeAll() {
        cascadeDelete = false;
        cascadeInsert = false;
        cascadeUpdate = false;
        return this;
    }

    /**
     * Sets setRelationship to parent
     *
     * @param relationshipType
     * @see RelationshipType
     */
    public void setRelationshipToParent(RelationshipType relationshipType) {
        if (MANY_TO_ONE.equals(relationshipType)) {
            insertBeforeParent = true;
        }
    }

    /**
     * Returns LifeCycleController set for this link
     *
     * @return LifeCycleController set for this link
     */
    public LifeCycleController getLifeCycleController() {
        return lifeCycleController;
    }

    /**
     * Sets LifeCycleController for this link
     *
     * @param lifeCycleController
     */

    public void setLifeCycleController(LifeCycleController lifeCycleController) {
        this.lifeCycleController = lifeCycleController;
    }

    /**
     * Sets link name. Link name is mandatory for PersistentObject trees
     *
     * @param name link name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Returns link name
     *
     * @return link name
     */
    public String getName() {
        return name;
    }

    /**
     * Returns true is this link is end of link chain. Marking link as end of chain prevents
     * infinite loops of retrievals when circular link references are set.
     *
     * @return true is this link is end of link chain
     */
    public boolean isEndOfChain() {
        return endOfChain;
    }

    /**
     * If true - this link is end of link chain. Marking link as end of chain prevents
     * infinite loops of retrievals when circular link references are set.
     *
     * @param endOfChain true is this link is end of link chain
     */
    public void setEndOfChain(boolean endOfChain) {
        this.endOfChain = endOfChain;
    }

    /**
     * Returns link dependency index
     *
     * @return link dependency index
     */
    public int getDependencyIndex() {
        return dependencyIndex;
    }

    /**
     * Sets link dependency index
     *
     * @param dependencyIndex link dependency index
     */
    public void setDependencyIndex(int dependencyIndex) {
        this.dependencyIndex = dependencyIndex;
    }

    /**
     * Returns "this indeces" - indeces of this link query's SingularResultFactory
     * which values are mapped to corresponding parent ones. Usually they are foregn key ones
     *
     * @return "this indeces" - indeces of this link query's SingularResultFactory
     *         which values are mapped to corresponding parent ones
     */
    public int[] getThisIndeces() {
        return thisIndeces;
    }


    /**
     * Sets "this indeces" - indeces of this link query's SingularResultFactory
     * which values are mapped to corresponding parent ones. Usually they are foregn key ones
     *
     * @param thisIndeces "this indeces" - indeces of this link query's SingularResultFactory
     *                    which values are mapped to corresponding parent ones
     */
    public void setThisIndeces(int[] thisIndeces) {
        this.thisIndeces = thisIndeces;
    }

    /**
     * Returns parent indeces - indeces of the parent persistent object which contains a link [pointing to itself.
     * Usually they are the primary key ones.
     *
     * @return parent indeces - indeces of the parent persistent object which contains a link [pointing to itself.
     *         Usually they are the primary key ones.
     */
    public int[] getParentIndeces() {
        return parentIndeces;
    }

    /**
     * Sets parent indeces - indeces of the parent persistent object which contains a link [pointing to itself.
     * Usually they are the primary key ones.
     *
     * @param parentIndeces indeces of the parent persistent object which contains a link [pointing to itself.
     *                      Usually they are the primary key ones.
     */
    public void setParentIndeces(int[] parentIndeces) {
        this.parentIndeces = parentIndeces;
    }

    /**
     * Returns full path to this link built of the names of the parent chain
     *
     * @return full path to this link built of the names of the parent chain
     */
    public String getPathString() {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < path.size(); i++) {
            buffer.append(path.get(i));
            if (i < path.size() - 1) {
                buffer.append(SEP);
            }
        }
        return buffer.toString();
    }

    public void setPath(String pathString) {
        path = string2path(pathString);
    }

    public static String path2string(List path) {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < path.size(); i++) {
            buffer.append(path.get(i));
            if (i < path.size() - 1) {
                buffer.append(SEP);
            }
        }
        return buffer.toString();
    }

    public static List string2path(String pathString) {
        String [] tokens = pathString.split(SEP);
        ArrayList path = new ArrayList(tokens.length);
        for (int i = 0; i < path.size(); i++) {
            path.add(tokens[i]);
        }
        return path;
    }

    /**
     * Sets full path to this link built of the names of the parent chain
     *
     * @param path full path to this link built of the names of the parent chain
     */
    void setPath(List path) {
        this.path = path;
    }

    /**
     * Returns full path to this link built of the names of the parent chain
     *
     * @return full path to this link built of the names of the parent chain
     */
    public List getPath() {
        return path;
    }

    /**
     * Appends all of the elements in the specified parentPath to the end of
     * this link's path
     *
     * @param parentPath to append to the end of
     *                   this link's path
     */
    public void addParentPath(List parentPath) {
        if (parentPath != null) {
            for (int i = 0; i < parentPath.size(); i++) {
                String parentName = (String) parentPath.get(i);
                addToPath0(parentName);
            }
        }
    }

    /**
     * Adds name to this link's path
     *
     * @param name to add
     */
    public void addToPath(String name) {
        addToPath0(name);
        setName(name);
    }

    private void addToPath0(String name) {
        if (path.size() > 0) {
            String lastName = (String) path.get(path.size() - 1);
            if (lastName.equals(name)) {
                throw new IllegalArgumentException("Attempt to add name twice");
            }
        } else if (!ROOT.equals(name)) {
            path.add(ROOT);
        }
        if (name != null) {
            path.add(name);
        }
    }

    /**
     * Returns result - data that is set during query execution for selects
     * or by using setter methods for update operations
     *
     * @return result - data that is set during query execution for selects
     *         or by using setter methods for update operations
     */
    public Object getResult() {
        return result;
    }

    public Collection getResultAsCollection() {
        return (Collection) result;
    }

    public void addToResultCollection(Object value) {
        getResultAsCollection().add(value);
    }

    public void addNotNullToResultCollection(Object value) {
        if (value != null) {
            getResultAsCollection().add(value);
        }
    }

    /**
     * Sets result - data that is set during query execution for selects
     * or by using setter methods for update operations
     *
     * @param result data that is set during query execution for selects
     *               or by using setter methods for update operations
     */
    public void setResult(Object result) {
        this.result = result;
    }


    /**
     * Returns query that is used to retrieve object trees
     *
     * @return query that is used to retrieve object trees
     */
    public Query getQuery() {
        return query;
    }

    /**
     * Sets query that is used to retrieve object trees
     *
     * @param query query that is used to retrieve object trees
     */
    public void setQuery(Query query) {
        this.query = query;
    }


    /**
     * Returns true the result of this link has to be performed in "lazy" fashion
     *
     * @return true the result of this link has to be performed in "lazy" fashion
     */
    public boolean isLazyRetrieval() {
        return lazyRetrieval;
    }

    /**
     * Sets true the result of this link has to be performed in "lazy" fashion
     *
     * @param lazyRetrieval true the result of this link has to be performed in "lazy" fashion
     */
    public void setLazyRetrieval(boolean lazyRetrieval) {
        this.lazyRetrieval = lazyRetrieval;
    }

    /**
     * Returns true if the result (data) of this link is to be inserted before the parent link's one
     *
     * @return true if the result (data) of this link is to be inserted before the parent link's one
     */
    public boolean isInsertBeforeParent() {
        return insertBeforeParent;
    }

    /**
     * Sets true if the result (data) of this link is to be inserted before the parent link's one
     *
     * @param insertBeforeParent true if the result (data) of this link is to be inserted before the parent link's one
     */
    public void setInsertBeforeParent(boolean insertBeforeParent) {
        this.insertBeforeParent = insertBeforeParent;
    }

    /**
     * Returns true if for one-to-one inversed relationship
     * (this link contains foreign key object and its child contains the primary key ones)
     * nullifying the foregn key field should cause deletion of the child object
     *
     *
     * @return true if for one-to-one inversed relationship
     * (this link contains foreign key object and its child contains the primary key ones)
     * nullifying the foregn key field should cause deletion of the child object
     */
    public boolean isTreatNullAsRemove() {
        return treatNullAsRemove;
    }

    /**
     * Sets true if for one-to-one inversed relationship
     * (this link contains foreign key object and its child contains the primary key ones)
     * nullifying the foregn key field should cause deletion of the child object
     *
     * @param treatNullAsRemove true if for one-to-one inversed relationship
     * (this link contains foreign key object and its child contains the primary key ones)
     * nullifying the foregn key field should cause deletion of the child object
     */
    public void setTreatNullAsRemove(boolean treatNullAsRemove) {
        this.treatNullAsRemove = treatNullAsRemove;
    }

    /**
     * Returns true if delete is to be propagated to this link when the parent one gets deleted
     *
     * @return true if delete is to be propagated to this link when the parent one gets deleted
     */
    public boolean isCascadeDelete() {
        return cascadeDelete;
    }

    /**
     * Sets true if delete is to be propagated to this link when the parent one gets deleted
     *
     * @param cascadeDelete true if delete is to be propagated to this link when the parent one gets deleted
     */
    public void setCascadeDelete(boolean cascadeDelete) {
        this.cascadeDelete = cascadeDelete;
    }

    /**
     * Returns true if delete is to be propagated to this link when the parent one gets inserted
     *
     * @return true if delete is to be propagated to this link when the parent one gets inserted
     */
    public boolean isCascadeInsert() {
        return cascadeInsert;
    }

    /**
     * Sets true if delete is to be propagated to this link when the parent one gets inserted
     *
     * @param cascadeInsert true if delete is to be propagated to this link when the parent one gets inserted
     */
    public void setCascadeInsert(boolean cascadeInsert) {
        this.cascadeInsert = cascadeInsert;
    }

    /**
     * Returns true if delete is to be propagated to this link when the parent one gets updated
     *
     * @return true if delete is to be propagated to this link when the parent one gets updated
     */
    public boolean isCascadeUpdate() {
        return cascadeUpdate;
    }

    /**
     * Sets true if delete is to be propagated to this link when the parent one gets updated
     *
     * @param cascadeUpdate true if delete is to be propagated to this link when the parent one gets updated
     */
    public void setCascadeUpdate(boolean cascadeUpdate) {
        this.cascadeUpdate = cascadeUpdate;
    }

    /**
     * Experimental
     */
    public boolean isInline() {
        return inlineMode != null;
    }

    /**
     * Experimental
     */
    public InlineMode getInlineMode() {
        return inlineMode;
    }

    /**
     * Experimental
     */
    public void setInlineMode(InlineMode inlineMode) {
        this.inlineMode = inlineMode;
    }


    /**
     * Returns new instance of this link that inherits set of its parent properties
     *
     * @return new instance of this link that inherits set of its parent properties
     */
    public Link newInstance() {
        Query query = null;
        if (this.query != null) {
            query = this.query.newQuery();
        }
        Link link = newInstance0(query);
        link.setName(name);
        link.setPath(path);
        link.setLazyRetrieval(lazyRetrieval);
        link.setInsertBeforeParent(insertBeforeParent);
        link.setDependencyIndex(dependencyIndex);
        link.setCascadeDelete(cascadeDelete);
        link.setCascadeInsert(cascadeInsert);
        link.setCascadeUpdate(cascadeUpdate);
        link.setTreatNullAsRemove(treatNullAsRemove);
        link.setEndOfChain(endOfChain);
        if (lifeCycleController != null) {
            link.setLifeCycleController(lifeCycleController.newLifeCycleInstance());
        }
        link.path = cloneList(path);
        return link;
    }

    List cloneList(List list) {
        if (list instanceof LinkedList) {
            return (List) ((LinkedList) list).clone();
        } else if (list instanceof ArrayList) {
            return (List) ((ArrayList) list).clone();
        } else {
            throw new RuntimeException("Unsupported type " + list);
        }
    }

    protected Link newInstance0(Query query) {
        return new Link(query, parentIndeces, thisIndeces);
    }

    /**
     * Returns Deep copy of this link
     *
     * @return Deep copy of this link
     * @throws CloneNotSupportedException
     */
    public Object clone() throws CloneNotSupportedException {
        Link link = (Link) super.clone();
        Object result = link.getResult();
        Object clonedResult = link.getResult();
        if (query != null) {
            link.setQuery(((Query) query.clone()));
        }
        if (result != null) {
            if (result instanceof com.completex.objective.components.persistency.Cloneable) {
                clonedResult = ((com.completex.objective.components.persistency.Cloneable) result).clone();
            } else if (result instanceof LinkedList) {
                clonedResult = ((LinkedList) result).clone();
                populateClonedCollection(((List) clonedResult));
            } else if (result instanceof ArrayList) {
                clonedResult = ((ArrayList) result).clone();
                populateClonedCollection(((List) clonedResult));
            } else if (result instanceof HashSet) {
                clonedResult = ((HashSet) result).clone();
                populateClonedCollection(((Set) clonedResult));
            } else if (result instanceof HashMap) {
                clonedResult = ((HashMap) result).clone();
                populateClonedMap(((Map) clonedResult));
            }
        }
        link.setResult(clonedResult);
        if (link.hasChildren()) {
            for (LinkIterator it = linkIterator(); it.hasNext();) {
                Link child = it.nextLink();
                child.clone();
            }
        }
        link.inlineMode = inlineMode;
        return link;
    }
    
    public void populateClonedCollection(Collection collection) {
        if (collection == null) {
            return;
        }
        AbstractPersistentObject[] objects =
                (AbstractPersistentObject[]) collection.toArray(new AbstractPersistentObject[collection.size()]);
        for (int i = 0; i < objects.length; i++) {
            AbstractPersistentObject object = objects[i];
            if (objects[i] != null) {
                objects[i] = (AbstractPersistentObject) object.clone();
            }
        }
        collection.clear();
        collection.addAll(Arrays.asList(objects));
        

    }

    public void populateClonedMap(Map map) {
        if (map == null) {
            return;
        }
        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            Object value = entry.getValue();
            if (value instanceof AbstractPersistentObject) {
                entry.setValue(((AbstractPersistentObject) value).clone());
            }
        }
        

    }

    /**
     * Copies results from "from" link to this one without touching children
     *
     * @param from
     */
    public void copyResultsOneLevel(Link from) {
        copyResultsOneLevel(from, this);
    }

    /**
     * Copies results from "from" link to this one including children
     *
     * @param from
     */
    public void copyResults(Link from) {
        copyResults(from, this, 0);
    }

    private static void copyResultsOneLevel(Link from, Link to) {
        if (from == null || to == null) {
            return;
        }

        if (from.getResult() != null) {
            to.setResult(from.getResult());
        }

    }

    // Copy results from parameter to this:
    public static void copyResults(Link from, Link to, int level) {
        level++;
        if (from == null || to == null) {
            return;
        }

        if (from.getResult() != null) {
            to.setResult(from.getResult());
        }

        LinkedHashMap toChildren = to.getChildren();
        if (toChildren != null) {
            for (LinkIterator it = from.linkIterator(); it.hasNext();) {
                Link fromChild = it.nextLink();
                String name = fromChild.getName();
                Link toChild = (Link) toChildren.get(name);
                if (toChild != null) {
                    copyResults(fromChild, toChild, level);
                } else {
                    // case when ad-hoc results are added:
                    fromChild.setAdHoc(true);
                    toChildren.put(name, fromChild);
                }
            }
        }
    }

    public boolean isAdHoc() {
        return adHoc;
    }

    public void setAdHoc(boolean adHoc) {
        this.adHoc = adHoc;
    }

    public boolean isRetrieved() {
        return retrieved;
    }

    public void setRetrieved(boolean retrieved) {
        this.retrieved = retrieved;
    }

    public Map toMap() {
        Map map = super.toMap();
        toMapArray(map, TAG_PARENT_INDECES, parentIndeces);
        toMapArray(map, TAG_THIS_INDECES, thisIndeces);
        map.put(TAG_NAME, name);
        if (query != null) {
            map.put(TAG_QUERY, ((Mappable) query).toMap());
            map.put(TAG_QUERY_CLASS, query.getClass().getName());
        }

        return map;
    }

    public void fromMap(Map map) {
        super.fromMap(map);
        PropertyMap propertyMap = PropertyMap.toPropertyMap(map);
        parentIndeces = fromMapToIntArray(propertyMap, TAG_PARENT_INDECES);
        thisIndeces = fromMapToIntArray(propertyMap, TAG_THIS_INDECES);
        name = propertyMap.getProperty(TAG_NAME);
        Map queryMap = propertyMap.getMap(TAG_QUERY);
        if (queryMap != null) {
            String queryClassName = propertyMap.getProperty(TAG_QUERY_CLASS, true);
            try {
                query = (Query) Class.forName(queryClassName).newInstance();
            } catch (Exception e) {
               throw new OdalRuntimePersistencyException("Cannot instantiate class by name " + queryClassName, e);
            }
            ((Mappable) query).fromMap(queryMap);
        } 
    }

    protected void toMapArray(Map map, String tag, int [] array) {
        if (array != null) {
            String [] arrayS = new String[array.length];
            for (int i = 0; i < array.length; i++) {
                arrayS[i] = String.valueOf(array[i]);
            }
            map.put(tag, Arrays.asList(arrayS));
        }
    }


    protected int [] fromMapToIntArray(PropertyMap map, String tag) {
        int [] array = null;
        List list = map.getList(tag);
        if (list != null) {
            array = new int[list.size()];
            for (int i = 0; i < list.size(); i++) {
                String value = (String) list.get(i);
                int intValue = 0;
                if (value != null) {
                    intValue = Integer.parseInt(value);
                }
                array[i] = intValue;
            }
        }
        return array;
    }

    public String toString() {
        StringBuffer buffer = new StringBuffer(" Link : {");
        buffer.append("name = ").append(name);
        buffer.append(parentIndecesBuffer());
        buffer.append("; dependencyIndex = (").append(dependencyIndex).append(")");
        buffer.append("; path = ").append(getPathString());
        buffer.append("; parent path = ");

        StringBuffer parentIndecesBuffer = new StringBuffer("; parentIndeces [");
        if (parentIndeces != null) {
            for (int i = 0; i < parentIndeces.length; i++) {
                if (i > 0) {
                    parentIndecesBuffer.append(", ");
                }
                parentIndecesBuffer.append(parentIndeces[i]);
            }
        } else {
            parentIndecesBuffer.append("null");
        }
        parentIndecesBuffer.append("]");

        if (getParentLink() != null) {
            buffer.append(getParentLink().getPathString());
        } else {
            buffer.append("null");
        }
        buffer.append("; result = (").append(result).append(")");
        buffer.append("}");
        return super.toString() + buffer.toString();
    }

    /**
     * Returns summary string
     *
     * @return summary string
     */
    public String toSummaryString() {
        StringBuffer buffer = new StringBuffer(" Link<");
        buffer.append("name = ").append(name);
        buffer.append(parentIndecesBuffer()).append(">");
        return super.toString() + buffer.toString();
    }

    private StringBuffer parentIndecesBuffer() {
        StringBuffer parentIndecesBuffer = new StringBuffer("; parentIndeces [");
        if (parentIndeces != null) {
            for (int i = 0; i < parentIndeces.length; i++) {
                if (i > 0) {
                    parentIndecesBuffer.append(", ");
                }
                parentIndecesBuffer.append(parentIndeces[i]);
            }
        } else {
            parentIndecesBuffer.append("null");
        }
        parentIndecesBuffer.append("]");
        return parentIndecesBuffer;
    }

    public static final RelationshipType ONE_TO_MANY = RelationshipType.ONE_TO_MANY;
    public static final RelationshipType ONE_TO_ONE = RelationshipType.ONE_TO_ONE;
    public static final RelationshipType MANY_TO_ONE = RelationshipType.MANY_TO_ONE;
    public static final RelationshipType MANY_TO_MANY = RelationshipType.MANY_TO_MANY;

    public static final String INLINE_INNER = "inner";
    public static final String INLINE_OUTER = "outer";
    /**
     * Inner (or equi-) join mode:
     */
    public static final InlineMode INNER_JOIN_MODE = new InlineMode(INLINE_INNER);

    /**
     * Outer (left outer) join mode
     */
    public static final InlineMode OUTER_JOIN_MODE = new InlineMode(INLINE_OUTER);

    public static InlineMode toInlineMode(String modeName) {
        if (INLINE_INNER.equalsIgnoreCase(modeName)) {
            return INNER_JOIN_MODE;
        } else if (INLINE_OUTER.equalsIgnoreCase(modeName)) {
            return OUTER_JOIN_MODE;
        } else {
            throw new IllegalArgumentException("Unknown inline mode name: " + modeName);
        }
    }

    public boolean isInner() {
        return getInlineMode() == INNER_JOIN_MODE;
    }

    public boolean isOuter() {
        return getInlineMode() == OUTER_JOIN_MODE;
    }

    public void setInlineMode(String childName, InlineMode inlineMode) {
        getChild(childName).setInlineMode(inlineMode);
    }

    /**
     * Represents entities relationship in ER paradigm
     */
    public static class RelationshipType {

        public static final RelationshipType ONE_TO_MANY = new RelationshipType("one_to_many");
        public static final RelationshipType ONE_TO_ONE = new RelationshipType("one_to_one");
        public static final RelationshipType MANY_TO_ONE = new RelationshipType("many_to_one");
        public static final RelationshipType MANY_TO_MANY = new RelationshipType("many_to_many");

        private String name;

        protected RelationshipType(String name) {
            this.name = name;
        }

        public String toString() {
            return name;
        }

        public String getName() {
            return name;
        }

        public static RelationshipType name2type(String name) {
            if (ONE_TO_MANY.getName().equals(name)) {
                return ONE_TO_MANY;

            } else if (ONE_TO_ONE.getName().equals(name)) {
                return ONE_TO_ONE;

            } else if (MANY_TO_ONE.getName().equals(name)) {
                return MANY_TO_ONE;
            } else {
                throw new UnsupportedOperationException(name);
            }
        }
    }

    /**
     * Represents query inlining mode. Inlined queries are executed in the same SQL statement 
     * as the main query.
     */
    public static class InlineMode {

        private String name;

        protected InlineMode(String name) {
            this.name = name;
        }

        public String toString() {
            return name;
        }
    }
}
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.