Package org.eclipse.jst.jsf.validation.internal.el.operators

Source Code of org.eclipse.jst.jsf.validation.internal.el.operators.MemberAccessorOperator

/*******************************************************************************
* Copyright (c) 2001, 2008 Oracle Corporation and others.
* 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:
*     Oracle Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.jsf.validation.internal.el.operators;

import org.eclipse.core.resources.IFile;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.jst.jsf.common.internal.types.LiteralType;
import org.eclipse.jst.jsf.common.internal.types.NullLiteralType;
import org.eclipse.jst.jsf.common.internal.types.SignatureBasedType;
import org.eclipse.jst.jsf.common.internal.types.TypeCoercer;
import org.eclipse.jst.jsf.common.internal.types.TypeConstants;
import org.eclipse.jst.jsf.common.internal.types.ValueType;
import org.eclipse.jst.jsf.context.symbol.IMethodSymbol;
import org.eclipse.jst.jsf.context.symbol.IObjectSymbol;
import org.eclipse.jst.jsf.context.symbol.IPropertySymbol;
import org.eclipse.jst.jsf.context.symbol.ISymbol;
import org.eclipse.jst.jsf.context.symbol.internal.util.IMethodSymbolBasedType;
import org.eclipse.jst.jsf.context.symbol.internal.util.IObjectSymbolBasedValueType;
import org.eclipse.jst.jsf.designtime.resolver.ISymbolContextResolver;
import org.eclipse.jst.jsf.validation.internal.el.diagnostics.DiagnosticFactory;

/**
* Super-class for all operators whose function is to access members of an EL
* object. i.e. the "." and "[]" operators
*
* @author cbateman
*
*/
public abstract class MemberAccessorOperator
{
    /**
     * The source file for the EL expression in which this operator is being
     * evaluated.
     */
    protected final IFile             _file;

    /**
     * the common factory used to create diagnostics
     */
    protected final DiagnosticFactory _diagnosticFactory;

    /**
     * Used to resolve variables and properties.
     */
    protected final ISymbolContextResolver  _contextResolver;

    // TODO: need to reconcile with BinaryOperator? performOperation must return
    // SignatureBasedType since it may return a method. This can't happen
    // with other operators (besides eqiv [])
    /**
     * @param file
     * @param diagnosticFactory
     * @param contextResolver
     */
    protected MemberAccessorOperator(final IFile file,
            final DiagnosticFactory diagnosticFactory, final ISymbolContextResolver contextResolver)
    {
        _file = file;
        _diagnosticFactory = diagnosticFactory;
        _contextResolver = contextResolver;
    }

    /**
     * @param firstArg
     * @param secondArg
     * @return the result of validating the dot operation with these arguments.
     */
    public Diagnostic validate(final ValueType firstArg, final ValueType secondArg)
    {
      if (TypeConstants.TYPE_JAVAOBJECT.equals(firstArg.getSignature())) {
        return Diagnostic.OK_INSTANCE;
      }
        if (!(firstArg instanceof IObjectSymbolBasedValueType))
        {
            throw new AssertionError(
            "The first argument of the member operator must always be a symbol resolvable value type"); //$NON-NLS-1$
        }

        if (TypeCoercer.typeIsNull(secondArg.getSignature()))
        {
            return _diagnosticFactory
            .create_BINARY_OP_DOT_WITH_VALUEB_NULL(getOperatorName());
        }

        return validateObjectSymbolValue(
                (IObjectSymbolBasedValueType) firstArg, secondArg);
    }

    /**
     * @param firstArg
     * @param secondArg
     * @return the diagnostic for member(firstArg, secondArg)
     */
    protected abstract Diagnostic validateObjectSymbolValue(
            IObjectSymbolBasedValueType firstArg, ValueType secondArg);

    /**
     * @param firstArg
     * @param secondArg
     * @return a validation of a named property accessible base (map or bean)
     *         given an a literal key argument
     */
    protected Diagnostic validateNamedPropertyAccessorBase(
            final IObjectSymbolBasedValueType firstArg, final LiteralType secondArg)
    {
        final IObjectSymbol curBaseSymbol = firstArg.getSymbol();

        final ISymbol nextSymbol =
            getMemberSymbol(firstArg.getSymbol(), secondArg
                    .getLiteralValueRaw());

        // if the x in x.y is an unconstrained map an it returns
        // a java.lang.Object, then return null. We can't really say
        // anything meaningful about such a property anyway.
        // TODO: do we need to refine the type descriptor on such
        // a property object to make this more precise?
        if (curBaseSymbol.supportsCoercion(TypeConstants.TYPE_MAP)
                && nextSymbol instanceof IPropertySymbol
                && TypeConstants.TYPE_JAVAOBJECT
                .equals(((IPropertySymbol) nextSymbol)
                        .getTypeDescriptor().getTypeSignature()))
        {
            // if we get a symbol back that's a generic object coming from a map
            // then stop validating; we can't tell anything for sure
            return Diagnostic.OK_INSTANCE;
        }

        if (nextSymbol == null)
        {
            return _diagnosticFactory.create_MEMBER_NOT_FOUND(secondArg
                    .getLiteralValue(), firstArg.getSymbol().getName());
        }

        return Diagnostic.OK_INSTANCE;
    }

    /**
     * @param firstArg
     * @param secondArg
     * @return the resolved type for the operation or null if not computable
     */
    public SignatureBasedType performOperation(final ValueType firstArg,
            final ValueType secondArg)
    {
        if (!(firstArg instanceof IObjectSymbolBasedValueType))
        {
            return null;
        }

        // per JSP.2.3.4, if value-b is null, then return null (not literal
        // null)
        if (TypeCoercer.typeIsNull(secondArg.getSignature()))
        {
            return null;
        }

        return handlePerformObjectSymbolValue(
                (IObjectSymbolBasedValueType) firstArg, secondArg);
    }

    /**
     * @param firstArg --
     *            represents value-a (expr-a after step 1) in JSP.2.3.4
     * @param secondArg --
     *            represents value-b (expr-b after step 3) in JSP.2.3.4
     * @return the new ValueType for this operation or null
     */
    protected abstract SignatureBasedType handlePerformObjectSymbolValue(
            IObjectSymbolBasedValueType firstArg, ValueType secondArg);

    /**
     * @param firstArg
     * @param secondArg
     * @return the resolved type for firstArg[secondArg] treating firstArg as a
     *         type that uses a named property accessor (i.e. a map or bean but
     *         not a list or array) or null if unresolved
     */
    protected SignatureBasedType handlePerformNamedPropertyAccessorBase(
            final IObjectSymbolBasedValueType firstArg, final LiteralType secondArg)
    {
        final ISymbol symbol =
            getMemberSymbol(firstArg.getSymbol(), secondArg
                    .getLiteralValueRaw());

        if (symbol instanceof IPropertySymbol)
        {
            return new IObjectSymbolBasedValueType((IPropertySymbol) symbol);
        }
        else if (symbol instanceof IMethodSymbol)
        {
            return new IMethodSymbolBasedType((IMethodSymbol) symbol);
        }

        // fall-through and return null
        // per JSP2.3.4 steps 5 and 6, return null literal if map, null (error)
        // otherwise
        if (firstArg.isInstanceOf(TypeConstants.TYPE_MAP))
        {
            return NullLiteralType.SINGLETON;
        }
        return null;
    }

    /**
     * @param symbol
     * @param name
     * @return the member symbol of 'symbol' corresponding to 'name' or null if
     *         there is no such member
     */
    protected final ISymbol getMemberSymbol(final IObjectSymbol symbol,
            final Object name)
    {
        ISymbol memberSymbol = getPropertySymbol(symbol, name);

        if (memberSymbol != null)
        {
            return memberSymbol;
        }

        memberSymbol = getMethodSymbol(symbol, name);

        // otherwise, see if it's a valid method
        if (memberSymbol != null)
        {
            return memberSymbol;
        }

        // if not a property or method, then not a valid member
        return null;
    }

    /**
     * @param symbol
     * @param name
     * @return the property symbol called name relative to 'symbol' or null if
     *         one doesn't exist
     */
    protected final ISymbol getPropertySymbol(final ISymbol symbol,
            final Object name)
    {
        return _contextResolver.getProperty(symbol, name);
    }

    /**
     * @param symbol
     * @param name
     * @return the method symbol on 'symbol' corresponding to 'name' or null if
     *         no such member
     */
    protected final IMethodSymbol getMethodSymbol(final IObjectSymbol symbol,
            final Object name)
    {
        return _contextResolver.getMethod(symbol, name);
    }


    /**
     * @return a user-readable name of the operator (i.e. dot or bracket)
     */
    protected abstract String getOperatorName();
}
TOP

Related Classes of org.eclipse.jst.jsf.validation.internal.el.operators.MemberAccessorOperator

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.