FileDocCategorySizeDatePackage
GenericValidator.javaAPI DocGlassfish v2 API18669Fri May 04 22:24:36 BST 2007com.sun.enterprise.config.serverbeans.validation

GenericValidator.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.enterprise.config.serverbeans.validation;

import java.util.Vector;
import java.net.InetAddress;
import java.net.UnknownHostException;
import com.sun.enterprise.config.ConfigContextEvent;
import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.config.ConfigBean;
import com.sun.enterprise.config.serverbeans.validation.tests.StaticTest;
import com.sun.enterprise.config.serverbeans.ElementProperty;

import com.sun.enterprise.admin.meta.MBeanRegistryFactory;

// Logging
import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;
import com.sun.enterprise.util.LocalStringManagerImpl;



/** 
 *  Class which validates all attributes in the validation descriptor xml file.
 *  All custom tests use this as the  base class

    @author Srinivas Krishnan
    @version 2.0
*/


public class GenericValidator implements DomainCheck {
    
    // Logging
    final static protected Logger _logger = LogDomains.getLogger(LogDomains.APPVERIFY_LOGGER);
    protected LocalStringManagerImpl smh = StringManagerHelper.getLocalStringsManager();
    
    ValidationDescriptor desc;
    
    public GenericValidator(ValidationDescriptor desc) {
        this.desc = desc;
//        try {
            StringManagerHelper.setLocalStringsManager(DomainXmlVerifier.class);
            smh = StringManagerHelper.getLocalStringsManager();
//        }
//        catch (ClassNotFoundException e) {
//           _logger.log(Level.FINE, "domainxmlverifier.class_notfound_exception", e);
//        }
    }
    
    // Initialize all the member variables from the event, invoked by validate. If sub class is not calling 
    // super.validate subclass has to call initialize before starting validation
    public ValidationContext initialize(ConfigContextEvent cce) {
        ValidationContext valCtx = new ValidationContext(new Result(), cce.getObject(), cce.getClassObject(), 
                                        cce.getBeanName(), cce.getConfigContext(), cce.getName(), cce.getChoice(), 
                                        desc.getKey(), smh, desc);
        String key = desc.getKey();
        String element = desc.getElementName();
        if(valCtx.value instanceof ConfigBean) {
            valCtx.result.setAssertion(element);
            try {
                valCtx.result.setTestName(smh.getLocalString(GenericValidator.class.getName() + ".Elementkeyvalue",
                "{0} = {1}", new Object[]{key, ((ConfigBean)valCtx.value).getAttributeValue(key) }));
            } catch(Exception e) {
                _logger.log(Level.FINE, "domainxmlverifier.keynotfound", e);
            }
        }
        valCtx.result.setStatus(0);
        //set operation name
        if(!valCtx.isVALIDATE())
        {
            String elementName = getTargetElementPrintName(valCtx, true, false);
            String strLocalTag;
            String strDefault;
            if(valCtx.isADD() || valCtx.isSET()) {
                strLocalTag = "add_operation_descr";
                strDefault = "Creation config element for {0}";
            } else if(valCtx.isDELETE()) {
                strLocalTag = "delete_operation_descr";
                strDefault = "Deletion of config element for {0}";
            } else {
                strLocalTag = "update_operation_descr";
                strDefault = "Update of config element for {0}";
            }
            valCtx.result.setOperationPrintName(valCtx.smh.getLocalString(
                   strLocalTag, strDefault, new Object[] {elementName}));
        }
        return valCtx;
    }

    private void validateAttribute(AttrType attr, ValidationContext valCtx) 
    {
        if(valCtx.choice == null)
            return;
        String attrName = attr.getName();
        Object value = null;
        ConfigBean ownerBean = null;
        if(valCtx.isADD() || valCtx.isVALIDATE() ||  valCtx.isSET() || valCtx.isDELETE()) 
        {
            ownerBean = (ConfigBean)valCtx.value;
            value = ((ConfigBean)valCtx.value).getAttributeValue(attrName);
            
        }
        else if(valCtx.isUPDATE())
        {
           if(attr.getName().equals(valCtx.name))
           {
                ownerBean = (ConfigBean)valCtx.classObject;
                value = valCtx.value;
//              _logger.log(Level.WARNING, "setting attribute: "+attr.getName()+" to: " +valCtx.value);
           }
        }

       
        if(ownerBean!=null /*&& value!=null*/)
        {
            //-----------set current validation state in valCtx
            valCtx.setAttrName(attrName);
            valCtx.attrValue = value;
            //valCtx.ownerBean = ownerBean;
            // and now - call attributes validation method for element
            validateAttribute(ownerBean, attr, value, valCtx);   
        }
    }
    
    // can be overriden by specific element test class
    public void validateAttribute(ConfigBean ownerBean, AttrType attr, Object value, ValidationContext valCtx) 
    {
        if (/*value!=null &&*/ !StaticTest.valueContainsTokenExpression((String) value))
        {
            //generic validation of attribute
            attr.validate(value, valCtx);
        }
    }

    // can be overriden by specific element test class
    public void validateElement(ValidationContext valCtx) 
    {
     String key = desc.getKey();
     String element = desc.getElementName();
     if(valCtx.isADD() || valCtx.isSET()) 
     {
        ConfigBean thisBean = (ConfigBean)valCtx.value;
        ConfigBean parentBean = (ConfigBean)valCtx.classObject;
        String[] names = desc.requiredChildren;
        for(int i=0; names!=null && i<names.length; i++)
        {
            String childName = names[i];
            if(names[i].endsWith("*"))
                childName = names[i].substring(0, names[i].length()-1);
            childName = XPathHelper.convertName(childName);
            ConfigBean[] beans = thisBean.getChildBeansByName(childName);
            if (beans==null || beans.length==0)
            {
                if(names[i].endsWith("*"))
                {
                    String printParentName = getConfigElementPrintName(
                        getFutureXPath(thisBean, parentBean), false, false);
                    valCtx.result.failed(valCtx.smh.getLocalString(
                        GenericValidator.class.getName() + ".multipleRequiredElemAbsent",
                        "At least one required element {0} should be present in created {1}", 
                        new Object[] {names[i].substring(0, names[i].length()-1),
                                printParentName}));
                }
                else
                {
                    String printParentName = getConfigElementPrintName(
                        getFutureXPath(thisBean, parentBean), false, false);
                    valCtx.result.failed(valCtx.smh.getLocalString(
                        GenericValidator.class.getName() + ".requiredElemAbsent",
                        "Required element {0} should be present in created {1}", 
                        new Object[] {names[i], printParentName}));
                }
            }
        }
        names = desc.exclusiveChildren;
        String alreadyFound = null;
        for(int i=0; names!=null && i<names.length; i++)
        {
            String childName = names[i];
            childName = XPathHelper.convertName(childName);
            ConfigBean[] beans = thisBean.getChildBeansByName(childName);
            if (beans==null || beans.length==0)
                continue;
            if(alreadyFound==null)
            {
                alreadyFound = names[i];
            }
            else
            {
                String printParentName = getConfigElementPrintName(
                    getFutureXPath(thisBean, parentBean), false, false);
                valCtx.result.failed(valCtx.smh.getLocalString(
                        GenericValidator.class.getName() + ".childrenCanExistTogether",
                        "{0} can not contain both sub-elements {1} and {2} in the same time.", 
                        new Object[] {printParentName, alreadyFound, names[i]}));
            }
        }
     }
    }

    // can be overriden by specific element test class
    // this is convenience method for property owner element validator
    // to add reaction on property changes
    // this method is called from <code>validateAsParent</code> method
    // NOTE: ValidationContext is initialized in child's validator
    public void validatePropertyChanges(ValidationContext valCtx) 
    {
       return;        
    }
    
    // can be overriden by specific element test class
    // NOTE: ValidationContext is initialized in child's validator
    public void validateAsParent(ValidationContext valCtx) 
    {
     if(valCtx.isADD() || valCtx.isSET()) 
     {
        ConfigBean newChildBean = (ConfigBean)valCtx.value;
        String newChildBeanName = getBeanElementName(newChildBean);
        ConfigBean parentBean = (ConfigBean)valCtx.classObject;

        String[] names = desc.exclusiveChildren;
        //first, let's be sure that newChildBean in exclusive list
        boolean bNewChildIsInList = false;
        if(names!=null)
        {
            for(int i=0; i<names.length; i++)
            {
               if(newChildBeanName.equals(names[i]))
               {
                   bNewChildIsInList = true;
                   break;
               }
            }
        }
        //now find out if any othjers are there too
        if(bNewChildIsInList)
        {
            for(int i=0; i<names.length; i++)
            {
                String childName = names[i];
                if(childName.equals(newChildBeanName))
                    continue;
                childName = XPathHelper.convertName(childName);
                ConfigBean[] beans = parentBean.getChildBeansByName(childName);
                if (beans!=null && beans.length>0)
                {
                    String printParentName = getConfigElementPrintName(
                        parentBean.getXPath(), false, false);
                    valCtx.result.failed(valCtx.smh.getLocalString(
                            GenericValidator.class.getName() + ".childrenCanExistTogether",
                            "{0} can not contain both sub-elements {1} and {2} in the same time.", 
                            new Object[] {printParentName, 
                                    newChildBeanName, names[i]}));
                }
            }
        }
     }
     else if(valCtx.isDELETE())
     {
        //Check for existence of required sub-elements
        ConfigBean childBean = (ConfigBean)valCtx.value;
        ConfigBean parentBean = (ConfigBean)valCtx.classObject;
        String childBeanName = XPathHelper.convertName(getBeanElementName(childBean));
        ConfigBean[] beans = parentBean.getChildBeansByName(childBeanName);
        if (beans!=null && beans.length==1)
        {  //LAST ELEM DELETION
            ValidationDescriptor parentDescr = desc;
            String[] names = null;
            if(parentDescr!=null)
                names = parentDescr.requiredChildren;
            String compareTo = getBeanElementName(childBean);
            String compareTo2 = compareTo+'*';
            for(int i=0; names!=null && i<names.length; i++)
            {
                if(compareTo.equals(names[i]))
                {
                    String printParentName = getConfigElementPrintName(
                        parentBean.getXPath(), false, false);
                    String printChildName = getConfigElementPrintName(
                        childBean.getXPath(), false, false);
                    valCtx.result.failed(valCtx.smh.getLocalString(
                        GenericValidator.class.getName() + ".requiredElemDelete",
                        "Required element {0} can not be deleted from {1}", 
                        new Object[] {printChildName, printParentName}));
                    break;
                }
                else if(compareTo2.equals(names[i]))
                {
                    String printParentName = getConfigElementPrintName(
                        parentBean.getXPath(), false, false);
                    String printChildName = getConfigElementPrintName(
                        childBean.getXPath(), false, false);
                    valCtx.result.failed(valCtx.smh.getLocalString(
                        GenericValidator.class.getName() + ".lastRequiredElemDelete",
                        "At least one required {0} should be present in {1}."+
                        " Deletion rejected.", 
                        new Object[] {printChildName, printParentName}));
                    break;
                }
            }
        }

     }
     
     if(valCtx.getTargetBean() instanceof ElementProperty)
        validatePropertyChanges(valCtx);
        
    }
    
    // Method for validation (ususally overriden by test classes)
    public Result validate(ConfigContextEvent cce) 
    {
        ValidationContext valCtx = initialize(cce);
        _logger.log(Level.CONFIG, "GenericValidator processing choice: "+valCtx.choice);
        validate(valCtx);
                
        return valCtx.result;
        
    }

    // Method for validation (ususally overriden by test classes)
    public void validate(ValidationContext valCtx) 
    {
        
        //validate element (without attributes) 
        validateElement(valCtx);
        
        //ask parent to confirm change   
        ConfigBean parentBean = valCtx.getParentBean();
        if(parentBean!=null)
        {
           //validate changes by Parent 
           GenericValidator parentValidator = 
                   desc.domainMgr.findConfigBeanValidator((ConfigBean)parentBean);
           if(parentValidator!=null)
           {
               parentValidator.validateAsParent(valCtx);
           }
        }
        
        Vector attrs = desc.getAttributes();
        //Attributes validation    
        for(int i=0; i<attrs.size(); i++) 
        {
            try {
                validateAttribute((AttrType) attrs.get(i), valCtx);
            } catch(IllegalArgumentException e) {
                valCtx.result.failed(e.getMessage());
            } catch(Exception e) {
                _logger.log(Level.WARNING, "domainxmlverifier.errorinvokingmethod", e);
            }
        }
        
    }

   static String getConfigElementPrintName( ValidationContext valCtx, 
            String xpath, boolean bIncludingKey, boolean bReplaceRefByParentElem)
   {
      return valCtx.validationDescriptor.domainMgr.getMBeanRegistry().
               getConfigElementPrintName(xpath, bIncludingKey, bReplaceRefByParentElem);
   }

   String getConfigElementPrintName(
            String xpath, boolean bIncludingKey, boolean bReplaceRefByParentElem)
   {
      return desc.domainMgr.getMBeanRegistry().
               getConfigElementPrintName(xpath, bIncludingKey, bReplaceRefByParentElem);
   }
    static String getTargetElementPrintName( ValidationContext valCtx, 
            boolean bIncludingKey, boolean bReplaceRefByParentElem)
   {
        ConfigBean targetBean = valCtx.getTargetBean();
        if(targetBean==null)
            return null;
        ConfigBean parentBean = valCtx.getParentBean();
        return getConfigElementPrintName( valCtx, 
                getFutureXPath(targetBean, parentBean),
                bIncludingKey, bReplaceRefByParentElem);
   }

    protected static String getFutureXPath(ConfigBean childBean, ConfigBean parentBean) {
        String[] tokens = XPathHelper.extractTokens(childBean.getAbsoluteXPath(""));
        if(parentBean==null) //root
        {
            return "/" + tokens[tokens.length-1];
        }
        return (parentBean.getXPath() + "/" + tokens[tokens.length-1]);
    }
    protected static String getBeanElementName(ConfigBean bean) {
        String[] tokens = XPathHelper.extractTokens(bean.getAbsoluteXPath(""));
        if(tokens.length<1)
            return null;
        String last = tokens[tokens.length-1];
        int idx = last.indexOf('[');
        if(idx>0)
            return last.substring(0, idx);
        else
            return last;
    }    

    /***********************************************************    
     * reports validation error
     ************************************************************/
    static public void reportValidationError(ValidationContext valCtx, 
            String msgNameSuffix, String defaultMsg, Object[] values)
    {
        ReportHelper.reportValidationError(valCtx, 
                        msgNameSuffix, defaultMsg, values);
    }
}