Package org.dmd.dmc

Source Code of org.dmd.dmc.DmcOmni

//  ---------------------------------------------------------------------------
//  dark-matter-data
//  Copyright (c) 2011 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;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;

import org.dmd.dmc.rules.DmcRuleExceptionSet;
import org.dmd.dmc.rules.RuleTracerIF;
import org.dmd.dmc.types.DmcTypeDmcObjectName;
import org.dmd.dmc.types.Modifier;
import org.dmd.dms.generated.dmo.MetaDMSAG;
import org.dmd.dms.generated.types.DmcTypeModifierMV;

/**
* The DmcOmni (short for omnipresent) provides a single point of access to information
* and settings that is useful in the operational environment of Dark Matter Objects.
*/
public class DmcOmni implements DmcNameResolverIF {

  // Our singleton handle
  protected static DmcOmni       omni;
 
  // Indicates if we want to track back references at the DMO level
  boolean                trackBackRefs;
 
  // Indicates if we're supported lazy resolution of object references
  boolean                lazyResolution;
 
  // Indicates if we're supported automatic resolution of object references
  // based on the application of modifiers
  boolean                autoResolution;
 
  // While doing lazy resolution, if we are unable to find an object, this
  // option tells us what to do. If it's true, we will toast the object
  // reference, thus "healing" the broken link. If you've provided a logger,
  // the dead reference will be logged.
  boolean                cleanUpDeadRefs;
 
  // Normally, we don't track schema references because we don't always
  // have the schema objects available. However, for certain tools/utilities,
  // such as the documentation tools, we want to turn this tracking on.
  boolean                trackSchemaReferences;
 
  // The logger through which various log messages can be sent
  DmcLoggerIF              logger;
 
  // Indicates if we want to tracker the execution of rules
  boolean                traceRules;
 
  // You can specify a component to handle rule tracing information
  RuleTracerIF            ruleTracer;
 
  // The set of things that can resolve object names for us. This allows for
  // lazy resolution of object references at the DMO level.
  ArrayList<DmcNameResolverIF>    resolvers;
 
  // The map where we store dmdID to DmcClassInfo for all Dark Matter Schema
  // (DMSAGs) that have been loaded
  TreeMap<Integer,DmcClassInfo>    idToClass;
 
  TreeMap<String,DmcClassInfo>    stringToClass;
 
  // The map where we store dmdID to DmcAttributeInfo for all Dark Matter Schema
  // (DMSAGs) that have been loaded
  TreeMap<Integer,DmcAttributeInfo>  idToAttr;
 
  TreeMap<String,DmcAttributeInfo>  stringToAttribute;
 
  // A map of the name builders for each naming type. The key is the name of
  // of the type e.g. StringName, DotName etc. For any DmcObjectName instance,
  // we can getNameClass() which should be in this map. From there, we can
  // ask the name builder to create an appropriate DmcTypeDmcObjectName to
  // to wrap the type i.e. associate its designatedNameAttribute with it.
  TreeMap<String,DmcNameBuilderIF>  nameBuilders;
 
  // A map of the filter builders for each naming type. The key is the name of
  // of the type e.g. ClassFilter, NameFilter etc. For any DmcFilter instance,
  // we can getFilterClass() which should be in this map. From there, we can
  // ask the filter builder to create an appropriate DmcTypeDmcFilter to
  // to wrap the type i.e. associate its designatedFilterAttribute with it.
  TreeMap<String,DmcFilterBuilderIF>  filterBuilders;
 
  // The cache that will be notified of required reference modifications
  // when an object with backrefs is deleted. This is only used if backref
  // tracking is enabled.
  DmcCacheIF              cache;
 
  // Named "slices" that can be used to retrieve a subset of attributes from
  // an object.
  TreeMap<String,DmcSliceInfo>    slices;
 
  // The set of recoginized types, either directly defined via type definitions
  // of internally created.
  TreeMap<String,DmcTypeInfo>      types;
 
//  TreeMap<String,DmcAttributeSchemaIF>  loadedSchemas;
 
  TreeMap<String,DmcCompactSchemaIF>  loadedCompactSchemas;
 
  /**
   * Protected constructor called when the omni singleton is required.
   */
  protected DmcOmni(){
    init();
  }
 
  /**
   * Resets the DmcOmni to its initial state.
   */
  public void reset(){
    init();
  }
 
  /**
   * Initializes our values.
   */
  void init(){
    trackBackRefs       = false;
    lazyResolution      = false;
    autoResolution      = false;
    cleanUpDeadRefs      = false;
    trackSchemaReferences  = false;
    logger          = null;
    traceRules        = false;
    ruleTracer        = null;
    resolvers        = null;
    idToClass        = new TreeMap<Integer, DmcClassInfo>();
    stringToClass      = new TreeMap<String, DmcClassInfo>();
    idToAttr        = new TreeMap<Integer, DmcAttributeInfo>();
    stringToAttribute    = new TreeMap<String, DmcAttributeInfo>();
    nameBuilders      = new TreeMap<String, DmcNameBuilderIF>();
    filterBuilders      = new TreeMap<String, DmcFilterBuilderIF>();
    slices          = new TreeMap<String, DmcSliceInfo>();
    types          = new TreeMap<String, DmcTypeInfo>();
    cache          = null;
//    loadedSchemas      = new TreeMap<String, DmcAttributeSchemaIF>();
    loadedCompactSchemas  = new TreeMap<String, DmcCompactSchemaIF>();
   
//    addAttributeSchema(MetaASAG.instance());
    addCompactSchema(MetaDMSAG.instance());
  }
 
  static public synchronized DmcOmni instance(){
    if (omni == null)
      omni = new DmcOmni();
   
    return(omni);
  }
 
  /**
   * This method should be used with caution! Generally, we don't attempt to perform
   * back reference tracking on schema related references, but, in certain tools/utilities,
   * we make use of this functionality.
   * @param f Set to true if we want perform back reference tracking on schema related objects.
   */
  public void setTrackSchemaReferences(boolean f){
    trackSchemaReferences = f;
  }
 
  /**
   * This method is called from the DmcObject to determine whether or not are
   * particular attribute should have its reference tracked.
   * @param attributeID
   * @return true if we want to reference track the attribute.
   */
  public boolean trackThisAttribute(int attributeID){
    // If trackSchemaReferences is turned on, we will track all attributes
    if (trackSchemaReferences)
      return(true);
    // If trackSchemaReferences is turned off (the default), we will only
    // attempt back reference tracking if the attribute ID is beyond the
    // maximum ID of the meta schema.
    else if (attributeID > MetaDMSAG.instance().getSchemaMaxID())
      return(true);
    return(false);
  }
 
  /**
   * @return true if DMO back reference tracking should be performed.
   */
  public boolean backRefTracking(){
    return(trackBackRefs);
  }
 
  /**
   * Turns backref tracking on/off.
   * @param f set to true to turn it on.
   */
  public void backRefTracking(boolean f){
    trackBackRefs = f;
  }
 
  /**
   * @return true if lazy resolution is turned on.
   */
  public boolean lazyResolution(){
    return(lazyResolution);
  }
 
  /**
   * Turns lazy resolution on/off.
   * @param f set to true to turn it on.
   */
  public void lazyResolution(boolean f){
    lazyResolution = f;
  }
 
  /**
   * @return true if auto resolution is turned on.
   */
  public boolean autoResolution(){
    return(autoResolution);
  }
 
  /**
   * Turns auto resolution on/off.
   * @param f set to true to turn it on.
   */
  public void autoResolution(boolean f){
    autoResolution = f;
  }
 
  /**
   * @return true if clean up of dead references is turned on.
   */
  public boolean cleanUpDeadRefs(){
    return(cleanUpDeadRefs);
  }
 
  /**
   * Turns clean up of dead references on/off.
   * @param f set to true to turn it on.
   */
  public void cleanUpDeadRefs(boolean f){
    cleanUpDeadRefs = f;
  }
 
  /**
   * @return the logger if it has been set.
   */
  public DmcLoggerIF logger(){
    return(logger);
  }
 
  /**
   * Sets the logger.
   * @param l the logger.
   */
  public void logger(DmcLoggerIF l){
    logger = l;
  }
 
  /**
   * This method is called from DmcTypeNamedObjectREF when it is unable to resolve a reference.
   * @param referrer The object that had the reference.
   * @param viaAttribute The object reference attribute.
   * @param referenceTo The name that couldn't be resolved.
   */
  public void logDeadReference(DmcObject referrer, DmcAttribute<?> viaAttribute, DmcObjectName referenceTo){
    if (logger != null){
      logger.logDeadReference(referrer, viaAttribute, referenceTo);
    }
  }
 
  /**
   * Adds a name resolver. Any number of resolvers may be added. When resolving a name, the
   * resolvers will be consulted in the order in which they were added. Name resolution stops
   * after the first positive name resolution, meaning that your name resolvers should have
   * mutually exclusive name spaces.
   * @param res The name resolver.
   */
  public void addResolver(DmcNameResolverIF res){
    if (res == null)
      throw(new IllegalStateException("Name resolver is null! Did you forget to initialize it?"));
   
    if (resolvers == null)
      resolvers = new ArrayList<DmcNameResolverIF>();
   
    resolvers.add(res);
  }
 
  /**
   * Dark Matter Schema Auto Generated (DMSAGs) are generated by the DMO Generator utility and
   * placed in the generated/dmo folder. DMSAGs contain a mapping from Dark Matter Data IDs (dmdID)
   * to the attributes/classes they identify). Since dmdIDs are the only things stored at the DmcAttribute
   * level, we have to be able to access the DmcAttributeInfo when it is lost in whatever
   * communication mechanism is being used between client/server, browser/servlet etc. The DmcOmni
   * provides access to these mappings.
   * @param schema
   */
  public void addCompactSchema(DmcCompactSchemaIF schema){
   
//DebugInfo.debug("Loading compact schema: " + schema.getSchemaName());
    // If we already have the schema, return
    if (loadedCompactSchemas.get(schema.getSchemaName()) != null)
      return;
   
    Iterator<DmcAttributeInfo> info = schema.getAttributeInfo();
    if (info != null){
      while(info.hasNext()){
        DmcAttributeInfo ai = info.next();
        DmcAttributeInfo existing = idToAttr.get(ai.id);
        if (existing != null)
          throw(new IllegalStateException("Clashing attribute IDs: " + existing + "  <>  " + ai));
       
        idToAttr.put(ai.id, ai);
       
        existing = stringToAttribute.get(ai.name);
        if (existing != null)
          throw(new IllegalStateException("Clashing attribute names: " + existing + "  <>  " + ai));
        stringToAttribute.put(ai.name, ai);
      }
    }
   
    Iterator<DmcClassInfo> cinfo = schema.getClassInfo();
    if (cinfo != null){
      while(cinfo.hasNext()){
        DmcClassInfo ci = cinfo.next();
       
//DebugInfo.debug(ci.toString());       
        DmcClassInfo existing = idToClass.get(ci.id);
        if (existing != null){
          throw(new IllegalStateException("Clashing class IDs: " + existing + "  <>  " + ci));
        }
        idToClass.put(ci.id, ci);
       
        existing = stringToClass.get(ci.name);
        if (existing != null){
          throw(new IllegalStateException("Clashing class names: " + existing + "  <>  " + ci));
        }
        stringToClass.put(ci.name, ci);
       
        if (ci.derivedFrom != null){
          ci.derivedFrom.addDerivedClass(ci);
        }
      }
    }
   
    Iterator<DmcNameBuilderIF> nbuilders = schema.getNameBuilders();
    if (nbuilders != null){
      while(nbuilders.hasNext()){
        DmcNameBuilderIF builder = nbuilders.next();
        nameBuilders.put(builder.getNameClass(), builder);
      }
    }
   
    Iterator<DmcFilterBuilderIF> fbuilders = schema.getFilterBuilders();
    if (fbuilders != null){
      while(fbuilders.hasNext()){
        DmcFilterBuilderIF builder = fbuilders.next();
        filterBuilders.put(builder.getFilterClass(), builder);
      }
    }
       
    Iterator<DmcSliceInfo> sliceIT = schema.getSliceInfo();
    if (sliceIT != null){
      while(sliceIT.hasNext()){
        DmcSliceInfo dsi = sliceIT.next();
        slices.put(dsi.getName(), dsi);
      }
    }
   
    Iterator<DmcTypeInfo> typeIT = schema.getTypeInfo();
    if (typeIT != null){
      while(typeIT.hasNext()){
        DmcTypeInfo dti = typeIT.next();
        types.put(dti.name, dti);
      }
    }
   
    loadedCompactSchemas.put(schema.getSchemaName(), schema);
  }
 
  public DmcTypeDmcObjectName<?> buildName(DmcObjectName name){
    DmcNameBuilderIF builder = nameBuilders.get(name.getNameClass());
    if (builder == null){
      throw(new IllegalStateException("No DmcNameBuilderIF available for name class: " + name.getNameClass() + " - ensure that you have loaded the appropriate ASAGs."));
    }
   
    DmcAttributeInfo ai = idToAttr.get(builder.getNameAttributeID());
     
    return(builder.getNewNameHolder(name,ai));
  }
 
  /**
   * Sets the implementor of the DmcCacheIF that will be notified when objects with backrefs
   * are deleted.
   * @param c The cache.
   */
  public void setCacheIF(DmcCacheIF c){
    cache = c;
  }
 
  public void removeReferences(DmcTypeModifierMV mods){
    // NOTE: all of the backref modifiers are stored in modifier that gets passed in, however
    // each Modifier is for a different object (potentially). We have to apply each Modifier
    // as a single operation, thus we create a new DmcTypeModifierMV and add the single Modifier
    // to it. We don;t attempt to reuse the same modifier because these may be used in events.
    Iterator<Modifier> it = mods.getMV();
    while(it.hasNext()){
      DmcTypeModifierMV single = new DmcTypeModifierMV();
      Modifier mod = it.next();
      try {
        // Add the Modifier to our temporary
        single.add(mod);
       
        if (cache == null)
          ((DmcObject)mod.getReferringObject()).applyModifier(single);
        else
          cache.applyModification(mod.getReferringObject(), single);
       
      } catch (DmcValueException e) {
        throw(new IllegalStateException("Adding a prebuilt Modifier to a DmcTypeModifierMV shouldn't thrown an exception."));
      } catch (DmcValueExceptionSet e) {
        throw(new IllegalStateException("Removing a back reference shouldn't thrown an exception."));
      }
    }
  }
 
  /**
   * Tries to find the specified class by its name.
   * @param cn The class name.
   * @return The class info if it's available.
   */
  public DmcClassInfo getClassInfo(String cn){
    return(stringToClass.get(cn));
  }
 
  /**
   * Tries to find the specified class by its id.
   * @param id The class id.
   * @return The class info if it's available.
   */
  public DmcClassInfo getClassInfo(Integer id){
    return(idToClass.get(id));
  }
 
  /**
   * @param tn the type name
   * @return the type info.
   */
  public DmcTypeInfo getTypeInfo(String tn){
    return(types.get(tn));
  }
 
  /**
   * Returns the DmcAttributeInfo associate with the ID or complains bitterly that you've
   * forgotten to prime the DmcOmni with the generated <schema>DMSchemaAG related
   * to the identifier in question. This method is usually called by base classes like
   * DmcAttribute when it's trying to dump things in OIF format.
   * @param id The attribute's ID.
   * @return the attribute info for the specified ID.
   */
  public DmcAttributeInfo getInfo(Integer id){
    DmcAttributeInfo ai = idToAttr.get(id);
   
    if (ai == null)
      return(null);
//    if (ai == null)
//      System.out.println("DmcOmni.getInfo() - can't find: " + id);
//      throw(new IllegalStateException(" Failed to get DmcAttributeInfo for id: " + id + "  - ensure that you have loaded the attribute schema in DmcOmni."));
   
    return(ai);
  }
 
  /**
   * Tries to find the specified attribute by its name.
   * @param an The attribute name.
   * @return The attribute info if it's available.
   */
  public DmcAttributeInfo getAttributeInfo(String an){
    return(stringToAttribute.get(an));
  }
 
  /**
   * The DmcOmni can act as a global name resolver. This method will attempt to
   * find the named object in any name resolvers that have been registered.
   */
  @Override
  public DmcObject findNamedDMO(DmcObjectName name) {
    DmcObject rc = null;
    for(DmcNameResolverIF res: resolvers){
      if ( (rc = res.findNamedDMO(name)) != null)
        break;
    }
   
    return(rc);
  }

  /**
   * The DmcOmni can act as a global name resolver. This method will attempt to
   * find the named object in any name resolvers that have been registered.
   */
  @Override
  public DmcNamedObjectIF findNamedObject(DmcObjectName name) {
    DmcNamedObjectIF rc = null;
   
    for(DmcNameResolverIF res: resolvers){
      DmcObject obj = res.findNamedDMO(name);
      if ( obj != null){
        rc = (DmcNamedObjectIF) obj;
        break;
      }
    }
   
    return(rc);
  }
 
  @Override
  public DmcNamedObjectIF findNamedObject(DmcObjectName name, int attributeID) {
    DmcNamedObjectIF rc = null;
   
    for(DmcNameResolverIF res: resolvers){
      rc = res.findNamedObject(name,attributeID);
     
      if ( rc != null)
        break;
    }
   
    return(rc);
  }

  /**
   * This method displays the currently loaded attribute schemas in dmdID order.
   */
  public void dumpASAG(){
    for(DmcAttributeInfo ai : idToAttr.values()){
      System.out.println(ai.toString());
    }
  }
 
  /**
   * Returns the slice information if it's available. Slice information is generated for SliceDefinitions
   * specified as part of your schema and indicate a subset of attributes to be returned in a GetResponse.
   * @param name the name of the slice.
   * @return The slice information if it's available.
   */
  public DmcSliceInfo getSliceInfo(String name){
    DmcSliceInfo rc = slices.get(name);
   
    if (rc == null)
      throw(new IllegalStateException("Unknown slice requested: " + name));
   
    return(rc);
  }
 
  ///////////////////////////////////////////////////////////////////////////
 
  public boolean ruleTracing(){
    return(traceRules);
  }
 
  public void ruleTracing(boolean f){
    traceRules = f;
  }
 
  public void ruleTracer(RuleTracerIF t){
    ruleTracer = t;
  }
 
  public void ruleExecuted(String info){
    if (traceRules){
      if (ruleTracer != null)
        ruleTracer.ruleExecuted(info);
    }
  }
 
  public void ruleAdded(String info){
    if (traceRules){
      if (ruleTracer != null)
        ruleTracer.ruleAdded(info);
    }
  }
 
  public void ruleFailed(DmcRuleExceptionSet errors){
    if (traceRules){
      if (ruleTracer != null)
        ruleTracer.ruleFailed(errors);
    }
  }

}
TOP

Related Classes of org.dmd.dmc.DmcOmni

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.