Package org.eclipse.jst.jsf.validation.internal.appconfig

Source Code of org.eclipse.jst.jsf.validation.internal.appconfig.AppConfigValidationUtil$ELResultWrapper

/*******************************************************************************
* Copyright (c) 2007 Oracle Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Cameron Bateman/Oracle - initial API and implementation
*   
********************************************************************************/
package org.eclipse.jst.jsf.validation.internal.appconfig;

import java.io.StringReader;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jst.jsf.common.internal.types.TypeConstants;
import org.eclipse.jst.jsf.common.util.TypeUtil;
import org.eclipse.jst.jsf.core.JSFVersion;
import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
import org.eclipse.jst.jsf.facesconfig.emf.ListEntriesType;
import org.eclipse.jst.jsf.facesconfig.emf.ManagedBeanScopeType;
import org.eclipse.jst.jsf.facesconfig.emf.MapEntriesType;
import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParser;
import org.eclipse.jst.jsp.core.internal.java.jspel.ParseException;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.xml.core.internal.emf2xml.EMF2DOMSSEAdapter;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.w3c.dom.Node;

/**
* Common functions for app config validation
*
* @author cbateman
*
*/
public final class AppConfigValidationUtil
{
    /**
     * Per the fully-qualified-classType in the Faces 1.2 schema and
     * the ClassName entity in the 1.1 DTD
     *
     * @param fullyQualifiedName
     * @param instanceOf
     * @param mustBeAClass
     * @param project
     * @return null if no problems or a Message if problem found
     */
    public static IMessage validateClassName(final String fullyQualifiedName,
                                             final String instanceOf,
                                             final boolean mustBeAClass,
                                             final IProject project)
    {
        try
        {
            IType type = getType(project, fullyQualifiedName);
            if (type == null || !type.exists())
            {
                return DiagnosticFactory
                        .create_CANNOT_FIND_CLASS_NAME(fullyQualifiedName);
            }
           
            // must be a class, not an interface or enum
            if (mustBeAClass && !type.isClass())
            {
                return DiagnosticFactory
                        .create_FULLY_QUALIFIED_NAME_MUST_BE_A_CLASS
                            (fullyQualifiedName);
            }
           
            // must not be abstract since it must instantiable
            if (Flags.isAbstract(type.getFlags()))
            {
                return DiagnosticFactory
                        .create_CLASS_MUST_BE_CONCRETE(fullyQualifiedName);
            }

            if (instanceOf != null)
            {
                if (!isInstanceOf(type, instanceOf))
                {
                    // if we get to here, we haven't found the expected
                    // the super type so error
                    return DiagnosticFactory.create_CLASS_MUST_BE_INSTANCE_OF
                        (fullyQualifiedName, Messages.AppConfigValidationUtil_0, instanceOf);
                }
            }
        }
        catch(JavaModelException jme)
        {
            // fall-through, not found
            JSFCorePlugin.log(jme,
                "Error resolving fully qualified class name: "+fullyQualifiedName); //$NON-NLS-1$
        }

        // either found the class or had an exception so don't report error
        return null;
    }
   
    private static IType getType(final IProject project,
                        final String fullyQualifiedName) throws JavaModelException
    {
        final IJavaProject javaProject = JavaCore.create(project);
        return javaProject.findType(fullyQualifiedName);
    }
   
    /**
     * Per the faces-config-el-expressionType in the Faces 1.2 schema and
     * the Action entity in the 1.1 DTD
     *
     * @param textContent
     * @return an validation diagnostic or null if the textContent
     * represent an expected EL expression
     */
    public static IMessage validateELExpression(final String textContent)
    {
        final ELResultWrapper result = extractELExpression(textContent);
       
        if (result.elText != null)
        {
             JSPELParser parser = new JSPELParser(new StringReader(result.elText));
           
            try {
                parser.Expression();
            } catch (ParseException e) {
                // syntax error
                return DiagnosticFactory.create_SYNTAX_ERROR_IN_EL();
            }
           
            return null;
        }
       
        return result.message;
    }

    /**
     * @param textContent
     * @return the result of trying to extract an EL  expression from the
     * textContent string.  The content is expected to be of the form
     * #{elText}.  elText in the return value will be set to this value
     * from within the braces.  If a syntax error occurs in this extraction
     * message property of the result object will contain a validation message
     * and elText will be set to null.
     * TODO: move this somewhere more generic and shared.
     */
    public static ELResultWrapper extractELExpression(final String textContent)
    {
        final String elRegex = "#\\{(.*)\\}"; //$NON-NLS-1$
        Pattern pattern = Pattern.compile(elRegex);
        Matcher matcher = pattern.matcher(textContent.trim());
        if (matcher.matches())
        {
           final String elText = matcher.group(1).trim();
           
            if ("".equals(elText) || elText == null) //$NON-NLS-1$
            {
                return new ELResultWrapper(DiagnosticFactory.create_SYNTAX_ERROR_IN_EL(), null);
            }
            return new ELResultWrapper(null, elText);
        }
        return new ELResultWrapper(DiagnosticFactory.create_EL_EXPR_MUST_BE_IN_HASH_BRACES(), null);
    }

    /**
     * Value object that wraps the result of trying
     * to extract an EL expression from an arbitrary String
     */
    public static class ELResultWrapper
    {
        private final IMessage    message;
        private final String      elText;
       
        ELResultWrapper(IMessage message, String elText) {
            super();
            this.message = message;
            this.elText = elText;
        }

        /**
         * @return a message indicating a problem encountered
         * trying to extract, or null if no problem was encountered
         */
        public IMessage getMessage() {
            return message;
        }

        /**
         * @return the el expression string raw, stripped of any
         * sorrounding #{} syntax or null if could not be extracted
         */
        public String getElText() {
            return elText;
        }
    }
   
    /**
     * @param eObj
     * @return the offset character offset in to the XML document of the
     * XML node that eObj was constructed from or -1 if not
     * computable
     */
    public static int getStartOffset(EObject eObj)
    {
        IDOMNode node = getDomNode(eObj);
       
        if (node != null)
        {
            return node.getStartStructuredDocumentRegion().getStartOffset();
        }
       
        return -1;
    }

    /**
     * @param eObj
     * @return the length in characters of the XML node that
     * eObj was constructed from or -1 if no computable
     */
    public static int getLength(EObject eObj)
    {
        IDOMNode node = getDomNode(eObj);
       
        if (node != null)
        {
          if(node.getEndStructuredDocumentRegion() != null) {
            return node.getEndStructuredDocumentRegion().getEndOffset()
                      - node.getStartStructuredDocumentRegion().getStartOffset();
          }
           return node.getStartStructuredDocumentRegion().getLength();
        }
       
        return -1;
    }
   
    /**
     * @param eObj
     * @return the DOM node that eObj was constructed from or
     * null if not computable
     */
    public static IDOMNode getDomNode(EObject eObj)
    {
        for (Iterator it = eObj.eAdapters().iterator(); it.hasNext();)
        {
            Adapter adapter = (Adapter) it.next();
           
            if (adapter instanceof EMF2DOMSSEAdapter)
            {
                final EMF2DOMSSEAdapter sseAdapter = (EMF2DOMSSEAdapter) adapter;
                final Node node = sseAdapter.getNode();
                if (node instanceof IDOMNode)
                {
                    return (IDOMNode) node;
                }
            }
        }
       
        return null;
    }
   
    /**
     * @param scope
     * @param file
     * @param version
     * @return an error message if scope does not match a valid
     * scope enum.
     */
    public static IMessage validateManagedBeanScope(ManagedBeanScopeType scope, IFile file, JSFVersion version)
    {     
        // scope must be one of a few enums
        if (!"request".equals(scope.getTextContent()) //$NON-NLS-1$
                && !"session".equals(scope.getTextContent()) //$NON-NLS-1$
                && !"application".equals(scope.getTextContent()) //$NON-NLS-1$
                && !"none".equals(scope.getTextContent())//$NON-NLS-1$
                && ((version == null) || !((version.compareTo(JSFVersion.V2_0) >=0) && "view".equals(scope.getTextContent()) )))  //$NON-NLS-1$
        {
            return DiagnosticFactory.create_BEAN_SCOPE_NOT_VALID();
        }
       
        return null;
    }

    /**
     * @param targetName
     * @param targetType the type of the object that mapEntries will be assigned to
     * @param mapEntries
     * @param project
     * @return null if okay or an error message if the mapEntries type is
     * invalid in some way
     * Note: when Java 1.5 support is added we can validate against the template types
     */
    public static IMessage validateMapEntries(String targetName, String targetType, MapEntriesType mapEntries, IProject project)
    {
        if (mapEntries == null || targetType == null || project == null)
        {
            throw new AssertionError("Arguments to validateMapEntries can't be null"); //$NON-NLS-1$
        }
       
        try
        {
            // TODO: do a bean look-up for targetName to verify that it a) matches the type
            // and b) exists on the bean
            IType type = getType(project, targetType);
           
            if (type != null &&
                    !(isInstanceOf(type, Signature.toString(TypeConstants.TYPE_MAP))))
            {
                return DiagnosticFactory
                    .create_MAP_ENTRIES_CAN_ONLY_BE_SET_ON_MAP_TYPE(targetName);
            }
            // TODO: validate the the map entries
            // TODO: validate the types of the map entries against the values present
            // TODO: validate the map key and value types against the template
        }
        catch (JavaModelException jme)
        {
            JSFCorePlugin.log(new Exception(jme), "Exception while validating mapEntries"); //$NON-NLS-1$
        }
        // if we get to here, we have not found anything meaningful to report
        return null;
    }
   
    /**
     * @param targetName
     * @param targetType the type of the object that mapEntries will be assigned to
     * @param listEntries
     * @param project
     * @return null if okay or an error message if the listEntries type is
     * invalid in some way
     * Note: when Java 1.5 support is added we can validate against the template types
     */
    public static IMessage validateListEntries(String targetName, String targetType, ListEntriesType listEntries, IProject project)
    {
        if (listEntries == null || targetType == null || project == null)
        {
            throw new AssertionError("Arguments to validateMapEntries can't be null"); //$NON-NLS-1$
        }
       
        try
        {
            IType type = getType(project, targetType);
            // TODO: do a bean look-up for targetName to verify that it a) matches the type
            // and b) exists on the bean
            if (type != null &&
                    !(isInstanceOf(type, Signature.toString(TypeConstants.TYPE_LIST))))
            {
                return DiagnosticFactory
                    .create_LIST_ENTRIES_CAN_ONLY_BE_SET_ON_LIST_TYPE(targetName);
            }
            // TODO: validate the the list entries
            // TODO: validate the types of the list entries against the values present
            // TODO: validate the value types against the template
        }
        catch (JavaModelException jme)
        {
            JSFCorePlugin.log(new Exception(jme), "Exception while validating mapEntries"); //$NON-NLS-1$
        }
        // if we get to here, we have not found anything meaningful to report
        return null;
    }
   
    /**
     * @param localeType
     * @return a diagnostic if 'localeType' does not match the
     * expected format or null if all is clear
     */
    public static IMessage validateLocaleType(final String localeType)
    {
        // based on the localeType in the Faces 1.2 schema.  This is safe
        // to apply to 1.1 since it expects the same pattern even though
        // the DTD cannot validate it
        final String localeTypePattern = "[a-z]{2}(_|-)?([\\p{L}\\-\\p{Nd}]{2})?"; //$NON-NLS-1$
        final Matcher matcher = Pattern.compile(localeTypePattern).matcher(localeType);
       
        if (!matcher.matches())
        {
            return DiagnosticFactory.create_LOCALE_FORMAT_NOT_VALID();
        }
       
        return null;
    }
   
    /**
     * @param type
     * @param instanceOf
     * @return true if type instanceof instanceOf is true
     *
     * @throws JavaModelException
     */
    public static boolean isInstanceOf(final IType type, final String instanceOf) throws JavaModelException
    {
        if (instanceOf != null)
        {
            // must have either a no-arg constructor or an adapter constructor
            // that is of the type of instanceOf
//            IType  constructorParam = getType(project, instanceOf);
//            if (constructorParam != null)
//            {
//                final String constructorMethodName =
//                    type.getElementName();
//                final IMethod defaultConstructor =
//                    type.getMethod(constructorMethodName, new String[0]);
//                final IMethod adapterConstructor =
//                    type.getMethod(constructorMethodName, new String[]{instanceOf});
//                final boolean isDefaultConstructor =
//                    defaultConstructor != null && defaultConstructor.isConstructor();
//                final boolean isAdapterConstructor =
//                    adapterConstructor != null && adapterConstructor.isConstructor();
//                if (!isDefaultConstructor && !isAdapterConstructor)
//                {
                    // TODO: no constructor == default constructor...
//                }
//            }

            // if the type is an exact match
            if (instanceOf.equals(type.getFullyQualifiedName()))
            {
                return true;
            }

            final ITypeHierarchy typeHierarchy =
                type.newSupertypeHierarchy(new NullProgressMonitor());
           
            final IType[] supers = typeHierarchy.getAllSupertypes(type);
            for (int i = 0; i < supers.length; i++)
            {
                if (instanceOf.equals(supers[i].getFullyQualifiedName()))
                {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Takes the form expected by faces-config files for fully qualified class names
     * @param inputStr java.lang.String format.
     * @return the fully qualified type signature for the inputStr
     */
    public static String getBaseType(final String inputStr)
    {
        String checkValue = inputStr.trim();
        try
        {
            // arrays are a special case where the
            // [Ljava.lang.String; syntax is valid.
            if (Signature.getArrayCount(checkValue)>0)
            {
                checkValue = Signature.getElementType(checkValue);
                checkValue = TypeUtil.getFullyQualifiedName(checkValue);
            }
        }
        catch (final IllegalArgumentException e)
        {
            // ignore
        }

        return checkValue;
    }

    private AppConfigValidationUtil()
    {
        // no external construction
    }
}
TOP

Related Classes of org.eclipse.jst.jsf.validation.internal.appconfig.AppConfigValidationUtil$ELResultWrapper

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.