Package org.apache.myfaces.view.facelets.impl

Source Code of org.apache.myfaces.view.facelets.impl.DefaultFacelet

/*
* 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.view.facelets.impl;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.el.ELException;
import javax.el.ExpressionFactory;
import javax.faces.FacesException;
import javax.faces.application.Resource;
import javax.faces.component.UIComponent;
import javax.faces.component.UniqueIdVendor;
import javax.faces.context.FacesContext;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.FaceletException;
import javax.faces.view.facelets.FaceletHandler;

import org.apache.myfaces.view.facelets.AbstractFacelet;
import org.apache.myfaces.view.facelets.AbstractFaceletContext;
import org.apache.myfaces.view.facelets.FaceletCompositionContext;


/**
* Default Facelet implementation.
*
* @author Jacob Hookom
* @version $Id: DefaultFacelet.java 1229440 2012-01-10 01:31:15Z lu4242 $
*/
final class DefaultFacelet extends AbstractFacelet
{

    //private static final Logger log = Logger.getLogger("facelets.facelet");
    private static final Logger log = Logger.getLogger(DefaultFacelet.class.getName());

    private final static String APPLIED_KEY = "org.apache.myfaces.view.facelets.APPLIED";

    private final String _alias;

    private final ExpressionFactory _elFactory;

    private final DefaultFaceletFactory _factory;

    private final long _createTime;

    private final long _refreshPeriod;

    private final Map<String, URL> _relativePaths;

    private final FaceletHandler _root;

    private final URL _src;

    private final boolean _isBuildingCompositeComponentMetadata;

    public DefaultFacelet(DefaultFaceletFactory factory, ExpressionFactory el, URL src, String alias,
                          FaceletHandler root)
    {
        _factory = factory;
        _elFactory = el;
        _src = src;
        _root = root;
        _alias = alias;
        _createTime = System.currentTimeMillis();
        _refreshPeriod = _factory.getRefreshPeriod();
        _relativePaths = new WeakHashMap<String, URL>();
        _isBuildingCompositeComponentMetadata = false;
    }
   
    public DefaultFacelet(DefaultFaceletFactory factory, ExpressionFactory el, URL src, String alias,
            FaceletHandler root, boolean isBuildingCompositeComponentMetadata)
    {
        _factory = factory;
        _elFactory = el;
        _src = src;
        _root = root;
        _alias = alias;
        _createTime = System.currentTimeMillis();
        _refreshPeriod = _factory.getRefreshPeriod();
        _relativePaths = new WeakHashMap<String, URL>();
        _isBuildingCompositeComponentMetadata = isBuildingCompositeComponentMetadata;
    }   

    /**
     * @see org.apache.myfaces.view.facelets.Facelet#apply(javax.faces.context.FacesContext,
     *      javax.faces.component.UIComponent)
     */
    public void apply(FacesContext facesContext, UIComponent parent) throws IOException, FacesException,
            FaceletException, ELException
    {
        FaceletCompositionContext myFaceletContext = null;
        boolean faceletCompositionContextInitialized = false;
        myFaceletContext = FaceletCompositionContext.getCurrentInstance(facesContext);
        if (myFaceletContext == null)
        {
            myFaceletContext = new FaceletCompositionContextImpl(_factory, facesContext);
            myFaceletContext.init(facesContext);
            faceletCompositionContextInitialized = true;
        }
        DefaultFaceletContext ctx = new DefaultFaceletContext(facesContext, this, myFaceletContext);
       
        //Set FACELET_CONTEXT_KEY on FacesContext attribute map, to
        //reflect the current facelet context instance
        facesContext.getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, ctx);
       
        ctx.pushPageContext(new PageContextImpl());
       
        try
        {
            // push the parent as a UniqueIdVendor to the stack here,
            // if there is no UniqueIdVendor on the stack yet
            boolean pushedUniqueIdVendor = false;
            if (parent instanceof UniqueIdVendor
                && ctx.getFaceletCompositionContext().getUniqueIdVendorFromStack() == null)
            {
                ctx.getFaceletCompositionContext().pushUniqueIdVendorToStack((UniqueIdVendor) parent);
                pushedUniqueIdVendor = true;
            }
           
            this.refresh(parent);
            myFaceletContext.markForDeletion(parent);
            _root.apply(ctx, parent);
            myFaceletContext.finalizeForDeletion(parent);
            this.markApplied(parent);
           
            // remove the UniqueIdVendor from the stack again
            if (pushedUniqueIdVendor)
            {
                ctx.getFaceletCompositionContext().popUniqueIdVendorToStack();
            }
        }
        finally
        {
            ctx.popPageContext();
           
            if (faceletCompositionContextInitialized)
            {
                myFaceletContext.release(facesContext);
            }
        }
    }

    private final void refresh(UIComponent c)
    {
        if (_refreshPeriod > 0)
        {

            // finally remove any children marked as deleted
            int sz = c.getChildCount();
            if (sz > 0)
            {
                UIComponent cc = null;
                List<UIComponent> cl = c.getChildren();
                ApplyToken token;
                while (--sz >= 0)
                {
                    cc = cl.get(sz);
                    if (!cc.isTransient())
                    {
                        token = (ApplyToken) cc.getAttributes().get(APPLIED_KEY);
                        if (token != null && token._time < _createTime && token._alias.equals(_alias))
                        {
                            if (log.isLoggable(Level.INFO))
                            {
                                DateFormat df = SimpleDateFormat.getTimeInstance();
                                log.info("Facelet[" + _alias + "] was modified @ "
                                        + df.format(new Date(_createTime)) + ", flushing component applied @ "
                                        + df.format(new Date(token._time)));
                            }
                            cl.remove(sz);
                        }
                    }
                }
            }

            // remove any facets marked as deleted
            if (c.getFacets().size() > 0)
            {
                Collection<UIComponent> col = c.getFacets().values();
                UIComponent fc;
                ApplyToken token;
                for (Iterator<UIComponent> itr = col.iterator(); itr.hasNext();)
                {
                    fc = itr.next();
                    if (!fc.isTransient())
                    {
                        token = (ApplyToken) fc.getAttributes().get(APPLIED_KEY);
                        if (token != null && token._time < _createTime && token._alias.equals(_alias))
                        {
                            if (log.isLoggable(Level.INFO))
                            {
                                DateFormat df = SimpleDateFormat.getTimeInstance();
                                log.info("Facelet[" + _alias + "] was modified @ "
                                        + df.format(new Date(_createTime)) + ", flushing component applied @ "
                                        + df.format(new Date(token._time)));
                            }
                            itr.remove();
                        }
                    }
                }
            }
        }
    }

    private final void markApplied(UIComponent parent)
    {
        if (this._refreshPeriod > 0)
        {
            int facetCount = parent.getFacetCount();
            int childCount = parent.getChildCount();
            if (childCount > 0 || facetCount > 0)
            {
                ApplyToken token = new ApplyToken(_alias, System.currentTimeMillis() + _refreshPeriod);

                if (facetCount > 0)
                {
                    for (UIComponent facet : parent.getFacets().values())
                    {
                        markApplied(token, facet);
                    }
                }
                for (int i = 0; i < childCount; i++)
                {
                    UIComponent child = parent.getChildren().get(i);
                    markApplied(token, child);
                }
            }
        }
    }

    private void markApplied(ApplyToken token, UIComponent c)
    {
        if (!c.isTransient())
        {
            Map<String, Object> attr = c.getAttributes();
            if (!attr.containsKey(APPLIED_KEY))
            {
                attr.put(APPLIED_KEY, token);
            }
        }
    }

    /**
     * Return the alias name for error messages and logging
     *
     * @return alias name
     */
    public String getAlias()
    {
        return _alias;
    }

    /**
     * Return this Facelet's ExpressionFactory instance
     *
     * @return internal ExpressionFactory instance
     */
    public ExpressionFactory getExpressionFactory()
    {
        return _elFactory;
    }

    /**
     * The time when this Facelet was created, NOT the URL source code
     *
     * @return final timestamp of when this Facelet was created
     */
    public long getCreateTime()
    {
        return _createTime;
    }

    /**
     * Delegates resolution to DefaultFaceletFactory reference. Also, caches URLs for relative paths.
     *
     * @param path
     *            a relative url path
     * @return URL pointing to destination
     * @throws IOException
     *             if there is a problem creating the URL for the path specified
     */
    private URL getRelativePath(String path) throws IOException
    {
        URL url = (URL) _relativePaths.get(path);
        if (url == null)
        {
            url = _factory.resolveURL(_src, path);
            _relativePaths.put(path, url);
        }
        return url;
    }

    /**
     * The URL this Facelet was created from.
     *
     * @return the URL this Facelet was created from
     */
    public URL getSource()
    {
        return _src;
    }

    /**
     * Given the passed FaceletContext, apply our child FaceletHandlers to the passed parent
     *
     * @see FaceletHandler#apply(FaceletContext, UIComponent)
     * @param ctx
     *            the FaceletContext to use for applying our FaceletHandlers
     * @param parent
     *            the parent component to apply changes to
     * @throws IOException
     * @throws FacesException
     * @throws FaceletException
     * @throws ELException
     */
    private void include(AbstractFaceletContext ctx, UIComponent parent) throws IOException, FacesException,
            FaceletException, ELException
    {
        ctx.pushPageContext(new PageContextImpl());
        try
        {
            this.refresh(parent);
            DefaultFaceletContext ctxWrapper = new DefaultFaceletContext((DefaultFaceletContext)ctx, this, false);
            ctx.getFacesContext().getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, ctxWrapper);
            _root.apply(ctxWrapper, parent);
            ctx.getFacesContext().getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, ctx);
            this.markApplied(parent);
        }
        finally
        {
            ctx.popPageContext();
        }
    }

    /**
     * Used for delegation by the DefaultFaceletContext. First pulls the URL from {@link #getRelativePath(String)
     * getRelativePath(String)}, then calls
     * {@link #include(org.apache.myfaces.view.facelets.AbstractFaceletContext,
     * javax.faces.component.UIComponent, java.net.URL)}.
     *
     * @see FaceletContext#includeFacelet(UIComponent, String)
     * @param ctx
     *            FaceletContext to pass to the included Facelet
     * @param parent
     *            UIComponent to apply changes to
     * @param path
     *            relative path to the desired Facelet from the FaceletContext
     * @throws IOException
     * @throws FacesException
     * @throws FaceletException
     * @throws ELException
     */
    public void include(AbstractFaceletContext ctx, UIComponent parent, String path)
            throws IOException, FacesException, FaceletException, ELException
    {
        URL url = this.getRelativePath(path);
        this.include(ctx, parent, url);
    }

    /**
     * Grabs a DefaultFacelet from referenced DefaultFaceletFacotry
     *
     * @see DefaultFaceletFactory#getFacelet(URL)
     * @param ctx
     *            FaceletContext to pass to the included Facelet
     * @param parent
     *            UIComponent to apply changes to
     * @param url
     *            URL source to include Facelet from
     * @throws IOException
     * @throws FacesException
     * @throws FaceletException
     * @throws ELException
     */
    public void include(AbstractFaceletContext ctx, UIComponent parent, URL url) throws IOException, FacesException,
            FaceletException, ELException
    {
        DefaultFacelet f = (DefaultFacelet) _factory.getFacelet(url);
        f.include(ctx, parent);
    }
   
    public void applyCompositeComponent(AbstractFaceletContext ctx, UIComponent parent, Resource resource)
            throws IOException, FacesException, FaceletException, ELException
    {
        // Here we are creating a facelet using the url provided by the resource.
        // It works, but the Resource API provides getInputStream() for that. But the default
        // implementation wraps everything that could contain ValueExpression and decode so
        // we can't use it here.
        //DefaultFacelet f = (DefaultFacelet) _factory.getFacelet(resource.getURL());
        //f.apply(ctx.getFacesContext(), parent);
        DefaultFacelet f = (DefaultFacelet) _factory.getFacelet(resource.getURL());
       
        ctx.pushPageContext(new PageContextImpl());
        try
        {
            // push the parent as a UniqueIdVendor to the stack here,
            // if there is no UniqueIdVendor on the stack yet
            boolean pushedUniqueIdVendor = false;
            FaceletCompositionContext mctx = ctx.getFaceletCompositionContext();
            if (parent instanceof UniqueIdVendor
                && ctx.getFaceletCompositionContext().getUniqueIdVendorFromStack() == null)
            {
                mctx.pushUniqueIdVendorToStack((UniqueIdVendor) parent);
                pushedUniqueIdVendor = true;
            }
           
            this.refresh(parent);
            mctx.markForDeletion(parent);
            DefaultFaceletContext ctxWrapper = new DefaultFaceletContext( (DefaultFaceletContext)ctx, f, true);
            //Update FACELET_CONTEXT_KEY on FacesContext attribute map, to
            //reflect the current facelet context instance
            ctx.getFacesContext().getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, ctxWrapper);
            f._root.apply(ctxWrapper, parent);
            ctx.getFacesContext().getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, ctx);
            mctx.finalizeForDeletion(parent);
            this.markApplied(parent);
           
            // remove the UniqueIdVendor from the stack again
            if (pushedUniqueIdVendor)
            {
                ctx.getFaceletCompositionContext().popUniqueIdVendorToStack();
            }
        }
        finally
        {
            ctx.popPageContext();
        }
    }

    private static class ApplyToken implements Externalizable
    {
        public String _alias;

        public long _time;

        public ApplyToken()
        {
        }

        public ApplyToken(String alias, long time)
        {
            _alias = alias;
            _time = time;
        }

        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
        {
            _alias = in.readUTF();
            _time = in.readLong();
        }

        public void writeExternal(ObjectOutput out) throws IOException
        {
            out.writeUTF(_alias);
            out.writeLong(_time);
        }
    }

    public String toString()
    {
        return _alias;
    }

    @Override
    public boolean isBuildingCompositeComponentMetadata()
    {
        return _isBuildingCompositeComponentMetadata;
    }
}
TOP

Related Classes of org.apache.myfaces.view.facelets.impl.DefaultFacelet

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.