Package org.openfaces.util

Source Code of org.openfaces.util.Resources

/*
* OpenFaces - JSF Component Library 2.0
* Copyright (C) 2007-2012, TeamDev Ltd.
* licensing@openfaces.org
* Unless agreed in writing the contents of this file are subject to
* the GNU Lesser General Public License Version 2.1 (the "LGPL" License).
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* Please visit http://openfaces.org/licensing/ for more details.
*/
package org.openfaces.util;

import org.openfaces.org.json.JSONException;
import org.openfaces.org.json.JSONObject;
import org.openfaces.org.json.JSONTokener;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

/**
* @author Dmitry Pikhulya
*/
public class Resources {
    public static final String HEADER_JS_LIBRARIES = "OF:js_file_included";
    public static final String RENDERED_JS_LINKS = "org.openfaces.util.Rendering.renderedJsLinks";
    public static final String POSTPONE_JS_LINK_RENDERING = "org.openfaces.util.Resources.postponeJsLinkRendering";
    public static final String JSON_JS_LIB_NAME = "util/json2.js";

    private static final String OPENFACES_VERSION_TXT = "/META-INF/openFacesVersion.txt";
    private static final String VERSION_PLACEHOLDER_STR = "version";

    private static final String CLDR = "cldr";
    private static final String NUMBER_LOCALE_SETTINGS = "number.js";
    private static final String PARAM_ORG_OPENFACES_JQUERY = "org.openfaces.jquery";
    public static final String META_INF_RESOURCES_ROOT = "/META-INF/resources/openfaces/";

    private Resources() {
    }

    /**
     * This method returns the URL string ready for rendering into HTML based on the URL specified by the user. If
     * URL is not specified by the user explicitly then URL to a default internal resource is returned instead.
     *
     * @param userSpecifiedUrl             optional resource url as specified by the user. This can be a relative URL, or an absolute URL
     * @param defaultResourceFileName      file name for a resource which should be provided if userSpecifiedUrl is null or empty string
     * @param defaultResourceBaseClassName the class relatively to which defaultResourceFileName is specified
     * @return
     */
    public static String getURL(FacesContext context, String userSpecifiedUrl,
                                Class defaultResourceBaseClassName, String defaultResourceFileName) {
        return getURL(context, userSpecifiedUrl, defaultResourceBaseClassName, defaultResourceFileName, true);
    }

    /**
     * @param userSpecifiedUrl             optional resource url as specified by the user. This can be a relative URL, or an absolute URL
     * @param defaultResourceFileName      file name for a resource which should be provided if userSpecifiedUrl is null (or empty string).
     *                                     Empty string is also considered as signal for returning the default resource here because null
     *                                     is auto-converted to an empty string when passed through a string binding
     * @param defaultResourceBaseClassName the class relatively to which defaultResourceFileName is specified
     * @param prependContextPath           use true here if you render the attribute yourself, and false if you use pass this URL to HtmlGraphicImage or similar component
     */
    public static String getURL(
            FacesContext context,
            String userSpecifiedUrl,
            Class defaultResourceBaseClassName,
            String defaultResourceFileName,
            boolean prependContextPath) {
        boolean returnDefaultResource = userSpecifiedUrl == null || userSpecifiedUrl.length() == 0;
        String result = returnDefaultResource
                ? internalURL(context, defaultResourceBaseClassName, defaultResourceFileName, prependContextPath)
                : (prependContextPath ? applicationURL(context, userSpecifiedUrl) : userSpecifiedUrl);
        return result;
    }

    /**
     * Get path to application resource according to context and resource path
     *
     * @param context      faces context provided by application
     * @param resourcePath path to resource - either absolute (starting with a slash) in the scope of application context,
     *                     or relative to the current page
     * @return full URL to resource ready for rendering as <code>src</code> or <code>href</code> attribute's value.
     */
    public static String applicationURL(FacesContext context, String resourcePath) {
        if (resourcePath == null || resourcePath.length() == 0)
            return "";
        ViewHandler viewHandler = context.getApplication().getViewHandler();
        String resourceUrl = viewHandler.getResourceURL(context, resourcePath);
        String encodedResourceUrl = context.getExternalContext().encodeResourceURL(resourceUrl);
        return encodedResourceUrl;
    }

    /**
     * A method which is a facade for JSF 1.2 and JSF 2.0 implementations of resource name generation. It has
     * different implementations in the appropriate OpenFaces branches.
     */
    public static String internalURL(FacesContext context, String resourceName) {
        return internalURL(context, null, resourceName, true);
    }

    public static String internalURL(FacesContext context, Class componentClass, String resourceName) {
        return internalURL(context, componentClass, resourceName, true);
    }

    private static String getPackagePath(Class componentClass) {
        String packageName = componentClass == null ? "" : getPackageName(componentClass);
        String packagePath = packageName.replace('.', '/');
        if (packagePath.length() > 0) {
            packagePath += "/";
        }
        return packagePath;
    }

    /**
     * @param context            Current FacesContext
     * @param componentClass     Class, relative to which the resourcePath is specified
     * @param resourcePath       Path to the resource file
     * @param prependContextPath true means that the resulting url should be prefixed with context root. This is the case
     *                           when the returned URL is rendered without any modifications. Passing false to this
     *                           parameter is required in cases when the returned URL is passed to some component which
     *                           expects application URL, so the component will prepend the URL with context root itself.
     * @return The requested URL
     */
    public static String internalURL(
            FacesContext context,
            Class componentClass,
            String resourcePath,
            boolean prependContextPath) {
        if (context == null) throw new NullPointerException("context");
        if (resourcePath == null) throw new NullPointerException("resourcePath");

        if (componentClass == null)
            resourcePath = META_INF_RESOURCES_ROOT + resourcePath;
        String packagePath = getPackagePath(componentClass);
        if (resourcePath.startsWith("/")) {
            packagePath = "";
            resourcePath = resourcePath.substring(1);
        }

        String versionString = getVersionString();
        int extensionIndex = resourcePath.lastIndexOf(".");
        String urlRelativeToContextRoot = ResourceFilter.INTERNAL_RESOURCE_PATH + packagePath +
                resourcePath.substring(0, extensionIndex) + "-" + versionString + resourcePath.substring(extensionIndex);

        if (!prependContextPath)
            return urlRelativeToContextRoot;

        return applicationURL(context, urlRelativeToContextRoot);
    }

    private static String versionString;

    /**
     * Return version of OpenFaces
     *
     * @return requested version of OpenFaces
     */
    public static String getVersionString() {
        if (versionString != null)
            return versionString;

        String buildInfo = readBuildInfo();

        String version = "";
        if (buildInfo != null) {
            int idx1 = buildInfo.indexOf(",");
            version = buildInfo.substring(0, idx1).trim();
            if (VERSION_PLACEHOLDER_STR.equals(version)) {
                long startTime = System.currentTimeMillis() / 1000;
                version = Long.toString(startTime, 36);
            }
        }

        versionString = version;
        return version;
    }

    private static String readBuildInfo() {
        InputStream versionStream = Resources.class.getResourceAsStream(OPENFACES_VERSION_TXT);
        if (versionStream == null)
            throw new IllegalStateException("Couldn't find resource file: " + OPENFACES_VERSION_TXT);

        String buildInfo = null;
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(versionStream));
        try {
            buildInfo = bufferedReader.readLine();
        } catch (IOException e) {
            Log.log("Couldn't read version string", e);
        } finally {
            try {
                bufferedReader.close();
            } catch (IOException e) {
                //
            }
        }
        return buildInfo;
    }


    public static JSONObject getNumberFormatSettings(Locale locale) throws IOException, JSONException {
        String cldrPath = "/" + getPackagePath(Resources.class) + CLDR;

        InputStream numberStream = null;
        if (locale != null) {
            numberStream = Resources.class.getResourceAsStream(cldrPath + "/" + locale.toString() + "/" + NUMBER_LOCALE_SETTINGS);
        }
        if (numberStream == null) {
            numberStream = Resources.class.getResourceAsStream(cldrPath + "/" + NUMBER_LOCALE_SETTINGS);
        }
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(numberStream, "UTF-8"));
            String text;
            do {
                text = bufferedReader.readLine();
            } while (text.startsWith("/*") || text.startsWith(" *") || text.trim().length() == 0);
            text = text.substring(1, text.length() - 1);
            JSONObject result = new JSONObject(new JSONTokener(text));
            return result;
        } finally {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
        }

    }


    /**
     * Return URL of util.js file
     *
     * @param context {@link FacesContext} for the current request
     * @return requested URL of util.js file
     */
    public static String utilJsURL(FacesContext context) {
        // To be sure that default.css is included to the web page,
        // because it is also required in cases when util.js included into web page
        Styles.requestDefaultCss(context);
        return internalURL(context, "util/util.js");
    }

    public static String filtersJsURL(FacesContext context) {
        return Resources.internalURL(context, "filter/filters.js");
    }

    /**
     * Return URL of ajaxUtil.js file. Keep in mind that ajaxUtil.js depends on util.js.
     * Don't forget to include util.js as well before including this URL.
     *
     * @param context {@link FacesContext} for the current request
     * @return requested URL of ajaxUtil.js file
     */
    public static String ajaxUtilJsURL(FacesContext context) {
        return Resources.internalURL(context, "util/ajaxUtil.js");
    }

    /**
     * Return URL of json javascript file
     *
     * @param context {@link FacesContext} for the current request
     * @return requested URL of json javascript file
     */
    public static String jsonJsURL(FacesContext context) {
        return Resources.internalURL(context, JSON_JS_LIB_NAME);
    }

    /**
     * Return full package name for Class
     *
     * @param aClass The Class object
     * @return full package name for given Class
     */
    private static String getPackageName(Class aClass) {
        String className = aClass.getName();
        int lastIndexOfDot = className.lastIndexOf('.');
        if (lastIndexOfDot == -1) {
            return "";
        } else {
            return className.substring(0, lastIndexOfDot);
        }
    }

    /**
     * Register javascript library to future adding to response
     *
     * @param context        {@link FacesContext} for the current request
     * @param baseClass      Class, relative to which the resourcePath is specified
     * @param relativeJsPath Path to the javascript file
     */
    static void registerJavascriptLibrary(FacesContext context, Class baseClass, String relativeJsPath) {
        String jsFileUrl = internalURL(context, baseClass, relativeJsPath);
        registerJavascriptLibrary(context, jsFileUrl);
    }

    /**
     * Register javascript library to future adding to response
     *
     * @param context   {@link FacesContext} for the current request
     * @param jsFileUrl Url for the javascript file
     */
    static void registerJavascriptLibrary(FacesContext context, String jsFileUrl) {
        Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
        List<String> libraries = (List<String>) requestMap.get(HEADER_JS_LIBRARIES);
        if (libraries == null) {
            libraries = new ArrayList<String>();
            requestMap.put(HEADER_JS_LIBRARIES, libraries);
        }

        if (libraries.contains(jsFileUrl)) return;
        libraries.add(jsFileUrl);

    }

    public static void processHeadResources(FacesContext context) {
        Map<String, Object> requestMap = context.getExternalContext().getRequestMap();

        Class richfacesContextClass = null;
        try {
            richfacesContextClass = Class.forName("org.ajax4jsf.context.AjaxContext");
        } catch (ClassNotFoundException e) {
            // Just checking for class presence. It's normal that a class can be absent.
        }

        String ajax4jsfScriptParameter = (String) ReflectionUtil.getStaticFieldValue(richfacesContextClass, "SCRIPTS_PARAMETER");
        String ajax4jsfStylesParameter = (String) ReflectionUtil.getStaticFieldValue(richfacesContextClass, "STYLES_PARAMETER");
        String headEventsParameter = (String) ReflectionUtil.getStaticFieldValue(richfacesContextClass, "HEAD_EVENTS_PARAMETER");

        if (ajax4jsfStylesParameter != null) {
            Set<String> styles = (Set<String>) requestMap.get(ajax4jsfStylesParameter);
            String defaultCssUrl = ((HttpServletRequest) context.getExternalContext().getRequest()).getContextPath()
                    + ResourceFilter.INTERNAL_RESOURCE_PATH + "org/openfaces/renderkit/default" + "-" + getVersionString() + ".css";
            if (styles == null) {
                styles = new LinkedHashSet<String>();
            }
            styles.add(defaultCssUrl);
            requestMap.put(ajax4jsfStylesParameter, styles);
        }

        if (ajax4jsfScriptParameter != null) {
            Set<String> libraries = (Set<String>) requestMap.get(ajax4jsfScriptParameter);
            List<String> ourLibraries = (List<String>) requestMap.get(HEADER_JS_LIBRARIES);

            if (libraries == null) {
                libraries = new LinkedHashSet<String>();
            }

            if (ourLibraries != null) {
                libraries.addAll(ourLibraries);
            }

            requestMap.put(ajax4jsfScriptParameter, libraries);
        }

        if (headEventsParameter != null) {
            List<String> ourLibraries = (List<String>) requestMap.get(HEADER_JS_LIBRARIES);
            final Node[] headerResources = (Node[]) requestMap.get(headEventsParameter);

            if (headerResources != null && ourLibraries != null) {
                final Node[] ourHeaderNodes = prepareHeaderNodes(ourLibraries);
                final Node[] mergedNodes = mergeHeadResourceNodes(ourHeaderNodes, headerResources);

                requestMap.put(headEventsParameter, mergedNodes);
            }
        }
    }


    private static void mergeHeadResourceNode(List<Node> nodes, Set<String> renderedScripts, Node node) {
        boolean shouldAdd = true;

        String nodeName = node.getNodeName();
        if ("script".equals(nodeName) || "SCRIPT".equals(nodeName)) {
            if (node.getFirstChild() == null) {
                //no text content etc.

                NamedNodeMap attributes = node.getAttributes();
                if (attributes != null) {
                    Node item = attributes.getNamedItem("src");
                    if (item == null) {
                        attributes.getNamedItem("SRC");
                    }

                    if (item != null) {
                        String src = item.getNodeValue();
                        if (src != null) {
                            if (renderedScripts.contains(src)) {
                                shouldAdd = false;
                            } else {
                                renderedScripts.add(src);
                            }
                        }
                    }
                }
            }
        }

        if (shouldAdd) {
            nodes.add(node);
        }
    }

    private static Node[] mergeHeadResourceNodes(Node[] headerJsNodes, Node[] richFacesHeaderNodes) {
        List<Node> result = new ArrayList<Node>();

        Set<String> scripts = new HashSet<String>();

        for (Node node : richFacesHeaderNodes) {
            mergeHeadResourceNode(result, scripts, node);
        }

        for (Node node : headerJsNodes) {
            mergeHeadResourceNode(result, scripts, node);
        }

        return result.toArray(new Node[result.size()]);
    }

    private static Node[] prepareHeaderNodes(List<String> headerLibraries) {
        try {
            Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            Node node = document.createElement("head");
            document.appendChild(node);

            for (String headerLibrary : headerLibraries) {
                Element element = document.createElement("script");
                element.setAttribute("src", headerLibrary);
                element.setAttribute("type", "text/javascript");

                node.appendChild(element);
            }

            NodeList childNodes = node.getChildNodes();
            Node[] list = new Node[childNodes.getLength()];
            for (int i = 0; i < list.length; i++) {
                list[i] = childNodes.item(i);
            }

            return list;
        } catch (ParserConfigurationException e) {
            throw new FacesException(e.getLocalizedMessage(), e);
        }
    }

    public static boolean isHeaderIncludesRegistered(ServletRequest servletRequest) {
        if (AjaxUtil.isAjaxRequest(RequestFacade.getInstance(servletRequest))) return false;
        for (Iterator<String> iterator = Styles.getClassKeyIterator(); iterator.hasNext();) {
            String key = iterator.next();
            if (servletRequest.getAttribute(key) != null) {
                return true;
            }
        }

        return servletRequest.getAttribute(Rendering.ON_LOAD_SCRIPTS_KEY) != null ||
                servletRequest.getAttribute(HEADER_JS_LIBRARIES) != null ||
                servletRequest.getAttribute(Styles.DEFAULT_CSS_REQUESTED) != null;
    }

    /**
     * Render javascript file link, if not rendered early
     *
     * @param context {@link javax.faces.context.FacesContext} for the current request
     * @param jsFile  Javascript file to include
     * @throws IOException if an input/output error occurs
     */
    public static void renderJSLinkIfNeeded(FacesContext context, String jsFile) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        List<String> renderedJsLinks = getRenderedJsLinks(context);
        if (renderedJsLinks.contains(jsFile)) {
            return;
        }
        renderedJsLinks.add(jsFile);

        Boolean postponeJsLinkRendering = (Boolean) context.getExternalContext().getRequestMap().get(POSTPONE_JS_LINK_RENDERING);
        if (postponeJsLinkRendering != null && postponeJsLinkRendering)
            return;
        if (AjaxUtil.isAjaxRequest(context)) {
            registerJavascriptLibrary(context, jsFile);
        } else if (AjaxUtil.isAjax4jsfRequest()) {
            registerJavascriptLibrary(context, jsFile);
        } else {
            writer.startElement("script", null);
            writer.writeAttribute("src", jsFile, null);
            writer.writeAttribute("type", "text/javascript", null);
            // write white-space to avoid creating self-closing <script/> tags
            // under certain servers, which are not correctly interpreted by browsers (JSFC-2303)
            if (Environment.isExoPortal())
                writer.writeText(" ", null);
            writer.endElement("script");
        }
    }

    /**
     * Return list of already rendered javascript links
     *
     * @param context {@link FacesContext} for the current request
     * @return list of already rendered javascript links
     */
    public static List<String> getRenderedJsLinks(FacesContext context) {
        Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
        List<String> renderedJsLinks = (List<String>) requestMap.get(RENDERED_JS_LINKS);
        if (renderedJsLinks == null) {
            renderedJsLinks = new ArrayList<String>();
            requestMap.put(RENDERED_JS_LINKS, renderedJsLinks);
        }
        return renderedJsLinks;
    }

    public static void includeJQuery(FacesContext context) throws IOException {
        String jQueryIncludedKey = "org.openfaces.util.Rendering.JQUERY_INCLUDED";
        Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
        if (requestMap.containsKey(jQueryIncludedKey)) return;
        requestMap.put(jQueryIncludedKey, true);
        String jQueryMode = Rendering.getContextParam(context, PARAM_ORG_OPENFACES_JQUERY, "embedded");
        if (jQueryMode.equals("none")) {
            // the org.openfaces.jQuery=none parameter might be required to avoid conflicts when jQuery.js is
            // already added to a page by application developer or another library
            return;
        }
        if (jQueryMode.equals("embedded"))
            registerJavascriptLibrary(context, internalURL(context, "util/jquery-1.4.2.min.js"));
            /* below are the official jQuery CDNs as referenced here: http://docs.jquery.com/Downloading_jQuery */
        else if (jQueryMode.equals("jquery"))
            renderJSLinkIfNeeded(context, "http://code.jquery.com/jquery-1.4.2.min.js");
        else if (jQueryMode.equals("google"))
            renderJSLinkIfNeeded(context, "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
        else if (jQueryMode.equals("microsoft"))
            renderJSLinkIfNeeded(context, "http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js");
        else {
            if (!jQueryMode.startsWith("http"))
                throw new FacesException("Invalid value for the " + PARAM_ORG_OPENFACES_JQUERY + " context parameter: \"" + jQueryMode + "\" ; It should either be one of the predefined values: none, embedded, jquery, google, microsoft, or be a URL string starting with \"http\". ");
            renderJSLinkIfNeeded(context, jQueryMode);
        }

        String noConflictStr = Rendering.getContextParam(context, "org.openfaces.jQuery.noConflict");
        if (noConflictStr != null && !noConflictStr.equalsIgnoreCase("false")) {
            if (noConflictStr.equalsIgnoreCase("true"))
                Rendering.renderInitScript(context, new RawScript("jQuery.noConflict()"));
            else
                Rendering.renderInitScript(context, new RawScript("var " + noConflictStr + " = jQuery.noConflict();"));
        }
    }
}
TOP

Related Classes of org.openfaces.util.Resources

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.