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

com.draagon.meta.MetaData Maven / Gradle / Ivy

/*
 * Copyright 2002 Draagon Software LLC. All Rights Reserved.
 *
 * This software is the proprietary information of Draagon Software LLC.
 * Use is subject to license terms.
 */
package com.draagon.meta;

import com.draagon.meta.attr.AttributeDef;
import com.draagon.meta.attr.MetaAttribute;
import com.draagon.meta.attr.MetaAttributeNotFoundException;
import com.draagon.meta.validator.MetaValidator;
import com.draagon.meta.view.MetaView;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public abstract class MetaData implements Cloneable, Serializable {

    private final Map cacheValues = Collections.synchronizedMap(new WeakHashMap());
    private final CopyOnWriteArrayList children = new CopyOnWriteArrayList();
    private final CopyOnWriteArrayList attributeDefs = new CopyOnWriteArrayList();
    private final String name;

    private MetaData superData = null;
    private WeakReference parentRef = null;

    /**
     * Constructs the MetaData
     */
    public MetaData( String name ) {
        this.name = name;
    }
    
    public abstract Class getMetaDataClass();

    ////////////////////////////////////////////////////
    // SETTER / GETTER METHODS
    
    /**
     * Returns the Name of this piece of MetaData
     */
    public String getName() {
        return name;
    }

    /**
     * Sets the parent of the attribute
     */
    protected void attachParent(MetaData parent) {
        parentRef = new WeakReference(parent);
    }

    /**
     * Gets the parent MetaData.  Be careful as this might not be the
     * same as the metadata you retrieved this from as a child due to 
     * inheritance.   Use with care!
     */
    public MetaData getParent() {
        if (parentRef == null) {
            return null;
        }
        return parentRef.get();
    }

    /**
     * Sets the Super Data
     */
    public void setSuperData(MetaData superData) {
        this.superData = superData;
    }

    /**
     * Gets the Super Data
     */
    public MetaData getSuperData() {
        return superData;
    }

    ////////////////////////////////////////////////////
    // ATTRIBUTE METHODS
    /**
     * Sets an attribute of the MetaClass
     */
    public void addAttribute(MetaAttribute attr) {
        addChild(attr);
    }

    /**
     * Sets an attribute of the MetaClass
     */
    public void deleteAttribute(String name) throws MetaAttributeNotFoundException {
        try {
            deleteChild(name, MetaAttribute.class);
        } catch (MetaException e) {
            throw new MetaAttributeNotFoundException("MetaAtribute [" + name + "] not found in [" + toInternalString() + "]", name);
        }
    }

    /**
     * Sets an attribute value of the MetaData
     */
    public void setAttribute(String name, Object value) {
        MetaAttribute ma = null;
        try {
            ma = (MetaAttribute) getChild(name, MetaAttribute.class);
        } catch (MetaDataNotFoundException e) {
            throw new MetaAttributeNotFoundException("MetaAttribute [" + name + "] was not found in [" + toInternalString() + "]", name);
        }
        
        ma.setValue(value);
    }

    /**
     * Retrieves an attribute value of the MetaData
     */
    public Object getAttribute(String name)
            throws MetaAttributeNotFoundException {
        try {
            MetaAttribute ma = (MetaAttribute) getChild(name, MetaAttribute.class);
            return ma.getValue();
        } catch (MetaDataNotFoundException e) {
            throw new MetaAttributeNotFoundException( "MetaAtribute [" + name + "] not found in [" + toInternalString() + "]", name );
        }
    }

    /**
     * Retrieves all attribute names
     */
    public boolean hasAttribute(String name) {
        try {
            if (getChild(name, MetaAttribute.class, false) != null) {
                return true;
            }
        } catch (MetaDataNotFoundException e) {
        }
        
        return false;
    }

    /**
     * Retrieves all attribute names
     */
    public Collection getAttributes() {
        Collection attrs = new ArrayList();
        for (MetaData md : getChildren(MetaAttribute.class)) {
            attrs.add((MetaAttribute) md);
        }
        return attrs;
    }

    ////////////////////////////////////////////////////
    // CHILDREN METHODS
    
    /**
     * Whether the child data exists
     */
    protected boolean hasChild(String name, Class c) {
        try {
            getChild(name, c);
            return true;
        } catch (MetaDataNotFoundException e) {
            return false;
        }
    }

    /**
     * Adds a child MetaData object of the specified class type. If no class
     * type is set, then a child of the same type is not checked against.
     */
    public void addChild(MetaData data)
            throws InvalidMetaDataException {
        addChild(data, true);
    }

    /**
     * Adds a child MetaData object of the specified class type. If no class
     * type is set, then a child of the same type is not checked against.
     */
    public void addChild(MetaData data, boolean checkExists) 
            throws InvalidMetaDataException {
        
        if (data == null) {
            throw new IllegalArgumentException("Cannot add null MetaData");
        }
        
        if (checkExists) {
            try {
                MetaData d = getChild(data.getName(), data.getMetaDataClass());
                if (d.getParent() == this) {
                    if (d instanceof MetaAttribute
                            || d instanceof MetaValidator
                            || d instanceof MetaView /*|| d instanceof MetaField*/) {
                        deleteChild(d);
                    } else {
                        throw new InvalidMetaDataException("MetaData [" + data.toInternalString() + "] with name [" + data.getName() + "] already exists in [" + toInternalString() + "] as [" + d + "]");
                    }
                }
            } catch (MetaDataNotFoundException e) {
            }
        }
        
        data.attachParent(this);
        children.add(data);
    }
   
    /**
     * Deletes a child MetaData object of the given class
     */
    public void deleteChild(String name, Class c) {
        MetaData d = getChild(name, c);
        if (d.getParent() == this) {
            children.remove(d);
        } else {
            throw new MetaDataNotFoundException("You cannot delete MetaData with name [" + name + "] from a SuperData of [" + toInternalString() + "]", name );
        }
    }

    /**
     * Deletes a child MetaData object
     */
    public void deleteChild(MetaData data) {
        if (data.getParent() != this) {
            throw new IllegalArgumentException("MetaData [" + data.toInternalString() + "] is not a child of [" + toInternalString() + "]");
        }
        
        children.remove(data);
    }
    
    /**
     * Returns all MetaData children
     */
    protected Collection getChildren() {
        return getChildren(null);
    }

    /**
     * Returns all MetaData children which implement the specified class
     */
    protected  Collection getChildren(Class c) {
        
        // Get all the local children
        ArrayList al = new ArrayList();
        for (MetaData d : children) {
            if (c == null || c.isInstance(d)) {
                al.add( (T) d);
            }
        }

        // Add the super class's children
        if (getSuperData() != null) {
            for (MetaData d : getSuperData().getChildren(c)) {
                
                // We know it exists in the super class, so get it correctly, which adds
                // it to this class except for MetaAttributs
                // if ( tmp instanceof MetaAttribute ) d = tmp;
                // else d = getChild( tmp.getName(), tmp.getMetaDataClass() );

                boolean found = false;

                // Only add the field if it's not found in the super class
                for (MetaData sd : al) {
                    if (sd.getName().equals(d.getName())) {
                        found = true;
                    }
                }
                
                if (!found) {
                    //if (!( d instanceof MetaAttribute ))
                    //  d = getChild( d.getName(), d.getMetaDataClass() );

                    al.add( (T) d); //wrapMetaData( d ));
                }
            }
        }
        
        return al;
    }
    
    /**
     * Returns the first child record
     */
    protected  T getFirstChild(Class c) {
        Iterator i = getChildren(c).iterator();
        if (!i.hasNext()) {
            return null;
        }
        return i.next();
    }
    
    /**
     * Returns a child by the specified name of the specified class
     *
     * @param name The name of the child to retrieve. A null will return the
     * first child.
     */
    public final  T getChild(String name, Class c) throws MetaDataNotFoundException {
        return getChild(name, c, true);
    }

    protected final  T getChild(String name, Class c, boolean shouldThrow) throws MetaDataNotFoundException {
        return (T) getChildOfType( name, c, shouldThrow );
    }

    protected final MetaData getChildOfType(String name, Class c, boolean shouldThrow) throws MetaDataNotFoundException {
        
        for (MetaData d : children) {
            if ((name == null || d.getName().equals(name))
                    && (c == null || c.isInstance(d))) {
                return d;
            }
        }

        // See if it exists in the parent class
        if (getSuperData() != null) {
            try {
                MetaData md = getSuperData().getChild(name, c, shouldThrow);

                // If the MetaData is not an attribute, then clone, clear,
                //  and set the super data
                /*if ( !( md instanceof MetaAttribute ))
                 {
                    MetaData add = (MetaData) md.clone();
                    add.clearChildren();
                    add.setSuperData( md );
                    addChild( add, false );
                    return add;
                 }*/
                
                return md; //wrapMetaData( md );
            } 
            catch (MetaDataNotFoundException ex) {
            }
        }
        
        if (shouldThrow) {
            throw new MetaDataNotFoundException( "MetaData child of class [" + c + "] with name [" + name + "] not found in [" + toString() + "]", name );
        } else {
            return null;
        }
    }

    /**
     * Clears all children
     */
    protected void clearChildren() {
        children.clear();
    }

    /**
     * Clears all children of the specified type
     */
    protected void clearChildren(Class c) {
        for (MetaData d : children) {
            if (c == null || c.isInstance(d)) {
                children.remove(d);
            }
        }
    }

    ////////////////////////////////////////////////////
    // MISC METHODS

    /**
     * Returns a list of expected attributes
     */
    public List getAttributeDefs() {
        return attributeDefs;
    }

    /**
     * Add the specified attribute definitions
     */
    public void addAttributeDef( AttributeDef def ) {
        attributeDefs.addIfAbsent( def );
    }
    
    /**
     * Validates the state of the data in the MetaData object
     */
    public void validate() {
        
        if (getName() == null) {
            throw new InvalidMetaDataException("MetaData has no name");
        }

        // Validate the Attribute options
        for (AttributeDef ao : getAttributeDefs()) {
            
            boolean has = hasAttribute(ao.getName());

            // Check for required fields
            if (ao.isRequired() && !has) {
                throw new InvalidMetaDataException("Required attribute [" + ao.getName() + "] was not found");
            }

            // Check for proper class types
            if (has && ao.getType() != null) {
                try {
                    Object obj = getAttribute(ao.getName());
                    if (!ao.getType().isInstance(obj)) {
                        throw new InvalidMetaDataException("Attribute [" + ao.getName() + "] was not an instance of class [" + ao.getType() + "]");
                    }
                } catch (MetaAttributeNotFoundException e) {
                }
            }
        }

        // Validate the children
        for (MetaData d : getChildren()) {
            d.validate();
        }
    }
    
    public MetaData wrap() {
        MetaData d = (MetaData) clone();
        d.clearChildren();
        d.setSuperData(this);
        return d;
    }

    /**
     * Clones this MetaData object
     */
    @Override
    public Object clone() {
        
        MetaData v;
        try {
            Constructor c = (Constructor) this.getClass().getConstructor(String.class);
            v = c.newInstance(name);
        } catch (Exception e) {
            throw new RuntimeException("Could not create new instance of MetaData class [" + getClass() + "]: " + e.getMessage(), e);
        }
        
        v.parentRef = parentRef;
        
        for (MetaData md : getChildren()) {
            v.addChild((MetaData) md.clone());
            //v.mChildren = (ArrayList) mChildren.clone();
        }
        
        return v;
    }

    /**
     * Sets a cache value for this piece of MetaData
     */
    public void setCacheValue(Object key, Object value) {
        //ystem.out.println( "SET [" + key + "] = " + value );
        cacheValues.put(key, value);
    }

    /**
     * Retrieves a cache value for this piece of MetaData
     */
    public Object getCacheValue(Object key) {
        return cacheValues.get(key);
    }

    /**
     * Returns a string representation of the MetaData
     */
    private String toInternalString() {
        String name = getClass().getName();
        int i = name.lastIndexOf('.');
        if (i >= 0) {
            name = name.substring(i + 1);
        }
        
        if (getParent() == null) {
            return name + "{" + getName() + "}";
        } else {
            return name + "{" + getName() + "}@" + getParent().toInternalString();
        }
    }

    /**
     * Returns a string representation of the MetaData
     */
    public String toString() {
        String name = getClass().getName();
        int i = name.lastIndexOf('.');
        if (i >= 0) {
            name = name.substring(i + 1);
        }
        
        if (getParent() == null) {
            return name + "{" + getName() + "}";
        } else {
            return name + "{" + getName() + "}@" + getParent().toString();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy