Package org.dmd.dmc.types

Source Code of org.dmd.dmc.types.DmcTypeNamedObjectREF

//  ---------------------------------------------------------------------------
//  dark-matter-data
//  Copyright (c) 2010 dark-matter-data committers
//  ---------------------------------------------------------------------------
//  This program is free software; you can redistribute it and/or modify it
//  under the terms of the GNU Lesser 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 Lesser General Public License for
//  more details.
//  You should have received a copy of the GNU Lesser General Public License along
//  with this program; if not, see <http://www.gnu.org/licenses/lgpl.html>.
//  ---------------------------------------------------------------------------
package org.dmd.dmc.types;

import java.io.Serializable;
import java.util.Iterator;

import org.dmd.dmc.DmcAttribute;
import org.dmd.dmc.DmcAttributeInfo;
import org.dmd.dmc.DmcNameResolverIF;
import org.dmd.dmc.DmcNamedObjectIF;
import org.dmd.dmc.DmcNamedObjectREF;
import org.dmd.dmc.DmcObject;
import org.dmd.dmc.DmcObjectName;
import org.dmd.dmc.DmcOmni;
import org.dmd.dmc.DmcValueException;
import org.dmd.dms.generated.enums.ModifyTypeEnum;
import org.dmd.dms.generated.enums.ValueTypeEnum;

/**
* The DmcTypeNamedObjectREF is a base type from which all references to named objects
* are derived. This stuff is a bit complicated and this class overrides most of the
* basic functionality of the DmcAttribute to make this happen. This is because unlike
* basic attribute types, types derived from this one allow you to set the contents of
* the attribute to be a DmcObjectName, or a DmcObject that implements the DmcNamedObjectIF
* interface.
* <P>
* The values of this kind of attribute are derived from DmcNamedObjectREF which allows
* you to store just the name of an object, or the name of the object and the object itself.
* This provides the concept of resolved/unresolved object references. For instance, if you
* parse a bunch of objects from a file and they contain object reference attributes, they
* will appear as just the names of other objects. Later, you can attempt to resolve
* these references (or not). Depending on the context in which you're using your data,
* this mechanism gives you the option of lazily resolving (or perhaps retrieving) the
* objects to which this type of attribute refers.
*/
@SuppressWarnings({ "serial", "unchecked", "rawtypes" })
abstract public class DmcTypeNamedObjectREF<HELPER extends DmcNamedObjectREF, NAMETYPE extends DmcObjectName> extends DmcAttribute<HELPER> implements Serializable {
   
  /**
   * Constructs a new object reference attribute.
   */
  public DmcTypeNamedObjectREF(){
  }
 
  public DmcTypeNamedObjectREF(DmcAttributeInfo ai){
    super(ai);
  }
   
  /**
   * @return A new DmcNamedObjectREF derivative instance.
   */
  abstract protected HELPER getNewHelper();
 
  abstract protected NAMETYPE getNewName();
 
  /**
   * Checks if the object is an instance of the appropriate type.
   * @param value The value to be tested.
   * @return True if the object is the appropriate type.
   */
  abstract protected boolean isDMO(Object value);
 
  abstract protected String getDMOClassName();
 
  /**
   * Attempts to resolve references with the specified name resolver.
   * @param rx The resolver.
   * @throws DmcValueException 
   */
  public void resolveReferences(DmcNameResolverIF rx) throws DmcValueException {
    if (getAttributeInfo().valueType == ValueTypeEnum.SINGLE){
      HELPER ref = getSV();
      if (ref.getObject() == null){
        DmcNamedObjectIF obj = (DmcNamedObjectIF) rx.findNamedDMO(ref.getObjectName());
        if (obj == null)
          throw(new DmcValueException("Could not resolve reference to: " + ref.getObjectName() + " via attribute: " + getName()));
         
        ref.setObject(obj);
      }
    }
    else{
      Iterator<HELPER> it = getMV();
      if (it != null){
        while(it.hasNext()){
          HELPER ref = it.next();
          if (ref.getObject() == null){
            DmcNamedObjectIF obj = (DmcNamedObjectIF) rx.findNamedDMO(ref.getObjectName());
            if (obj == null)
              throw(new DmcValueException("Could not resolve reference to: " + ref.getObjectName() + " via attribute: " + getName()));
             
            ref.setObject(obj);
          }
        }
      }
    }
  }
 
  /**
   * This method will remove back references that are associated with this reference
   * attribute. This is used when removing a reference attribute from an object.
   */
  public void removeBackReferences(){
    // If backref tracking isn't on, don't bother
//    if (DmcOmni.instance().backRefTracking() && (attrInfo.id> 200) ){
    if (DmcOmni.instance().backRefTracking() && DmcOmni.instance().trackThisAttribute(getAttributeInfo().id) ){
      if (getAttributeInfo().valueType == ValueTypeEnum.SINGLE){
        HELPER ref = getSV();
        if (ref != null){
          if (ref.getObject() != null){
            if (ref.getBackrefModifier() != null)
              ((DmcObject)ref.getObject()).removeBackref(ref.getBackrefModifier());
          }
        }
      }
      else{
        Iterator<HELPER> it = getMV();
        if (it != null){
          while(it.hasNext()){
            HELPER ref = it.next();
            if (ref != null){
              if (ref.getObject() != null){
                if (ref.getBackrefModifier() != null)
                  ((DmcObject)ref.getObject()).removeBackref(ref.getBackrefModifier());
              }
            }
          }
        }
      }
    }
  }
 
  /**
   * This method is called from derived classes if the lazy resolution mechanism has been
   * turned on via the DmcOmni.
   * <P>
   * We try to find the object(s) referred to in the reference. If so, we set the object on the
   * reference (thus making it resolved).
   * <P>
   * We also check to see if backref tracking has been turned on in DmcOmni. If so, we create
   * the backref modifier and add it to the object we're referring to.
   * <P>
   * If the reference(s) can't be resolved we return a flag that indicates that the attribute
   * should remove itself from the object (since there's nothing of value in it).
   * @param referrer The object doing the referring.
   * @return true if this attribute needs to be removed from the object.
   */
  public boolean doLazyResolution(DmcObject referrer){
    boolean deleteUs = false;
   
    // If we're already resolved, don't bother trying again
    if (weAreResolved())
      return(deleteUs);
   
    if (getAttributeInfo() == null){
//      if ( (attrInfo = DmcOmni.instance().getInfo(ID)) == null)
        throw (new IllegalStateException("Unable to get attribute info for ID: " + ID));
    }
   
    if (getAttributeInfo().valueType == ValueTypeEnum.SINGLE){
      DmcNamedObjectREF<?> ref = getSV();
     
      // We can't resolve the reference, so we need to be removed
      if (!resolveIt(referrer, ref))
        deleteUs = true;
    }
    else{
      if (getAttributeInfo().indexSize == 0){
          Iterator<DmcNamedObjectREF<?>> it = (Iterator<DmcNamedObjectREF<?>>) getMV();
          while(it.hasNext()){
            DmcNamedObjectREF<?> ref = it.next();
            if (!resolveIt(referrer, ref)){
              // Delete the reference from our multi-valued container - we can do
              // this safely because we're iterating over a copy of the collection
              del(ref);
            }
          }
         
          // There's nothing left in the collection, so we need to be removed
          if (getMVSize() == 0)
            deleteUs = true;
      }
      else{
        boolean anyResolved = false;
        for(int index=0; index<getMVSize(); index++){
          DmcNamedObjectREF<?> ref = getMVnth(index);
          if (ref == null)
            continue;
            if (resolveIt(referrer, ref)){
              anyResolved = true;
            }
            else{
              // Set the index slot to null
              try {
              setMVnth(index, null);
            } catch (DmcValueException e) {
              throw(new IllegalStateException("Nulling an indexed attribute slot should not cause an exception."));
            }
            }
        }
       
        if (!anyResolved)
          deleteUs = true;
      }
    }
   
    return(deleteUs);
  }
 
  /**
   * Determines of the reference can be resolved.
   * @param referrer The object doing the referring.
   * @param ref The object reference.
   * @return true if the reference can be resolved.
   */
  private boolean resolveIt(DmcObject referrer, DmcNamedObjectREF ref){
    boolean resolved = true;
   
    DmcObject obj = DmcOmni.instance().findNamedDMO(ref.getObjectName());
   
    // Couldn't find it - nuttin' we can do 'bout dat!
    if (obj == null){
      DmcOmni.instance().logDeadReference(referrer, this, ref.getObjectName());
     
      if (DmcOmni.instance().cleanUpDeadRefs())
        resolved = false;
    }
    else{
      // Set the object in the reference
      ref.setObject((DmcNamedObjectIF) obj);
     
      // And if backref tracking is on, inform the object that it's being tracked
      if (DmcOmni.instance().backRefTracking()){
        if (referrer.supportsBackrefTracking()){
          Modifier backrefMod = null;
         
          DmcAttribute<?> mod = this.getNew();
          mod.setAttributeInfo(getAttributeInfo());
          try {
            if (getAttributeInfo().valueType == ValueTypeEnum.SINGLE)
              mod.set(ref);
            else
              mod.add(ref);
          } catch (DmcValueException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
         
          if (getAttributeInfo().valueType == ValueTypeEnum.SINGLE)
            backrefMod = new Modifier(ModifyTypeEnum.SET,mod,referrer);
          else
            backrefMod = new Modifier(ModifyTypeEnum.ADD,mod,referrer);
         
          obj.addBackref(backrefMod);
         
//System.out.println("Resolved ref " + ref.getObjectName().getNameString() + " hash = " + System.identityHashCode(ref));
          // And tell the reference it's back reference modifier
          ref.setBackrefModifier(backrefMod);
        }
      }
    }
   
    return(resolved);
  }
 
    protected boolean weAreResolved(){
      boolean rc = false;
     
      if (getAttributeInfo().valueType == ValueTypeEnum.SINGLE){
        DmcNamedObjectREF<?> ref = getSV();
        if (ref.getObject() != null)
          rc = true;
      }
      else{
        if (getAttributeInfo().indexSize == 0){
          Iterator<DmcNamedObjectREF<?>> it = (Iterator<DmcNamedObjectREF<?>>) getMV();
          if (DmcOmni.instance().cleanUpDeadRefs()){
            // IF we're cleaning up dead refs, we need only check the first
            // element to see if we're resolved. That's because it's an all
            // or nothing deal - we resolve everything in one shot and if something
            // isn't resolved, it will have been tossed
            DmcNamedObjectREF<?> ref = it.next();
              if (ref.getObject() != null)
                rc = true;
          }
          else{
            // Otherwise, we must cycle through all refs
            rc = true;
            while(it.hasNext()){
              if (it.next().getObject() == null){
                rc = false;
                break;
              }
            }
          }
        }
        else{
          // For indexed attributes we have to cycle through everything regardless
          rc = true;
        for(int index=0; index<getMVSize(); index++){
          DmcNamedObjectREF<?> ref = getMVnth(index);
          if (ref == null)
            continue;
          if (ref.getObject() == null){
            rc = false;
            break;
          }
        }
        }
      }
     
      return(rc);
    }



}
TOP

Related Classes of org.dmd.dmc.types.DmcTypeNamedObjectREF

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.