Package org.eclipse.jst.jsf.designtime.el

Source Code of org.eclipse.jst.jsf.designtime.el.DefaultDTPropertyResolver

/*******************************************************************************
* Copyright (c) 2006 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.designtime.el;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jst.jsf.common.internal.types.StringLiteralType;
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.ERuntimeSource;
import org.eclipse.jst.jsf.context.symbol.IBoundedTypeDescriptor;
import org.eclipse.jst.jsf.context.symbol.IObjectSymbol;
import org.eclipse.jst.jsf.context.symbol.ISymbol;
import org.eclipse.jst.jsf.context.symbol.ITypeDescriptor;
import org.eclipse.jst.jsf.designtime.symbols.JSFSymbolFactory;

/**
* A design time proxy for the runtime PropertyResolver.  This is used to
* resolve all but the first element of a var.prop.prop2 type of sub-expression in
* a JSF EL expression. @see DefaultDTVariableResolver for how to resolve 'var' at
* designtime
*
* Clients may implement
*
* @author cbateman
*/
public class DefaultDTPropertyResolver extends AbstractDTPropertyResolver
{
  private static final String UICOMPONENT_SYMBOL_SIGNATURE   = "Ljavax.faces.component.UIComponent;"; //$NON-NLS-1$
  private static final String ATTRS_SYMBOL_NAME         = "attrs"; //$NON-NLS-1$
  private JSFSymbolFactory   _symbolFactory           = new JSFSymbolFactory();
  
    /**
     * Returns a symbol encapsulating the property on base with the name
     * properyId
     *
     * @param base
     * @param propertyId
     * @return the symbol for the named propertyId or null if not found
     */
    public ISymbol getProperty(ISymbol base, Object propertyId)
    {
        ITypeDescriptor typeDesc = null;

        Object[] factoredProperties = new Object[] {propertyId};

        // check for expected interface types per JSP.2.3.4
        if (base instanceof IObjectSymbol)
        {
            final IObjectSymbol objSymbol = (IObjectSymbol) base;
            typeDesc = objSymbol.getTypeDescriptor();

            // although not stated explicitly stated by the spec, in practice (based on Sun RI),
            // a list cannot have non-numeric indexed properties
            // note: due to remove(Object) having different return types
            // an object can't be both a List and a Map!  So we can consider
            // a List instanceof out of order
            if (objSymbol.supportsCoercion(TypeConstants.TYPE_LIST))
            {
                typeDesc = null;
            }
            // per JSP.2.3.4, if instance of map (unconstrained in our terminology)
            else if (objSymbol.supportsCoercion(TypeConstants.TYPE_MAP))
            {
                EList<ValueType>  args = new BasicEList<ValueType>();
                args.add(new StringLiteralType(propertyId.toString()));
               
                ISymbol prop = objSymbol.call("get", args, propertyId.toString()); //$NON-NLS-1$
               
                if (prop != null)
                {
                    return prop;
                }
               
                typeDesc = objSymbol.coerce(TypeConstants.TYPE_MAP);

                // handle string keys into maps that contain dots.  Because type descriptor
                // handle dotted property ids (i.e. 'x.y.z') as separate properties with
                // intermediate parts, we need to handle this specially.
                if (propertyId instanceof String && ((String)propertyId).indexOf('.')>-1)
                {
                    factoredProperties = factorKey(propertyId);
                }
            }
            //if symbol is "attrs", add it if applicable
            else if (propertyId instanceof String
                && ((String)propertyId).equals(ATTRS_SYMBOL_NAME)) {
              return getCCAttrsSymbolIfNecessary(typeDesc);
            }

            // check unconstrained type
            if (typeDesc instanceof IBoundedTypeDescriptor)
            {
                // TODO: propertyId may need to change when supporting
                // template types
                if (((IBoundedTypeDescriptor)typeDesc).isUnboundedForType(TypeConstants.TYPE_JAVAOBJECT))
                {
                    // the most we know is that it could be an Object
                    return ((IBoundedTypeDescriptor)typeDesc).getUnboundedProperty(propertyId, TypeConstants.TYPE_JAVAOBJECT);
                }
            }
           
        }

        int i = 0;
        ISymbol  matchedSymbol;

        do
        {
            matchedSymbol = null; // always reset so if the for completes without setting, the
                                  // while ends
            SEARCH_SEGMENT: for (final Iterator it = getIterator(typeDesc); it.hasNext();)
            {
                final ISymbol element = (ISymbol) it.next();

                if (element.getName().equals(factoredProperties[i])
                        && element instanceof IObjectSymbol)
                {
                    matchedSymbol = element;
                    typeDesc = ((IObjectSymbol)matchedSymbol).getTypeDescriptor();
                    break SEARCH_SEGMENT;
                }
            }
        } while(++i < factoredProperties.length && matchedSymbol != null);

        // may be null if none matched
        return matchedSymbol;
    }
   
    /**
     * @param base
     * @return all properties of base
     */
    public ISymbol[] getAllProperties(ISymbol base)
    {
        // if nothing found, return an empty array
        List  symbolsList =  Collections.EMPTY_LIST;
       
        if (base instanceof IObjectSymbol)
        {
            ITypeDescriptor typeDesc = null;
           
            // per JSP.2.3.4, if instance of map (unconstrained in our terminology)
            if (((IObjectSymbol)base).supportsCoercion(TypeConstants.TYPE_MAP))
            {
                typeDesc =
                    ((IObjectSymbol)base).coerce(TypeConstants.TYPE_MAP);
            }
            // Lists have no properties, even if they are also beans
            else if (((IObjectSymbol)base).supportsCoercion(TypeConstants.TYPE_LIST))
            {
                typeDesc = null;
            }
            else
            {
                typeDesc = ((IObjectSymbol)base).getTypeDescriptor();
           
            }
           
            if (typeDesc != null)
            {
                symbolsList =  typeDesc.getProperties();
                addCCAttrsIfNecessary(typeDesc, symbolsList);
            }
        }

        return (ISymbol[]) symbolsList.toArray(ISymbol.EMPTY_SYMBOL_ARRAY);
    }

    private ISymbol getCCAttrsSymbolIfNecessary(final ITypeDescriptor typeDesc) {
      ISymbol attrsSymbol = null;
      if (typeDesc.instanceOf(UICOMPONENT_SYMBOL_SIGNATURE)) {
        attrsSymbol = _symbolFactory.createUnknownInstanceSymbol(ATTRS_SYMBOL_NAME, ERuntimeSource.BUILT_IN_SYMBOL_LITERAL);       
      }
      return attrsSymbol;
    }
   
    private void addCCAttrsIfNecessary(final ITypeDescriptor typeDesc, final List symbolsList) {
      final ISymbol attrsSymbol = getCCAttrsSymbolIfNecessary(typeDesc);
      if (attrsSymbol != null) {       
        symbolsList.add(attrsSymbol);
      }
  }

  /* (non-Javadoc)
     * @see org.eclipse.jst.jsf.designtime.el.AbstractDTPropertyResolver#getProperty(org.eclipse.jst.jsf.context.symbol.ISymbol, int)
     */
    public ISymbol getProperty(ISymbol base, int offset)
    {
        ITypeDescriptor typeDesc = null;

        if (offset < 0)
        {
          // should never be called with offset < 0
          throw new AssertionError("offsets must be >=0 to be valid"); //$NON-NLS-1$
        }
       
        // check for expected interface types per JSP.2.3.4
        if (base instanceof IObjectSymbol)
        {

          final IObjectSymbol objSymbol = (IObjectSymbol) base;
            typeDesc = objSymbol.getTypeDescriptor();

            // per JSP.2.3.4, if instance of array (unconstrained in our terminology)
            if (typeDesc.isArray())
            {
                ISymbol arrayElement = typeDesc.getArrayElement();
                // reset the name
                arrayElement.setName(base.getName()+"["+offset+"]"); //$NON-NLS-1$ //$NON-NLS-2$
                return arrayElement;
            }
           
            // per JSP.2.3.4, if instance of list (unbounded in our terminology)
            if (objSymbol.supportsCoercion(TypeConstants.TYPE_LIST))
            {
                //typeDesc = objSymbol.coerce(TypeConstants.TYPE_LIST);
                final EList<ValueType> args = new BasicEList<ValueType>();
                args.add(new ValueType(Signature.SIG_INT, ValueType.ASSIGNMENT_TYPE_RHS));
                return objSymbol.call("get", args, base.getName()+"["+offset+"]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            }

            return getCCAttrsSymbolIfNecessary(typeDesc);
            // check unconstrained type
//            if (typeDesc instanceof IBoundedTypeDescriptor)
//            {
//                // TODO: propertyId may need to change when supporting
//                // template types
//                if (((IBoundedTypeDescriptor)typeDesc).isUnboundedForType(TypeConstants.TYPE_BOXED_INTEGER))
//                {
                    // the most we know is that it could be an Object
//                    return ((IBoundedTypeDescriptor)typeDesc)
//                        .getUnboundedProperty
//                            (new Integer(offset), TypeConstants.TYPE_BOXED_INTEGER);
//                    final EList<Object> args = new BasicEList<Object>();
//                    args.add(offset);
//                    return ((IBoundedTypeDescriptor)typeDesc)
//                          .call("get", args, base.getName()+"["+offset+"]");
//                }
//            }
        }
       
        return null;
    }
   
    /**
     * @param typeDesc
     * @return the type descriptor's property iterator or empty list
     * if null
     */
    protected final Iterator getIterator(ITypeDescriptor typeDesc)
    {
        if (typeDesc != null)
        {
            return typeDesc.getProperties().iterator();
        }
        return Collections.EMPTY_LIST.iterator();
    }
   
    /**
     * Takes a key expression and factors it down to into all property segments it contains.
     * Property segments occur mainly when String keys contain '.' characters, indicating that
     * more one than property actually must be traversed to evaluate the whole expr.
     * @param key
     * @return an array containing all property segments of the key.  If the key contains only
     * one property, then this is returned a single element in the array
     */
    protected final Object[] factorKey(Object key)
    {
        if (key instanceof String)
        {
            List  segments = new ArrayList();
           
            String stringKey = (String) key;
            int nextPos = -1;
           
            while ((nextPos = stringKey.indexOf('.')) > -1)
            {
                segments.add(stringKey.substring(0, nextPos));
                stringKey = stringKey.substring(nextPos+1);
            }
           
            if (stringKey != null && stringKey.length() > 0)
            {
                segments.add(stringKey);
            }
           
            return segments.toArray();
        }

        return new Object[] {key};
    }
}
TOP

Related Classes of org.eclipse.jst.jsf.designtime.el.DefaultDTPropertyResolver

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.