How to use JSF versioning for resources in jar

前端 未结 3 1016
别那么骄傲
别那么骄傲 2020-12-01 13:20

PF 3.5.10, Mojarra 2.1.21, omnifaces 1.5

I have a JSF library (with css files only). This library is in a .jar file. The css will be included in xhtml with &l

相关标签:
3条回答
  • 2020-12-01 13:24

    You can also use your project version and append it as a version number for your resource files. This can be done using the maven-war-plugin. The maven-war-plugin will look at your pages during the build time and replace the defined properties.

    The following example shows you how to configure the maven-war-plugin to filter your webapp resources in order to inject the custom property asset.version:

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" ...>
      ...
    
      <properties>
        <asset.version>${project.version}</asset.version>    
      </properties>
    
      ...
    
      <build>
        <plugins>
          ...
    
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.3</version>
            <configuration>
    
              <nonFilteredFileExtensions>
                <nonFilteredFileExtension>gif</nonFilteredFileExtension>
                <nonFilteredFileExtension>ico</nonFilteredFileExtension>
                <nonFilteredFileExtension>jpg</nonFilteredFileExtension>
                <nonFilteredFileExtension>png</nonFilteredFileExtension>
                <nonFilteredFileExtension>pdf</nonFilteredFileExtension>
              </nonFilteredFileExtensions>
    
              <failOnMissingWebXml>false</failOnMissingWebXml>
    
              <webResources> 
                <webResource>
                  <directory>${basedir}/src/main/webapp</directory> 
                  <filtering>true</filtering> 
                </webResource>
              </webResources> 
    
            </configuration>
          </plugin>
    
          ...
        </plugins>
      </build>
    
    </project>
    

    The asset.version property can then be used in your JSF file.

    Here is an example tested with JSF 2.2:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html>
    <html ...
          xmlns:jsf="http://xmlns.jcp.org/jsf">
    
    ...
    <script jsf:name="js/libs/pure/pure-min.css?v=${project.version}" />
    

    The result (in my case) will be the following:

    <script type="text/javascript" src="/context-path/javax.faces.resource/js/libs/pure/pure-min.css.xhtml?v=1.0.15-SNAPSHOT"></script>
    
    0 讨论(0)
  • 2020-12-01 13:40

    @Balusc response said "well, not a bug, but oversight and spec fail". It seems like css resources deployed in libraries cannot be versioned with mojarra 2.2.14. Is it right? I tried to implement your solution with a custom ResourceHandler, but resource returned by getWrapped().createResource(resourceName, libraryName) always returns null. It seems like createResource() try to find the library's resources (like css/layout.css) with path /META-INF/resources/ but it lacks the version.

    To workaround the problem i have overrided createResource method on a custom ResourceHandler which extends Omnifaces DefaultResourceHandler to add version prefix to the resourceName

    @Override
    public Resource createResource(String resourceName, String libraryName) {
        if (libraryName != null && libraryName.equals(LIBRARY_NAME)) {
            if (!resourceName.startsWith(version)) {
                resourceName = version + "/"+resourceName;
            }
        }
        return super.createResource(resourceName, libraryName);
    }
    

    With this workaround the generated link looks like

    <link type="text/css" rel="stylesheet" href="/javax.faces.resource/1_0_3/css/layout.css?ln=common&amp;v=1_0_3"/>
    

    for the outputStylesheet declaration

    <h:outputStylesheet library="common" name="css/layout.css" />
    

    I'm not sure this is the best workaround.

    0 讨论(0)
  • 2020-12-01 13:43

    That's unfortunately not possible. Library versioning is not supported for resources in JAR.

    You've basically 2 options:

    1. Do it the easy and ugly way, include server's startup time as query string. Given that you're using OmniFaces, you could use its builtin #{startup} managed bean referring a java.util.Date instance in application scope:

      <h:outputStylesheet ... name="some.css?#{startup.time}" />
      <h:outputScript ... name="some.js?#{startup.time}" />
      

      Or perhaps you've the version already as some application variable.

      <h:outputStylesheet ... name="some.css?v=#{app.version}" />
      <h:outputScript ... name="some.js?v=#{app.version}" />
      

      Update: Notwithstanding, this doesn't work for <h:outputStylesheet>. See also: https://github.com/javaserverfaces/mojarra/issues/3945 or https://github.com/javaee/javaserverfaces-spec/issues/1395

      It works for <h:outputScript> though, which had a very simliar bug report which was implemented pretty soon https://github.com/javaserverfaces/mojarra/issues/1216

    2. Do the same as PrimeFaces, create a custom ResourceHandler.

      public class MyVersionResourceHandler extends ResourceHandlerWrapper {
      
          private ResourceHandler wrapped;
      
          public MyVersionResourceHandler(ResourceHandler wrapped) {
              this.wrapped = wrapped;
          }
      
          @Override
          public Resource createResource(String resourceName) {
              return createResource(resourceName, null, null);
          }
      
          @Override
          public Resource createResource(String resourceName, String libraryName) {
              return createResource(resourceName, libraryName, null);
          }
      
          @Override
          public Resource createResource(String resourceName, String libraryName, String contentType) {
              final Resource resource = super.createResource(resourceName, libraryName, contentType);
      
              if (resource == null) {
                  return null;
              }
      
              return new ResourceWrapper() {
      
                  @Override
                  public String getRequestPath() {
                      return super.getRequestPath() + "&v=1.0";
                  }
      
                  @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
                  public String getResourceName() {
                      return resource.getResourceName();
                  }
      
                  @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
                  public String getLibraryName() {
                      return resource.getLibraryName();
                  }
      
                  @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
                  public String getContentType() {
                      return resource.getContentType();
                  }
      
                  @Override
                  public Resource getWrapped() {
                      return resource;
                  }
              };
          }
      
          @Override
          public ResourceHandler getWrapped() {
              return wrapped;
          }
      
      }
      

      Or if you happen to already use OmniFaces, it could be done simpler:

      public class YourVersionResourceHandler extends DefaultResourceHandler {
      
          public YourVersionResourceHandler(ResourceHandler wrapped) {
              super(wrapped);
          }
      
          @Override
          public Resource decorateResource(Resource resource) {
              if (resource == null || !"mylib".equals(resource.getLibraryName())) {
                  return resource;
              }
      
              return new RemappedResource(resource, resource.getRequestPath() + "&v=1.0");
          }
      
      }
      

      Either way, to get it to run, register it as <resource-handler> in /META-INF/faces-config.xml of the JAR.

      <application>
          <resource-handler>com.example.MyVersionResourceHandler</resource-handler>
      </application>
      
    0 讨论(0)
提交回复
热议问题