Package org.apache.myfaces.commons.resourcehandler

Source Code of org.apache.myfaces.commons.resourcehandler.ExtendedResourceHandlerImpl

/*
* 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.commons.resourcehandler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPOutputStream;

import javax.faces.FacesException;
import javax.faces.application.ProjectStage;
import javax.faces.application.Resource;
import javax.faces.application.ResourceHandler;
import javax.faces.application.ResourceHandlerWrapper;
import javax.faces.application.ResourceWrapper;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;

import org.apache.myfaces.commons.resourcehandler.config.element.Library;
import org.apache.myfaces.commons.resourcehandler.resource.ResourceHandlerCache;
import org.apache.myfaces.commons.resourcehandler.resource.ResourceHandlerCache.ResourceValue;
import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoader;
import org.apache.myfaces.commons.resourcehandler.resource.ResourceMeta;
import org.apache.myfaces.commons.util.ClassUtils;
import org.apache.myfaces.commons.util.ExternalContextUtils;
import org.apache.myfaces.commons.util.RequestType;
import org.apache.myfaces.commons.util.StringUtils;

/**
*
* @author Leonardo Uribe
*
*/
public class ExtendedResourceHandlerImpl extends ResourceHandlerWrapper
{
    private static final String IS_RESOURCE_REQUEST = "org.apache.myfaces.commons.IS_RESOURCE_REQUEST";
   
    private static final String RESOURCE_LOCALE = "org.apache.myfaces.commons.RESOURCE_LOCALE";

    private ExtendedDefaultResourceHandlerSupport _resourceHandlerSupport;

    private ResourceHandlerCache _resourceHandlerCache;

    //private static final Log log = LogFactory.getLog(ResourceHandlerImpl.class);
    private static final Logger log = Logger.getLogger(ExtendedResourceHandlerImpl.class.getName());

    private static final int _BUFFER_SIZE = 2048;
   
    private ResourceHandler _delegate;
   
    //private volatile Boolean filterOn;

    public ExtendedResourceHandlerImpl(ResourceHandler delegate)
    {
        this._delegate = delegate;
        //Eager initialization
        _resourceHandlerSupport = new ExtendedDefaultResourceHandlerSupport();
    }
   
    /*
    @Override
    public Resource createResource(String resourceName)
    {
        return createResource(resourceName, null);
    }*/
   
    @Override
    public Resource createResource(String resourceName, String libraryName)
    {
        if (getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(libraryName) != null)
        {
            return createResource(resourceName, libraryName, null);
        }
        else
        {
            return super.createResource(resourceName, libraryName);
        }
    }

    @Override
    public Resource createResource(String resourceName, String libraryName,
            String contentType)
    {
        if (getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(libraryName) != null)
        {
            return defaultCreateResource(resourceName, libraryName, contentType);
        }
        else
        {
            return super.createResource(resourceName, libraryName, contentType);
        }
    }
   
    private Resource defaultCreateResource(String resourceName, String expectedLibraryName,
            String contentType)
    {
        Resource resource = null;

        FacesContext facesContext = FacesContext.getCurrentInstance();

        if (contentType == null)
        {
            //Resolve contentType using ExternalContext.getMimeType
            contentType = facesContext.getExternalContext().getMimeType(resourceName);
        }
       
        String localePrefix = (String) facesContext.getAttributes().get(RESOURCE_LOCALE);
       
        if (localePrefix == null)
        {
            localePrefix = getLocalePrefixForLocateResource();
        }
       
        //Calculate the real libraryName
        String redirectedLibraryName = resolveLibraryName(expectedLibraryName);

        // check cache
        if(getResourceLoaderCache().containsResource(resourceName, redirectedLibraryName, contentType, localePrefix))
        {
            ResourceValue resourceValue = getResourceLoaderCache().getResource(
                    resourceName, redirectedLibraryName, contentType, localePrefix);
           
            //resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
            //        getResourceHandlerSupport(), contentType);
            resource = new ExtendedResourceImpl((ExtendedResourceMeta) resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
                    getResourceHandlerSupport(), contentType, localePrefix, redirectedLibraryName.equals(expectedLibraryName) ? null : expectedLibraryName);
        }
        else
        {
            for (ResourceLoader loader : getResourceHandlerSupport().getResourceLoaders())
            {
                ResourceMeta resourceMeta = deriveResourceMeta(loader, resourceName, redirectedLibraryName, localePrefix);
   
                if (resourceMeta != null)
                {
                    //resource = new ResourceImpl(resourceMeta, loader, getResourceHandlerSupport(), contentType);
                    resource = new ExtendedResourceImpl((ExtendedResourceMeta) resourceMeta, loader, getResourceHandlerSupport(), contentType, localePrefix,
                            redirectedLibraryName.equals(expectedLibraryName) ? null : expectedLibraryName);

                    // cache it
                    getResourceLoaderCache().putResource(resourceName, redirectedLibraryName, contentType,
                            localePrefix, resourceMeta, loader);
                    break;
                }
            }
        }
       
        return resource;
    }

    public String resolveLibraryName(String libraryName)
    {
        String finalLibraryName = libraryName;
        Library library = null;
        boolean resolved = false;
        do
        {
            library = getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(finalLibraryName);
            if (library != null)
            {
                if (library.getRedirectName() != null && library.getRedirectName().length() > 0)
                {
                    finalLibraryName = library.getRedirectName();
                }
                else
                {
                    //No redirect, so this is the real instance
                    resolved = true;
                }
            }
        } while (library != null && !resolved);
       
        return finalLibraryName;
    }
   
    /**
     * This method try to create a ResourceMeta for a specific resource
     * loader. If no library, or resource is found, just return null,
     * so the algorithm in createResource can continue checking with the
     * next registered ResourceLoader.
     */
    protected ExtendedResourceMeta deriveResourceMeta(ResourceLoader resourceLoader,
            String resourceName, String libraryName, String localePrefix)
    {
        String resourceVersion = null;
        String libraryVersion = null;
        ExtendedResourceMeta resourceId = null;
       
        //1. Try to locate resource in a localized path
        if (localePrefix != null)
        {
            if (null != libraryName)
            {
                String pathToLib = localePrefix + '/' + libraryName;
                libraryVersion = resourceLoader.getLibraryVersion(pathToLib);

                if (null != libraryVersion)
                {
                    String pathToResource = localePrefix + '/'
                            + libraryName + '/' + libraryVersion + '/'
                            + resourceName;
                    resourceVersion = resourceLoader
                            .getResourceVersion(pathToResource);
                }
                else
                {
                    String pathToResource = localePrefix + '/'
                            + libraryName + '/' + resourceName;
                    resourceVersion = resourceLoader
                            .getResourceVersion(pathToResource);
                }

                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
                {
                    resourceId = (ExtendedResourceMeta) resourceLoader.createResourceMeta(localePrefix, libraryName,
                            libraryVersion, resourceName, resourceVersion);
                }
            }
            else
            {
                resourceVersion = resourceLoader
                        .getResourceVersion(localePrefix + '/'+ resourceName);
                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
                {              
                    resourceId = (ExtendedResourceMeta) resourceLoader.createResourceMeta(localePrefix, null, null,
                            resourceName, resourceVersion);
                }
            }

            if (resourceId != null)
            {
                if (!resourceLoader.resourceExists(resourceId))
                {
                    resourceId = null;
                }
            }           
        }
       
        //2. Try to localize resource in a non localized path
        if (resourceId == null)
        {
            if (null != libraryName)
            {
                libraryVersion = resourceLoader.getLibraryVersion(libraryName);

                if (null != libraryVersion)
                {
                    String pathToResource = (libraryName + '/' + libraryVersion
                            + '/' + resourceName);
                    resourceVersion = resourceLoader
                            .getResourceVersion(pathToResource);
                }
                else
                {
                    String pathToResource = (libraryName + '/'
                            + resourceName);
                    resourceVersion = resourceLoader
                            .getResourceVersion(pathToResource);
                }

                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
                {              
                    resourceId = (ExtendedResourceMeta) resourceLoader.createResourceMeta(null, libraryName,
                            libraryVersion, resourceName, resourceVersion);
                }
            }
            else
            {
                resourceVersion = resourceLoader
                        .getResourceVersion(resourceName);
               
                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
                {              
                    resourceId = (ExtendedResourceMeta) resourceLoader.createResourceMeta(null, null, null,
                            resourceName, resourceVersion);
                }
            }

            if (resourceId != null)
            {
                if (!resourceLoader.resourceExists(resourceId))
                {
                    resourceId = null;
                }
            }           
        }
       
        return resourceId;
    }

    /**
     *  Handle the resource request, writing in the output.
     * 
     *  This method implements an algorithm semantically identical to
     *  the one described on the javadoc of ResourceHandler.handleResourceRequest
     */
    @Override
    public void handleResourceRequest(FacesContext facesContext) throws IOException
    {
        // Only if filter is on
        //if (!isFilterOn())
        //{
        //    super.handleResourceRequest(facesContext);
        //}
       
        // And this is a request handled from the filter first!
        //if (!facesContext.getAttributes().containsKey(ResourceHandlerFilter.RESOURCE_HANDLER_FILTER_REQUEST))
        //{
        //    super.handleResourceRequest(facesContext);
        //}
       
        try
        {
            String resourceBasePath = getResourceHandlerSupport()
                    .calculateResourceBasePath(facesContext);
   
            if (resourceBasePath == null)
            {
                // No base name could be calculated, so no further
                //advance could be done here. HttpServletResponse.SC_NOT_FOUND
                //cannot be returned since we cannot extract the
                //resource base name
                super.handleResourceRequest(facesContext);
                return;
            }
   
            // We neet to get an instance of HttpServletResponse, but sometimes
            // the response object is wrapped by several instances of
            // ServletResponseWrapper (like ResponseSwitch).
            // Since we are handling a resource, we can expect to get an
            // HttpServletResponse.
            if (!RequestType.SERVLET.equals(ExternalContextUtils.getRequestType(facesContext.getExternalContext())))
            {
                throw new IllegalStateException("Could not obtain an instance of HttpServletResponse.");
            }
            Object response = facesContext.getExternalContext().getResponse();
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            if (httpServletResponse == null)
            {
                throw new IllegalStateException("Could not obtain an instance of HttpServletResponse.");
            }
   
            if (isResourceIdentifierExcluded(facesContext, resourceBasePath))
            {
                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return;
            }

            String resourceName = null;
            String libraryName = null;
            String requestedLocalePrefix = null;
            if (resourceBasePath.startsWith(getResourceHandlerSupport().getResourceIdentifier()))
            {
                //resourceName = resourceBasePath
                //        .substring(ResourceHandler.RESOURCE_IDENTIFIER.length() + 1);
                resourceName = resourceBasePath
                        .substring(getResourceHandlerSupport().getResourceIdentifier().length());
               
                if (resourceName.startsWith("/$"))
                {
                    //Extract locale prefix, libraryName and resourceName
                    int from = 3;
                    int to = resourceName.indexOf('/',3);
                    requestedLocalePrefix = resourceName.substring(from,to);
                    from = to+1;
                    to = resourceName.indexOf('/', from);
                    libraryName = resourceName.substring(from, to);
                    resourceName = resourceName.substring(to+1);
                }
                else
                {
                    //No special identifier used, delegate to default algorithm
                    resourceName = null;
                    //Try to get the library name using the standard form
                    //libraryName = facesContext.getExternalContext()
                    //    .getRequestParameterMap().get("ln");
                }
            }
            else
            {
                //Does not have the conditions for be a resource call, let the base one
                //return not found
                super.handleResourceRequest(facesContext);
                return;
            }
           
            //Only resources with resourceName and advanced libraryName are handled by this handler
            if (resourceName == null)
            {
                super.handleResourceRequest(facesContext);
                return;
            }
            else if (libraryName == null)
            {
                super.handleResourceRequest(facesContext);
                return;
            }
            else if (libraryName != null && getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(libraryName) == null)
            {
                super.handleResourceRequest(facesContext);
                return;
            }
   
            if (requestedLocalePrefix != null)
            {
                facesContext.getAttributes().put(RESOURCE_LOCALE, requestedLocalePrefix);
            }
           
            Resource resource = null;
            //if (libraryName != null)
            //{
                //log.info("libraryName=" + libraryName);
                resource = facesContext.getApplication().getResourceHandler().createResource(resourceName, libraryName);
            //}
            //else
            //{
            //    resource = facesContext.getApplication().getResourceHandler().createResource(resourceName);
            //}
   
            if (resource == null)
            {
                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return;
            }
   
            if (!resource.userAgentNeedsUpdate(facesContext))
            {
                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                return;
            }
   
            httpServletResponse.setContentType(_getContentType(resource, facesContext.getExternalContext()));
   
            Map<String, String> headers = resource.getResponseHeaders();
   
            for (Map.Entry<String, String> entry : headers.entrySet())
            {
                httpServletResponse.setHeader(entry.getKey(), entry.getValue());
            }
           
            //serve up the bytes (taken from trinidad ResourceServlet)
            try
            {
                // we should serve a compressed version of the resource, if
                //   - ProjectStage != Development
                //   - a compressed version is available (created in constructor)
                //   - the user agent supports compresssion
                // and if there is no caching on disk, do compression here!
                if (!facesContext.isProjectStage(ProjectStage.Development) &&
                    getResourceHandlerSupport().isGzipResourcesEnabled() &&
                    !getResourceHandlerSupport().isCacheDiskGzipResources() &&
                    getResourceHandlerSupport().userAgentSupportsCompression(facesContext) &&
                    getResourceHandlerSupport().isCompressable(resource))
                {
                    InputStream in = resource.getInputStream();
                    OutputStream out = new GZIPOutputStream(httpServletResponse.getOutputStream(), _BUFFER_SIZE);
                    byte[] buffer = new byte[_BUFFER_SIZE];
       
                    try
                    {
                        int count = pipeBytes(in, out, buffer);
                        //set the content lenght
                        httpServletResponse.setContentLength(count);
                    }
                    finally
                    {
                        try
                        {
                            in.close();
                        }
                        finally
                        {
                            out.close();
                        }
                    }
                }
                else
                {
                    InputStream in = resource.getInputStream();
                    OutputStream out = httpServletResponse.getOutputStream();
                    byte[] buffer = new byte[_BUFFER_SIZE];
       
                    try
                    {
                        int count = pipeBytes(in, out, buffer);
                        //set the content lenght
                        httpServletResponse.setContentLength(count);
                    }
                    finally
                    {
                        try
                        {
                            in.close();
                        }
                        finally
                        {
                            out.close();
                        }
                    }
                }
            }
            catch (IOException e)
            {
                //TODO: Log using a localized message (which one?)
                if (log.isLoggable(Level.SEVERE))
                    log.severe("Error trying to load resource " + resourceName
                            + " with library " + libraryName + " :"
                            + e.getMessage());
                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
            }
        }
        catch (Throwable ex)
        {
            // handle the Throwable accordingly. Maybe generate an error page.
            // FIXME we are creating a html error page for a non html request here
            // shouln't we do something better? -=Jakob Korherr=-
            throw new FacesException(ex);
            //ErrorPageWriter.handleThrowable(facesContext, ex);
        }
    }

    /**
     * Reads the specified input stream into the provided byte array storage and
     * writes it to the output stream.
     */
    private static int pipeBytes(InputStream in, OutputStream out, byte[] buffer)
            throws IOException
    {
        int count = 0;
        int length;

        while ((length = (in.read(buffer))) >= 0)
        {
            out.write(buffer, 0, length);
            count += length;
        }
        return count;
    }

    @Override
    public boolean isResourceRequest(FacesContext facesContext)
    {
        // Since this method could be called many times we save it
        //on request map so the first time is calculated it remains
        //alive until the end of the request
        Boolean value = (Boolean) facesContext.getAttributes().get(IS_RESOURCE_REQUEST);

        if (value != null && value)
        {
            //return the saved value
            return value;
        }
        else
        {
            String resourceBasePath = getResourceHandlerSupport()
                    .calculateResourceBasePath(facesContext);

            if (resourceBasePath != null
                    && resourceBasePath.startsWith(getResourceHandlerSupport().getResourceIdentifier()))
            {
                facesContext.getAttributes().put(IS_RESOURCE_REQUEST, Boolean.TRUE);
                return true;
            }
            else
            {
                value = super.isResourceRequest(facesContext);
                facesContext.getAttributes().put(IS_RESOURCE_REQUEST, value);
                return value;
            }
        }
    }

    protected String getLocalePrefixForLocateResource()
    {
        String localePrefix = null;
        FacesContext context = FacesContext.getCurrentInstance();

        String bundleName = context.getApplication().getMessageBundle();

        if (null != bundleName)
        {
            Locale locale = context.getApplication().getViewHandler()
                    .calculateLocale(context);

            ResourceBundle bundle = ResourceBundle
                    .getBundle(bundleName, locale, ClassUtils.getContextClassLoader());

            if (bundle != null)
            {
                try
                {
                    localePrefix = bundle.getString(ResourceHandler.LOCALE_PREFIX);
                }
                catch (MissingResourceException e)
                {
                    // Ignore it and return null
                }
            }
        }
        return localePrefix;
    }

    protected boolean isResourceIdentifierExcluded(FacesContext context,
            String resourceIdentifier)
    {
        String value = context.getExternalContext().getInitParameter(
                RESOURCE_EXCLUDES_PARAM_NAME);
        if (value == null)
        {
            value = RESOURCE_EXCLUDES_DEFAULT_VALUE;
        }
        //TODO: optimize this code
        String[] extensions = StringUtils.splitShortString(value, ' ');
        for (int i = 0; i < extensions.length; i++)
        {
            if (resourceIdentifier.endsWith(extensions[i]))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Check if a library exists or not. This is done delegating
     * to each ResourceLoader used, because each one has a different
     * prefix and way to load resources.
     *
     */
    @Override
    public boolean libraryExists(String libraryName)
    {
        if (getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(libraryName) != null)
        {
            String localePrefix = getLocalePrefixForLocateResource();
   
            String pathToLib = null;
           
            if (localePrefix != null)
            {
                //Check with locale
                pathToLib = localePrefix + '/' + libraryName;
               
                for (ResourceLoader loader : getResourceHandlerSupport()
                        .getResourceLoaders())
                {
                    if (loader.libraryExists(pathToLib))
                    {
                        return true;
                    }
                }           
            }
   
            //Check without locale
            for (ResourceLoader loader : getResourceHandlerSupport()
                    .getResourceLoaders())
            {
                if (loader.libraryExists(libraryName))
                {
                    return true;
                }
            }
        }
        else
        {
            super.libraryExists(libraryName);
        }

        return false;
    }

    /**
     * @param resourceHandlerSupport
     *            the resourceHandlerSupport to set
     */
    public void setResourceHandlerSupport(
            ExtendedDefaultResourceHandlerSupport resourceHandlerSupport)
    {
        _resourceHandlerSupport = resourceHandlerSupport;
    }

    /**
     * @return the resourceHandlerSupport
     */
    protected ExtendedDefaultResourceHandlerSupport getResourceHandlerSupport()
    {
        return _resourceHandlerSupport;
    }

    private ResourceHandlerCache getResourceLoaderCache()
    {
        if (_resourceHandlerCache == null)
            _resourceHandlerCache = new ResourceHandlerCache();
        return _resourceHandlerCache;
    }

    private String _getContentType(Resource resource, ExternalContext externalContext)
    {
        String contentType = resource.getContentType();

        // the resource does not provide a content-type --> determine it via mime-type
        if (contentType == null || contentType.length() == 0)
        {
            String resourceName = getWrappedResourceName(resource);

            if (resourceName != null)
            {
                contentType = externalContext.getMimeType(resourceName);
            }
        }

        return contentType;
    }

    /**
     * Recursively unwarp the resource until we find the real resourceName
     * This is needed because the JSF2 specced ResourceWrapper doesn't override
     * the getResourceName() method :(
     * @param resource
     * @return the first non-null resourceName or <code>null</code> if none set
     */
    private String getWrappedResourceName(Resource resource)
    {
        String resourceName = resource.getResourceName();
        if (resourceName != null)
        {
            return resourceName;
        }

        if (resource instanceof ResourceWrapper)
        {
            return getWrappedResourceName(((ResourceWrapper) resource).getWrapped());
        }

        return null;
    }

    @Override
    public ResourceHandler getWrapped()
    {
        return _delegate;
    }
}
TOP

Related Classes of org.apache.myfaces.commons.resourcehandler.ExtendedResourceHandlerImpl

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.