All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.el.unified.resolver.ImportConstantsELResolver Maven / Gradle / Ivy

Go to download

The private implementation classes of the Apache MyFaces Core JSF-2.3 Implementation

There is a newer version: 4.1.0-RC2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.myfaces.el.unified.resolver;

import java.beans.FeatureDescriptor;
import static java.lang.String.format;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.logging.Level.FINE;
import java.util.logging.Logger;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.PropertyNotFoundException;
import javax.el.PropertyNotWritableException;
import javax.faces.component.UIImportConstants;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewMetadata;
import org.apache.myfaces.shared.util.ClassUtils;
import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;

/**
 *
 */
public final class ImportConstantsELResolver extends ELResolver
{
    private static final String ERROR_MISSING_CLASS = "Cannot find type '%s' in classpath.";
    private static final String ERROR_FIELD_ACCESS = "Cannot access constant field '%s' of type '%s'.";

    private static final String IMPORT_CONSTANTS = "oam.importConstants";
    
    private Map > constantsTypeMap = new ConcurrentHashMap >();

    @Override
    public Object getValue(final ELContext context, final Object base,
            final Object property)
            throws NullPointerException, PropertyNotFoundException, ELException
    {
        if (base != null)
        {
            return null;
        }
        if (property == null)
        {
            throw new PropertyNotFoundException();
        }
        if (!(property instanceof String))
        {
            return null;
        }

        final FacesContext facesContext = facesContext(context);
        if (facesContext == null)
        {
            return null;
        }

        UIViewRoot viewRoot = facesContext.getViewRoot();
        if (viewRoot == null)
        {
            return null;
        }

        Map importConstantsMap = (Map) 
                viewRoot.getTransientStateHelper().getTransient(IMPORT_CONSTANTS);
        if (importConstantsMap == null)
        {
            Collection constants = ViewMetadata.getImportConstants(viewRoot);
            if (constants != null && !constants.isEmpty())
            {
                importConstantsMap = new HashMap();
                for (UIImportConstants c : constants)
                {
                    String var = c.getVar();
                    String type = c.getType();
                    if (var == null) 
                    {
                        int innerClass = type.lastIndexOf('$');
                        int outerClass = type.lastIndexOf('.');
                        var = type.substring(Math.max(innerClass, outerClass) + 1);
                    }                    
                    importConstantsMap.put(var, type);
                }
            } 
            else
            {
                importConstantsMap = Collections.emptyMap();
            }
            if (!FaceletViewDeclarationLanguage.isBuildingViewMetadata(facesContext))
            {
                viewRoot.getTransientStateHelper().putTransient(IMPORT_CONSTANTS, importConstantsMap);
            }
        }

        if (importConstantsMap != null && !importConstantsMap.isEmpty())
        {
            String type = importConstantsMap.get((String)property);
            if (type != null)
            {
                Map constantsMap = constantsTypeMap.get(type);
                if (constantsMap == null)
                {
                    constantsMap = collectConstants(type);
                    constantsTypeMap.put(type, constantsMap);
                }
                if (constantsMap != null && !constantsMap.isEmpty())
                {
                    context.setPropertyResolved(true);
                    return constantsMap;
                }
            }
        }
        return null;
    }

    @Override
    public Class getType(final ELContext context, final Object base,
            final Object property)
            throws NullPointerException, PropertyNotFoundException, ELException
    {
        return null;
    }

    @Override
    public void setValue(ELContext elc, Object o, Object o1, Object o2)
            throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException, ELException
    {
        //No op
    }

    @Override
    public boolean isReadOnly(final ELContext context, final Object base,
            final Object property)
            throws NullPointerException, PropertyNotFoundException, ELException
    {
        return false;
    }

    @Override
    public Iterator getFeatureDescriptors(final ELContext context, final Object base)
    {
        return null;
    }

    @Override
    public Class getCommonPropertyType(final ELContext context, final Object base)
    {
        return base == null ? Object.class : null;
    }

    // get the FacesContext from the ELContext
    private static FacesContext facesContext(final ELContext context)
    {
        return (FacesContext) context.getContext(FacesContext.class);
    }

    // Helpers --------------------------------------------------------------------------------------------------------
    /**
     * Collect constants of the given type. That are, all public static final fields of the given type.
     *
     * @param type The fully qualified name of the type to collect constants for.
     * @return Constants of the given type.
     */
    private static Map collectConstants(final String type)
    {
        Map constants = new HashMap();

        for (Field field : toClass(type).getFields())
        {
            if (isPublicStaticFinal(field))
            {
                try
                {
                    constants.put(field.getName(), field.get(null));
                }
                catch (Exception e)
                {
                    throw new IllegalArgumentException(format(ERROR_FIELD_ACCESS, type, field.getName()), e);
                }
            }
        }

        return constants;
    }

    /**
     * Convert the given type, which should represent a fully qualified name, to a concrete {@link Class} instance.
     *
     * @param type The fully qualified name of the class.
     * @return The concrete {@link Class} instance.
     * @throws IllegalArgumentException When it is missing in the classpath.
     */
    static Class toClass(String type)
    {
        // Package-private so that ImportFunctions can also use it.
        try
        {
            return ClassUtils.classForName(type);
        } 
        catch (ClassNotFoundException e)
        {
            // Perhaps it's an inner enum which is specified as com.example.SomeClass.SomeEnum.
            // Let's be lenient on that although the proper type notation should be com.example.SomeClass$SomeEnum.
            int i = type.lastIndexOf('.');

            if (i > 0)
            {
                try
                {
                    return toClass(new StringBuilder(type).replace(i, i + 1, "$").toString());
                } 
                catch (Exception ignore)
                {
                    Logger.getLogger(ImportConstantsELResolver.class.getName()).log(
                            FINE, "Ignoring thrown exception; previous exception will be rethrown instead.", ignore);
                    // Just continue to IllegalArgumentException on original ClassNotFoundException.
                }
            }

            throw new IllegalArgumentException(format(ERROR_MISSING_CLASS, type), e);
        }
    }

    /**
     * Returns whether the given field is a constant field, that is when it is public, static and final.
     *
     * @param field The field to be checked.
     * @return true if the given field is a constant field, otherwise false.
     */
    private static boolean isPublicStaticFinal(Field field)
    {
        int modifiers = field.getModifiers();
        return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy