Package com.gammastream.validity

Source Code of com.gammastream.validity.GSVEngine

package com.gammastream.validity;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.webobjects.appserver.xml.WOXMLDecoder;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EOModel;
import com.webobjects.eoaccess.EOModelGroup;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSPathUtilities;
import com.webobjects.foundation.NSValidation;

/**
*  This is Validity's validation engine. This class loads and
*  applies the rules you have modeled in your Validity model file.
*  This class is accessed via a singleton accessor.
*
@author GammaStream Technologies, Inc.
*/
public final class GSVEngine {

    /**********************************  STATIC  **********************************/
   
    /**
     *  Key used to access the Validity exception dictionary from
     *  NSValidation.Exception's userinfo dictionary.
     */
    public static String ERROR_DICTIONARY_KEY = "GSVExceptions";
   
    //internal constants used to determine when a rule should be applied.
    private static int ON_SAVE = 1;
    private static int ON_INSERT = 2;
    private static int ON_UPDATE = 3;
    private static int ON_DELETE = 4;
    private static int ON_DEMAND = 5;
   
    //GSVEngine is a singlet class, this iVar stores the single instance.
    private static GSVEngine _sharedValidationEngine = null;
   
    /**
     *  Creates a new GSVEngine if one is not already created, and returns the shared instance.
     *
     *  @return The shared validation engine.
     */
    public static GSVEngine sharedValidationEngine(){
        if( _sharedValidationEngine == null ){
            //NSLog.debug.appendln("*** Validity: GSVEngine.sharedValidationEngine(): Creating Shared Validation Engine");
            _sharedValidationEngine = new GSVEngine();
        }
        return _sharedValidationEngine;
    }

    public static NSValidation.ValidationException exceptionByAppendingErrorToException(String errorMessage, String key, NSValidation.ValidationException ex){
        NSMutableDictionary userInfo = null;
        NSMutableDictionary errorDict = null;
        NSMutableArray errorList = null;
        NSValidation.ValidationException returnException = ex;
       
        //get or create the userInfo dictionary
        if( returnException == null || returnException.userInfo() == null ){
            userInfo = new NSMutableDictionary(new NSMutableDictionary(), GSVEngine.ERROR_DICTIONARY_KEY);
        } else {
            userInfo = new NSMutableDictionary(returnException.userInfo());
        }
       
        //get or create the GSV error dictionary
        errorDict = (NSMutableDictionary)userInfo.objectForKey(GSVEngine.ERROR_DICTIONARY_KEY);
        if( errorDict == null ){
            errorDict = new NSMutableDictionary();
            userInfo.setObjectForKey(errorDict, GSVEngine.ERROR_DICTIONARY_KEY);
        }
       
        //get or create the gsv error list
        errorList = (NSMutableArray)errorDict.objectForKey(key);
        if( errorList == null ){
            errorList = new NSMutableArray();
            errorDict.setObjectForKey(errorList, key);
        }
       
        //add the error
        errorList.addObject(errorMessage);
       
        //return the new aggregated exception
        return new NSValidation.ValidationException("Validity Exception", userInfo);
    }
   
    /**********************************  INSTANCE  **********************************/
   
    //caches
    private NSMutableDictionary _modelCache = null;
    private NSMutableDictionary _classCache = null;
    private NSMutableDictionary _methodCache = null;
   
    //stores the reusable method signature for all gsv rules
    private Class[] _gsvRuleSignature = new Class[4];
   
    //The default model group used of accessing the EOModel associated with the Validity model
    private EOModelGroup _defaultModelGroup = null;
   
    //store whether the beta/trial period has passed
    private boolean _expired = false;
   
    /**
     *  Private constructor called by the singlet accessor.
     */
    private GSVEngine(){
        super();
       
        this.checkExpirationDate();
        this.generateGSVRuleSignature();
       
        _defaultModelGroup = EOModelGroup.defaultGroup();
       
        //initialize caches
        _modelCache = new NSMutableDictionary();
        _classCache = new NSMutableDictionary();
        _methodCache = new NSMutableDictionary();
    }
   
    /**
     *  Called from an object being validated (i.e. validateForSave());
     */
    public boolean validateEOObjectOnSave(EOEnterpriseObject eoObject){
        //NSLog.debug.appendln("*** Validity: GSVEngine.validateEOObjectOnSave(EOEnterpriseObject eoObject)");
        return ( this.validateEOObject(eoObject, ON_SAVE) );
    }
   
    /**
     *  Called from an object being validated (i.e. validateForInsert());
     */
    public boolean validateEOObjectOnInsert(EOEnterpriseObject eoObject){
        //NSLog.debug.appendln("*** Validity: GSVEngine.validateEOObjectOnInsert(EOEnterpriseObject eoObject)");
        return ( this.validateEOObject(eoObject, ON_INSERT) );
    }
   
    /**
     *  Called from an object being validated (i.e. validateForUpdate());
     */
    public boolean validateEOObjectOnUpdate(EOEnterpriseObject eoObject){
        //NSLog.debug.appendln("*** Validity: GSVEngine.validateEOObjectOnUpdate(EOEnterpriseObject eoObject)");
        return ( this.validateEOObject(eoObject, ON_UPDATE) );
    }
   
    /**
     *  Called from an object being validated (i.e. validateForDelete());
     */
    public boolean validateEOObjectOnDelete(EOEnterpriseObject eoObject){
        //NSLog.debug.appendln("*** Validity: GSVEngine.validateEOObjectOnDelete(EOEnterpriseObject eoObject)");
        return ( this.validateEOObject(eoObject, ON_DELETE) );
    }

    public NSDictionary validateKeyAndValueInEntity(String key, String value, String entity) {
        GSVEntity gsvEntity = null;
        GSVAttribute currentAttribute = null;
        GSVRule currentRule = null;
        NSMutableDictionary errorDict = new NSMutableDictionary();
        boolean rulePassed = false;
  gsvEntity = this.entityWithName(entity);
  if( gsvEntity != null ){
      //check each of the object's attributes
      currentAttribute = gsvEntity.attributeNamed(key);
      if (currentAttribute != null) {
    NSArray rules = currentAttribute.rules();
    if (rules != null) {
        for(int r=0; r<currentAttribute.rules().count(); r++){
      currentRule = (GSVRule)currentAttribute.rules().objectAtIndex(r);
      rulePassed = this.checkRule(currentRule, key, errorDict, value, ON_SAVE);
      if(currentRule.stopIfFails() && !rulePassed){
          break;
      }
        }
    }
      }
  }
  //if the error dict contains values, rules failed, so throw an exception
  if(errorDict.allKeys().count()>0) {
      return errorDict;
  } else {
      return null;
  }
    }

    /**
     *  May be called arbitrarily to validate and eo object
     *  Returns <code>true</code> if all validation succeeds.
     *  Throws an NSValidation.ValidationException if one or more of the rules fails.
     */
    public boolean validateEOObject(EOEnterpriseObject eoObject, int when){
        GSVEntity gsvEntity = null;
        GSVAttribute currentAttribute = null;
        GSVRule currentRule = null;
        NSMutableDictionary errorDict = new NSMutableDictionary();
        boolean rulePassed = false;
        if( !_expired ){
            gsvEntity = this.entityForObject(eoObject);
            if( gsvEntity != null ){
                //check each of the object's attributes
                for(int i=0;i<gsvEntity.attributes().count();i++){
                    currentAttribute = (GSVAttribute)gsvEntity.attributes().objectAtIndex(i);
        //check each or the attribute's rules
        for(int r=0;r<currentAttribute.rules().count();r++){
      currentRule = (GSVRule)currentAttribute.rules().objectAtIndex(r);
      rulePassed = this.checkRule(currentRule, currentAttribute.name(), errorDict, eoObject, when);
      if(currentRule.stopIfFails() && !rulePassed){
          break;
      }
        }

    }
      }   
            //if the error dict contains values, rules failed, so throw an exception
            if(errorDict.allKeys().count()>0){
                NSDictionary userInfo = new NSDictionary(errorDict, GSVEngine.ERROR_DICTIONARY_KEY);
                System.out.println("eo="+eoObject);
                throw new NSValidation.ValidationException("Validity Exception", userInfo);
            }
           
        } else {
            //System.out.println("Validity 1.0  has expired.  Please visit http://www.gammastream.com");
            //System.out.println("for the latest release.");
            return false;
        }
        return true;
    }
   
   
    /**
     *  May be called arbitrarily to validate an object
     *  Returns <code>true</code> if all validation succeeds.
     *  Throws an NSValidation.ValidationException if one or more of the rules fails.
     */
    public boolean validateAttribute(Object object, String attributeName, GSVRule rule){
        NSMutableDictionary errorDict = new NSMutableDictionary();
        if( !_expired ){
            if( object != null ){
                this.checkRule(rule, attributeName, errorDict, object, GSVEngine.ON_DEMAND);
            }
           
            //if the error dict contains values, rules failed, so throw an exception
            if(errorDict.allKeys().count()>0){
                NSDictionary userInfo = new NSDictionary(errorDict, GSVEngine.ERROR_DICTIONARY_KEY);
                throw new NSValidation.ValidationException("Validity Exception", userInfo);
            }
           
        } else {
            //System.out.println("Validity 1.0 b1 has expired.  Please visit http://www.gammastream.com");
            //System.out.println("for the latest release.");
            return false;
        }
        return true;
    }

    private boolean checkRule(GSVRule rule, String attributeName, NSMutableDictionary errorDict, String value, Object eoObject, int when) {
        //determine whether this rule applies to the provided 'when'
        if( (when == GSVEngine.ON_SAVE && rule.onSave()) ||
            (when == GSVEngine.ON_INSERT && rule.onInsert()) ||
            (when == GSVEngine.ON_UPDATE && rule.onUpdate()) ||
            (when == GSVEngine.ON_DELETE && rule.onDelete()) ||
            (when == GSVEngine.ON_DEMAND)){

            try{
    Object attributeValue = (eoObject == null) ? value : NSKeyValueCoding.Utility.valueForKey(eoObject,attributeName);
                //if the attributeValue is null, we can stop
                if( attributeValue == null && rule.continueIfNULL()==false){
                    if( rule.failIfNULL() ){
                        NSMutableArray errorArray = (NSMutableArray)errorDict.objectForKey( attributeName );
                        //if this is the first error for this attribute, we need to create an error array
                        if(errorArray == null){
                            errorArray = new NSMutableArray();
                            //place the new error array into the error dictionary
                            errorDict.setObjectForKey(errorArray, attributeName);
                        }
                        //now append the error message to error array
                        if(rule.errorMessage()!=null){
                            errorArray.addObject(rule.errorMessage());
                        }else{
                            errorArray.addObject(attributeName+": Error - No message provided.");
                        }
      return false;
                    }
                    return true//rule passed
                }

                //continue
                String classKey = rule.cName();
                String ruleKey = rule.cName() + "." + rule.mName();
                Class clss = (Class)_classCache.objectForKey(classKey);
                Method method = (Method)_methodCache.objectForKey(ruleKey);
                Class methodReturnType = null;
                boolean rulePassed = false;

                if(method == null){
                    //first lets get the class, if we don't have it already
                    if( clss == null ){
                        clss = Class.forName(classKey);
                        //the class was found, cache it.
                        if( clss != null ){
                            _classCache.setObjectForKey(clss, classKey);
                        }
                    }
                    //now get the method from the class, if the class was found
                    if( clss != null ){
                        method = clss.getMethod(rule.mName(), _gsvRuleSignature);
                        //the method was found, cache it.
                        if(method != null){
                            _methodCache.setObjectForKey(method, ruleKey);
                        }
                    }
                }

                //we have the method, lets continue;

                if( method != null ){

                    methodReturnType = method.getReturnType();
                    //this return type must be a <code>boolean</code>
                    if(methodReturnType.toString().equals("boolean")){
                        Object[] params = {eoObject, attributeValue , attributeName, rule.parameters()};
                        rulePassed = ((Boolean)method.invoke(null, params)).booleanValue();
                        //did the rule fail, if so, populate the error dictionary
                        if( (!rule.negate() && !rulePassed) || (rule.negate() && rulePassed) ){
                            NSMutableArray errorArray = (NSMutableArray)errorDict.objectForKey( attributeName );
                            //if this is the first error for this attribute, we need to create an error array
                            if(errorArray == null){
                                errorArray = new NSMutableArray();
                                //place the new error array into the error dictionary
                                errorDict.setObjectForKey(errorArray, attributeName);
                            }
                            //now append the error message to error array
                            if(rule.errorMessage()!=null){
                                errorArray.addObject(rule.errorMessage());
                            }else{
                                errorArray.addObject(attributeName+": Error - No message provided.");
                            }
                        }
                    }
                }
            }catch(InvocationTargetException e){
                System.out.println(e);
                return false;
            }catch(IllegalAccessException e){
                System.out.println(e);
                return false;
            }catch(ClassNotFoundException e){
                System.out.println(e);
                return false;
            }catch(NoSuchMethodException e){
                System.out.println(e);
                return false;
            }
        }
        return true;
    }

    public boolean checkRule(GSVRule rule, String attributeName, NSMutableDictionary errorDict, String value, int when){
  return checkRule(rule, attributeName, errorDict, value, null, when);
    }
   
    /**
     *  May be called arbitrarily to validate an EO Object, though
     *  it is explicitly called by <code>validateObject</code>
     *  Returns <code>true</code> if all validation succeeds.
     *  Returns <code>false</code> if the rule fails, and populates the error
     *  dictionary with the error.
     */
    public boolean checkRule(GSVRule rule, String attributeName, NSMutableDictionary errorDict, Object eoObject, int when){
  return  checkRule(rule, attributeName, errorDict, null, eoObject, when);
    }

    private GSVEntity entityWithName(String name) {
        EOEntity eoentity = _defaultModelGroup.entityNamed(name);
  return entityForEntity(eoentity);
    }

    private GSVEntity entityForEntity(EOEntity eoentity) {
        //if the eoentity, indeed exists, find out the name of it's model
        if( eoentity != null ){
            String modelName = eoentity.model().name();

            //check the cache to see if this Valididty model has been loaded
            GSVModel model = (GSVModel)_modelCache.objectForKey(modelName);

            //if the model hasn't been cache, load then cache it
            if( model == null ){
                EOModel eomodel = eoentity.model();
                String eoModelPath = NSPathUtilities.stringByDeletingLastPathComponent(eomodel.path());
                eoModelPath = NSPathUtilities.stringByAppendingPathComponent(eoModelPath, eomodel.name());
                eoModelPath = NSPathUtilities.stringByAppendingPathExtension(eoModelPath, "eomodeld");
                String gsvModelPath = NSPathUtilities.stringByAppendingPathComponent(eoModelPath, GSVModel.MODEL_NAME);
                gsvModelPath = NSPathUtilities.stringByAppendingPathExtension(gsvModelPath, GSVModel.MODEL_EXTENSION);
                WOXMLDecoder decoder = WOXMLDecoder.decoder();
                decoder.setEncoding("UTF-8");
                model = (GSVModel)decoder.decodeRootObject(gsvModelPath);
                model.setEomodelPath(eoModelPath)//not sure why we need to do this?
    model.init(eomodel);

                model.saveModel();          //not sure why we need to do this?
               //now cache
                _modelCache.setObjectForKey(model, modelName);
            }
            return model.entityNamed(eoentity.name());
        }
        //the eo entity wasn't found
        return null;
    }
    /**
     *  Loads and returns the GSVEntity associated with the enterprise object.
     */
    private GSVEntity entityForObject(EOEnterpriseObject eoObject){
        EOEntity eoentity = _defaultModelGroup.entityNamed(eoObject.entityName());
        return entityForEntity(eoentity);
    }
    /**
     *  Checks the expiration date for the trial/beta versions of Validity.
     */
    private void checkExpirationDate(){
        /*
        NSTimestamp now = new NSTimestamp();
        if( now.yearOfCommonEra() >= 2002 && now.monthOfYear() >= 2 && now.dayOfMonth() >= 1){
            System.out.println("Validity 1.0 b1 has expired.  Please visit http://www.gammastream.com");
            System.out.println("for the latest release.");
            _expired = true;
        }
        */
        _expired = false;
    }
   
    /**
     *  Simply generates the method signature for a Validity Rule.  A Validity Rule
     *  must use this signature.
     */
    private void generateGSVRuleSignature(){
        try{
            Class[] temp = {
                Class.forName("java.lang.Object"),
                Class.forName("java.lang.Object"),
                Class.forName("java.lang.String"),
                Class.forName("com.webobjects.foundation.NSDictionary")
            };
            _gsvRuleSignature = temp;
        } catch(Exception e){
            System.out.println(e);
        }
    }
   
}
TOP

Related Classes of com.gammastream.validity.GSVEngine

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.