Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6756801
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 26, 20262026-05-26T13:34:05+00:00 2026-05-26T13:34:05+00:00

Is anyone aware of a method to dynamically combine/minify all the h:outputStylesheet resources and

  • 0

Is anyone aware of a method to dynamically combine/minify all the h:outputStylesheet resources and then combine/minify all h:outputScript resources in the render phase? The comined/minified resource would probably need to be cached with a key based on the combined resource String or something to avoid excessive processing.

If this feature doesn’t exist I’d like to work on it. Does anyone have ideas on the best way to implement something like this. A Servlet filter would work I suppose but the filter would have to do more work than necessary — basically examining the whole rendered output and replacing matches. Implementing something in the render phase seems like it would work better as all of the static resources are available without having to parse the entire output.

Thanks for any suggestions!

Edit: To show that I’m not lazy and will really work on this with some guidance, here is a stub that captures Script Resources name/library and then removes them from the view. As you can see I have some questions about what to do next … should I make http requests and get the resources to combine, then combine them and save them to the resource cache?

package com.davemaple.jsf.listener;

import java.util.ArrayList;
import java.util.List;

import javax.faces.component.UIComponent;
import javax.faces.component.UIOutput;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.event.PreRenderViewEvent;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;

import org.apache.log4j.Logger;

/**
 * A Listener that combines CSS/Javascript Resources
 * 
 * @author David Maple<d@davemaple.com>
 *
 */
public class ResourceComboListener implements PhaseListener, SystemEventListener {

    private static final long serialVersionUID = -8430945481069344353L;
    private static final Logger LOGGER = Logger.getLogger(ResourceComboListener.class);

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }

    /*
     * (non-Javadoc)
     * @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
     */
    public void afterPhase(PhaseEvent event) {
        FacesContext.getCurrentInstance().getViewRoot().subscribeToViewEvent(PreRenderViewEvent.class, this);
    }

    /*
     * (non-Javadoc)
     * @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
     */
    public void beforePhase(PhaseEvent event) {
        //nothing here
    }

    /*
     * (non-Javadoc)
     * @see javax.faces.event.SystemEventListener#isListenerForSource(java.lang.Object)
     */
    public boolean isListenerForSource(Object source) {
        return (source instanceof UIViewRoot);
    }

    /*
     * (non-Javadoc)
     * @see javax.faces.event.SystemEventListener#processEvent(javax.faces.event.SystemEvent)
     */
    public void processEvent(SystemEvent event) throws AbortProcessingException {
        FacesContext context = FacesContext.getCurrentInstance();
        UIViewRoot viewRoot = context.getViewRoot();
        List<UIComponent> scriptsToRemove = new ArrayList<UIComponent>();

        if (!context.isPostback()) {

            for (UIComponent component : viewRoot.getComponentResources(context, "head")) {
                if (component.getClass().equals(UIOutput.class)) {
                    UIOutput uiOutput = (UIOutput) component;

                    if (uiOutput.getRendererType().equals("javax.faces.resource.Script")) {
                        String library = uiOutput.getAttributes().get("library").toString();
                        String name = uiOutput.getAttributes().get("name").toString();

                        // make https requests to get the resources?
                        // combine then and save to resource cache?
                        // insert new UIOutput script?

                        scriptsToRemove.add(component);
                    }


                }
            }

            for (UIComponent component : scriptsToRemove) {
                viewRoot.getComponentResources(context, "head").remove(component);
            }

        }
    }

}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-26T13:34:06+00:00Added an answer on May 26, 2026 at 1:34 pm

    This answer doesn’t cover minifying and compression. Minifying of individual CSS/JS resources is better to be delegated to build scripts like YUI Compressor Ant task. Manually doing it on every request is too expensive. Compression (I assume you mean GZIP?) is better to be delegated to the servlet container you’re using. Manually doing it is overcomplicated. On Tomcat for example it’s a matter of adding a compression="on" attribute to the <Connector> element in /conf/server.xml.


    The SystemEventListener is already a good first step (apart from some PhaseListener unnecessity). Next, you’d need to implement a custom ResourceHandler and Resource. That part is not exactly trivial. You’d need to reinvent pretty a lot if you want to be JSF implementation independent.

    First, in your SystemEventListener, you’d like to create new UIOutput component representing the combined resource so that you can add it using UIViewRoot#addComponentResource(). You need to set its library attribute to something unique which is understood by your custom resource handler. You need to store the combined resources in an application wide variable along an unique name based on the combination of the resources (a MD5 hash maybe?) and then set this key as name attribute of the component. Storing as an application wide variable has a caching advantage for both the server and the client.

    Something like this:

    String combinedResourceName = CombinedResourceInfo.createAndPutInCacheIfAbsent(resourceNames);
    UIOutput component = new UIOutput();
    component.setRendererType(rendererType);
    component.getAttributes().put(ATTRIBUTE_RESOURCE_LIBRARY, CombinedResourceHandler.RESOURCE_LIBRARY);
    component.getAttributes().put(ATTRIBUTE_RESOURCE_NAME, combinedResourceName + extension);
    context.getViewRoot().addComponentResource(context, component, TARGET_HEAD);
    

    Then, in your custom ResourceHandler implementation, you’d need to implement the createResource() method accordingly to create a custom Resource implementation whenever the library matches the desired value:

    @Override
    public Resource createResource(String resourceName, String libraryName) {
        if (RESOURCE_LIBRARY.equals(libraryName)) {
            return new CombinedResource(resourceName);
        } else {
            return super.createResource(resourceName, libraryName);
        }
    }
    

    The constructor of the custom Resource implementation should grab the combined resource info based on the name:

    public CombinedResource(String name) {
        setResourceName(name);
        setLibraryName(CombinedResourceHandler.RESOURCE_LIBRARY);
        setContentType(FacesContext.getCurrentInstance().getExternalContext().getMimeType(name));
        this.info = CombinedResourceInfo.getFromCache(name.split("\\.", 2)[0]);
    }
    

    This custom Resource implementation must provide a proper getRequestPath() method returning an URI which will then be included in the rendered <script> or <link> element:

    @Override
    public String getRequestPath() {
        FacesContext context = FacesContext.getCurrentInstance();
        String path = ResourceHandler.RESOURCE_IDENTIFIER + "/" + getResourceName();
        String mapping = getFacesMapping();
        path = isPrefixMapping(mapping) ? (mapping + path) : (path + mapping);
        return context.getExternalContext().getRequestContextPath()
            + path + "?ln=" + CombinedResourceHandler.RESOURCE_LIBRARY;
    }
    

    Now, the HTML rendering part should be fine. It’ll look something like this:

    <link type="text/css" rel="stylesheet" href="/playground/javax.faces.resource/dd08b105bf94e3a2b6dbbdd3ac7fc3f5.css.xhtml?ln=combined.resource" />
    <script type="text/javascript" src="/playground/javax.faces.resource/2886165007ccd8fb65771b75d865f720.js.xhtml?ln=combined.resource"></script>
    

    Next, you have to intercept on combined resource requests made by the browser. That’s the hardest part. First, in your custom ResourceHandler implementation, you need to implement the handleResourceRequest() method accordingly:

    @Override
    public void handleResourceRequest(FacesContext context) throws IOException {
        if (RESOURCE_LIBRARY.equals(context.getExternalContext().getRequestParameterMap().get("ln"))) {
            streamResource(context, new CombinedResource(getCombinedResourceName(context)));
        } else {
            super.handleResourceRequest(context);
        }
    }
    

    Then you have to do the whole lot of work of implementing the other methods of the custom Resource implementation accordingly such as getResponseHeaders() which should return proper caching headers, getInputStream() which should return the InputStreams of the combined resources in a single InputStream and userAgentNeedsUpdate() which should respond properly on caching related requests.

    @Override
    public Map<String, String> getResponseHeaders() {
        Map<String, String> responseHeaders = new HashMap<String, String>(3);
        SimpleDateFormat sdf = new SimpleDateFormat(PATTERN_RFC1123_DATE, Locale.US);
        sdf.setTimeZone(TIMEZONE_GMT);
        responseHeaders.put(HEADER_LAST_MODIFIED, sdf.format(new Date(info.getLastModified())));
        responseHeaders.put(HEADER_EXPIRES, sdf.format(new Date(System.currentTimeMillis() + info.getMaxAge())));
        responseHeaders.put(HEADER_ETAG, String.format(FORMAT_ETAG, info.getContentLength(), info.getLastModified()));
        return responseHeaders;
    }
    
    @Override
    public InputStream getInputStream() throws IOException {
        return new CombinedResourceInputStream(info.getResources());
    }
    
    @Override
    public boolean userAgentNeedsUpdate(FacesContext context) {
        String ifModifiedSince = context.getExternalContext().getRequestHeaderMap().get(HEADER_IF_MODIFIED_SINCE);
    
        if (ifModifiedSince != null) {
            SimpleDateFormat sdf = new SimpleDateFormat(PATTERN_RFC1123_DATE, Locale.US);
    
            try {
                info.reload();
                return info.getLastModified() > sdf.parse(ifModifiedSince).getTime();
            } catch (ParseException ignore) {
                return true;
            }
        }
    
        return true;
    }
    

    I’ve here a complete working proof of concept, but it’s too much of code to post as a SO answer. The above was just a partial to help you in the right direction. I assume that the missing method/variable/constant declarations are self-explaining enough to write your own, otherwise let me know.


    Update: as per the comments, here’s how you can collect resources in CombinedResourceInfo:

    private synchronized void loadResources(boolean forceReload) {
        if (!forceReload && resources != null) {
            return;
        }
    
        FacesContext context = FacesContext.getCurrentInstance();
        ResourceHandler handler = context.getApplication().getResourceHandler();
        resources = new LinkedHashSet<Resource>();
        contentLength = 0;
        lastModified = 0;
    
        for (Entry<String, Set<String>> entry : resourceNames.entrySet()) {
            String libraryName = entry.getKey();
    
            for (String resourceName : entry.getValue()) {
                Resource resource = handler.createResource(resourceName, libraryName);
                resources.add(resource);
    
                try {
                    URLConnection connection = resource.getURL().openConnection();
                    contentLength += connection.getContentLength();
                    long lastModified = connection.getLastModified();
    
                    if (lastModified > this.lastModified) {
                        this.lastModified = lastModified;
                    }
                } catch (IOException ignore) {
                    // Can't and shouldn't handle it here anyway.
                }
            }
        }
    }
    

    (the above method is called by reload() method and by getters depending on one of the properties which are to be set)

    And here’s how the CombinedResourceInputStream look like:

    final class CombinedResourceInputStream extends InputStream {
    
        private List<InputStream> streams;
        private Iterator<InputStream> streamIterator;
        private InputStream currentStream;
    
        public CombinedResourceInputStream(Set<Resource> resources) throws IOException {
            streams = new ArrayList<InputStream>();
    
            for (Resource resource : resources) {
                streams.add(resource.getInputStream());
            }
    
            streamIterator = streams.iterator();
            streamIterator.hasNext(); // We assume it to be always true; CombinedResourceInfo won't be created anyway if it's empty.
            currentStream = streamIterator.next();
        }
    
        @Override
        public int read() throws IOException {
            int read = -1;
    
            while ((read = currentStream.read()) == -1) {
                if (streamIterator.hasNext()) {
                    currentStream = streamIterator.next();
                } else {
                    break;
                }
            }
    
            return read;
        }
    
        @Override
        public void close() throws IOException {
            IOException caught = null;
    
            for (InputStream stream : streams) {
                try {
                    stream.close();
                } catch (IOException e) {
                    if (caught == null) {
                        caught = e; // Don't throw it yet. We have to continue closing all other streams.
                    }
                }
            }
    
            if (caught != null) {
                throw caught;
            }
        }
    
    }
    

    Update 2: a concrete and reuseable solution is available in OmniFaces. See also CombinedResourceHandler showcase page and API documentation for more detail.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Is anyone aware of any methodology to try and determine the method and instance
Is anyone aware of a method to export specific fields from a database with
Anyone aware of a method/class/library that will allow me to easily reproduce the results
Is anyone aware of any method (or external plugin) that would allow for nested
Are anyone aware of any method to achieve indentation in the ASPXGridView (we are
Is anyone aware of a script/class (preferably in PHP) that would parse a given
Is anyone aware of a language feature or technique in C++ to prevent a
Is anyone aware of a reasonably well documented example of simulated annealing in Visual
Is anyone aware of any text editors with Visual Studio editor functionality? Specifically, I'm
Is anyone aware of general UI design guidelines for increasing ad revenue from web

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.