You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2017/03/10 00:20:34 UTC

svn commit: r1786263 - in /myfaces/core/branches/2.3.x: api/src/main/java/javax/faces/component/ api/src/main/java/javax/faces/view/ impl/src/main/java/org/apache/myfaces/el/unified/ impl/src/main/java/org/apache/myfaces/el/unified/resolver/ impl/src/m...

Author: lu4242
Date: Fri Mar 10 00:20:34 2017
New Revision: 1786263

URL: http://svn.apache.org/viewvc?rev=1786263&view=rev
Log:
MYFACES-4101 Implement f:importConstants

Added:
    myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/component/UIImportConstants.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/resolver/ImportConstantsELResolver.java
Modified:
    myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/view/ViewMetadata.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/ResolverBuilderForFaces.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java

Added: myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/component/UIImportConstants.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/component/UIImportConstants.java?rev=1786263&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/component/UIImportConstants.java (added)
+++ myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/component/UIImportConstants.java Fri Mar 10 00:20:34 2017
@@ -0,0 +1,75 @@
+/*
+ * 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 javax.faces.component;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
+
+/**
+ *
+ */
+@JSFComponent
+(clazz = "javax.faces.component.UIImportConstants",
+ name = "f:importConstants", bodyContent = "empty")
+public class UIImportConstants extends UIComponentBase
+{
+    
+    static public final String COMPONENT_FAMILY = "javax.faces.ImportConstants";
+    static public final String COMPONENT_TYPE = "javax.faces.ImportConstants";
+
+
+    public UIImportConstants()
+    {
+        setRendererType(null);
+    }
+
+    @Override    
+    public String getFamily()
+    {
+        return COMPONENT_FAMILY;
+    }
+    
+    @JSFProperty
+    public String getType()
+    {
+        return (String) getStateHelper().eval(PropertyKeys.type);
+    }
+    
+    public void setType(String type)
+    {
+        getStateHelper().put(PropertyKeys.type, type ); 
+    }
+
+    @JSFProperty
+    public String getVar()
+    {
+        return (String) getStateHelper().eval(PropertyKeys.var);
+    }
+    
+    public void setVar(String var)
+    {
+        getStateHelper().put(PropertyKeys.var, var ); 
+    }
+
+    enum PropertyKeys
+    {
+         type
+        , var
+    }
+}

Modified: myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/view/ViewMetadata.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/view/ViewMetadata.java?rev=1786263&r1=1786262&r2=1786263&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/view/ViewMetadata.java (original)
+++ myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/view/ViewMetadata.java Fri Mar 10 00:20:34 2017
@@ -24,6 +24,7 @@ import java.util.Iterator;
 import java.util.LinkedList;
 
 import javax.faces.component.UIComponent;
+import javax.faces.component.UIImportConstants;
 import javax.faces.component.UIViewAction;
 import javax.faces.component.UIViewParameter;
 import javax.faces.component.UIViewRoot;
@@ -147,4 +148,57 @@ public abstract class ViewMetadata
         UIComponent metadataFacet = root.getFacet(UIViewRoot.METADATA_FACET_NAME);
         return metadataFacet != null ? metadataFacet.getChildCount() > 0 : false;
     }
+    
+    /**
+     * @since 2.3
+     * @param root
+     * @return 
+     */
+    public static Collection<UIImportConstants> getImportConstants(UIViewRoot root)
+    {
+        LinkedList<UIImportConstants> result = null;
+        UIComponent metadataFacet = root.getFacet (UIViewRoot.METADATA_FACET_NAME);
+        Iterator<UIComponent> children;
+        
+        if (metadataFacet == null)
+        {
+             // No metadata, so return an empty collection.
+             
+             return Collections.emptyList();
+        }
+        
+        // Iterate over all the children, keep only the view parameters.
+        
+        if (metadataFacet.getChildCount() > 0)
+        {
+            children = metadataFacet.getChildren().iterator();
+            
+            while (children.hasNext())
+            {
+                 UIComponent component = children.next();
+                 
+                 if (result == null)
+                 {
+                     result = new LinkedList<UIImportConstants>();
+                 }
+                 
+                 if (component instanceof UIImportConstants)
+                 {
+                      result.add ((UIImportConstants) component);
+                 }
+            }
+        }
+        
+        // TODO: does this need to be immutable?  Spec does not indicate either
+        // way.
+        if (result == null)
+        {
+            return Collections.emptyList();
+        }
+        else
+        {
+            return Collections.unmodifiableCollection (result);
+        }
+    }
+
 }

Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/ResolverBuilderForFaces.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/ResolverBuilderForFaces.java?rev=1786263&r1=1786262&r2=1786263&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/ResolverBuilderForFaces.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/ResolverBuilderForFaces.java Fri Mar 10 00:20:34 2017
@@ -37,6 +37,7 @@ import org.apache.myfaces.config.Runtime
 import org.apache.myfaces.el.FlashELResolver;
 import org.apache.myfaces.el.unified.resolver.CompositeComponentELResolver;
 import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.Scope;
+import org.apache.myfaces.el.unified.resolver.ImportConstantsELResolver;
 import org.apache.myfaces.el.unified.resolver.ImportHandlerResolver;
 import org.apache.myfaces.el.unified.resolver.ManagedBeanResolver;
 import org.apache.myfaces.el.unified.resolver.ResourceBundleResolver;
@@ -104,6 +105,7 @@ public class ResolverBuilderForFaces ext
         list.add(new ResourceResolver());
         list.add(new ResourceBundleELResolver());
         list.add(new ResourceBundleResolver());
+        list.add(new ImportConstantsELResolver());
         
         if (STATIC_FIELD_EL_RESOLVER_CLASS != null &&
             GET_STREAM_EL_RESOLVER_METHOD != null)

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/resolver/ImportConstantsELResolver.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/resolver/ImportConstantsELResolver.java?rev=1786263&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/resolver/ImportConstantsELResolver.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/el/unified/resolver/ImportConstantsELResolver.java Fri Mar 10 00:20:34 2017
@@ -0,0 +1,251 @@
+/*
+ * 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 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";
+
+    @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<String, String> importConstantsMap = (Map<String, String>) 
+                viewRoot.getTransientStateHelper().getTransient(IMPORT_CONSTANTS);
+        if (importConstantsMap == null)
+        {
+            Collection<UIImportConstants> constants = ViewMetadata.getImportConstants(viewRoot);
+            if (constants != null && !constants.isEmpty())
+            {
+                importConstantsMap = new HashMap<String, String>();
+                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<String, Object> constantsMap = collectConstants(type);
+                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<FeatureDescriptor> 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<String, Object> collectConstants(final String type)
+    {
+        Map<String, Object> constants = new HashMap<String, Object>();
+
+        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 <code>true</code> if the given field is a constant field, otherwise <code>false</code>.
+     */
+    private static boolean isPublicStaticFinal(Field field)
+    {
+        int modifiers = field.getModifiers();
+        return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers);
+    }
+
+}

Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java?rev=1786263&r1=1786262&r2=1786263&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java Fri Mar 10 00:20:34 2017
@@ -18,6 +18,7 @@
  */
 package org.apache.myfaces.view.facelets.tag.jsf.core;
 
+import javax.faces.component.UIImportConstants;
 import javax.faces.component.UIParameter;
 import javax.faces.component.UISelectItem;
 import javax.faces.component.UISelectItems;
@@ -114,6 +115,8 @@ public final class CoreLibrary extends A
         this.addComponent("viewAction", UIViewAction.COMPONENT_TYPE, null);
         
         this.addComponent("viewParam", UIViewParameter.COMPONENT_TYPE, null);
+        
+        this.addComponent("importConstants", UIImportConstants.COMPONENT_TYPE, null);
 
         this.addComponent("verbatim", "javax.faces.HtmlOutputText", "javax.faces.Text", VerbatimHandler.class);