Skip navigation
2012

Michal Petrov's Blog

November 2012 Previous month Next month

In RichFaces 4.X custom skins do not work with resource optimization resulting in RF components not being properly styled. This is because your application expects a resource file named packed.css that contains styles for these components. This file is bundled with the predefined skins but not with your custom skin.

 

However you can generate that file with the resource plugin.

Get the URL

First make you sure you have resource optimization enabled in your web.xml:

 

<context-param>
     <param-name>org.richfaces.resourceOptimization.enabled</param-name>
     <param-value>true</param-value>
</context-param>

 

Your application is expecting to find the file on a specific URL, you need to find it and then generate the file on that location. The link to the missing file will look similar to this:

{code}<link type="text/css" rel="stylesheet" href="/richfaces-photoalbum/org.richfaces.resources/javax.faces.resource/org.richfaces.staticResource/4.2.3.Final/PackedCompressed/photoalbum/packed/packed.css">{code}

The important part is org.richfaces.staticResource/4.2.3.Final/PackedCompressed, you will need this to set up the plugin.

Set up the plugin

Create a richfaces.version property in your pom.xml if you haven’t already (this makes it easier when you upgrade to a new version),

 

<properties>
     <richfaces.version>4.2.3.Final</richfaces.version>
       …
</properties>

 

and put this inside the <build> element:


<plugin>
     <groupId>org.richfaces.cdk</groupId>
     <artifactId>maven-richfaces-resources-plugin</artifactId>
     <version>${richfaces.version}</version>
     <configuration>
          <skins>
               <!-- the name of your skin -->
               <skin>photoalbum</skin>
          </skins>
          <excludedFiles>
               <exclude>^\Qorg.richfaces.renderkit.html.images.\E.*</exclude>
               <exclude>^\Qorg.richfaces.renderkit.html.iconimages.\E.*</exclude>
          </excludedFiles>
          <includedContentTypes>
               <include>text/css</include>
               <include>image/.+</include>
          </includedContentTypes>
          <fileNameMappings>
                <property>
                     <name>^.*showcase.*/([^/]+\.css)$</name>
                     <value>org.richfaces.showcase.css/$1</value>
                </property>
                <property>
                     <name>^.+/([^/]+\.(png|gif|jpg))$</name>
                     <value>org.richfaces.images/$1</value>
                </property>
                <property>
                     <name>^.+/([^/]+\.css)$</name>
                     <value>org.richfaces.css/$1</value>
                </property>
          </fileNameMappings>
     </configuration>
     <executions>
          <execution>
               <id>process-resources</id>
               <goals>
                    <goal>process</goal>
               </goals>
               <configuration>    
                    <!-- the actual name of this file is not important but it should be inside the META-INF folder -->
                    <staticResourceMappingFile>${project.build.outputDirectory}/META-INF/richfaces/photoalbum-packedcompressed-resource-mappings.properties</staticResourceMappingFile>
                    
                    <!-- the URL part goes after /META-INF/resources/ -->
                    <resourcesOutputDir>${project.build.outputDirectory}/META-INF/resources/org.richfaces.staticResource/${richfaces.version}/PackedCompressed/</resourcesOutputDir>
                    
                    <!-- replace completely with the URL part -->
                    <staticResourcePrefix>org.richfaces.staticResource/${richfaces.version}/PackedCompressed</staticResourcePrefix>
                        
                    <pack>true</pack>                            
                    <compress>true</compress>

                    <excludedFiles>
                         <exclude>^javax.faces</exclude>
                         <exclude>^\Qorg.richfaces.renderkit.html.images.\E.*</exclude>
                         <exclude>^\Qorg.richfaces.renderkit.html.iconimages.\E.*</exclude>
                         <exclude>^jquery\.js$</exclude>
                    </excludedFiles>

               </configuration>
          </execution>

          <!-- If you are in Development stage the compression is ignored, include this execution to generate uncompressed files --> 

          <execution>
               <id>process-resources-packed</id>
               <goals>
                    <goal>process</goal>
               </goals>
               <configuration>
                    <staticResourceMappingFile>${project.build.outputDirectory}/META-INF/richfaces/photoalbum-packed-resource-mappings.properties</staticResourceMappingFile>
                            
                    <!-- the directory is named “Packed”, not “PackedCompressed” as in the previous execution -->
                    <resourcesOutputDir>${project.build.outputDirectory}/META-INF/resources/org.richfaces.staticResource/${richfaces.version}/Packed/</resourcesOutputDir>
                    <staticResourcePrefix>org.richfaces.staticResource/${richfaces.version}/Packed</staticResourcePrefix>
                            
                    <pack>true</pack>
                    <compress>false</compress> <!-- do not compress -->

                    <excludedFiles>
                         <exclude>^javax.faces</exclude>
                         <exclude>^\Qorg.richfaces.renderkit.html.images.\E.*</exclude>
                         <exclude>^\Qorg.richfaces.renderkit.html.iconimages.\E.*</exclude>
                         <exclude>^jquery\.js$</exclude>
                    </excludedFiles>
               </configuration>
          </execution>
     </executions>
</plugin>

Excuse the weird highlighting.

The important tags are resourcesOutputDir and staticResourcePrefix. Change them according to the URL part for the missing file (and replace the RichFaces version with ${richfaces.version}).

 

Now you can run the maven build and all necessary files will be generated. Enjoy your custom skin.

Notes

Plugin execution not covered by lifecycle configuration: org.richfaces.cdk:maven-richfaces-resources-plugin:4.2.3.Final:process (execution: process-resources-packed, phase: process-classes)


Your IDE may complain complain like (JBDS does) this but you can ignore that.

 

Troubleshooting

Skin not found

 

WARNING: Error creating resource org.richfaces.renderkit.html.BaseGradient

javax.faces.FacesException

          at org.richfaces.application.DependencyInjectionServiceImpl.inject(DependencyInjectionServiceImpl.java:361)

          at org.richfaces.resource.ResourceFactoryImpl.injectProperties(ResourceFactoryImpl.java:197)

          at org.richfaces.resource.ResourceFactoryImpl.createHandlerDependentResource(ResourceFactoryImpl.java:320)

          at org.richfaces.resource.ResourceFactoryImpl.createDynamicResource(ResourceFactoryImpl.java:468)

          at org.richfaces.resource.ResourceFactoryImpl.createResource(ResourceFactoryImpl.java:412)

          at org.richfaces.cdk.resource.handler.impl.DynamicResourceHandler.createResource(DynamicResourceHandler.java:85)

          at org.richfaces.cdk.resource.handler.impl.AbstractResourceHandler.createResource(AbstractResourceHandler.java:42)

          at org.richfaces.cdk.task.ResourceTaskFactoryImpl$ResourcesRendererCallable.createResource(ResourceTaskFactoryImpl.java:71)

          at org.richfaces.cdk.task.ResourceTaskFactoryImpl$ResourcesRendererCallable.renderResource(ResourceTaskFactoryImpl.java:83)

          at org.richfaces.cdk.task.ResourceTaskFactoryImpl$ResourcesRendererCallable.call(ResourceTaskFactoryImpl.java:155)

          at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)

          at java.util.concurrent.FutureTask.run(FutureTask.java:166)

          at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)

          at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)

          at java.util.concurrent.FutureTask.run(FutureTask.java:166)

          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)

          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)

          at java.lang.Thread.run(Thread.java:722)

Caused by: java.lang.reflect.InvocationTargetException

          at sun.reflect.GeneratedMethodAccessor23.invoke(Unknown Source)

          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

          at java.lang.reflect.Method.invoke(Method.java:601)

          at org.richfaces.application.DependencyInjectionServiceImpl.invokeMethod(DependencyInjectionServiceImpl.java:187)

          at org.richfaces.application.DependencyInjectionServiceImpl.inject(DependencyInjectionServiceImpl.java:354)

          ... 17 more

Caused by: org.richfaces.skin.SkinNotFoundException: Skin with name photoalbum not found

          at org.richfaces.skin.AbstractSkinFactory.getSkin(AbstractSkinFactory.java:161)

          at org.richfaces.cdk.skin.SkinFactoryImpl.getSkin(SkinFactoryImpl.java:49)

          at org.richfaces.renderkit.html.BaseGradient.initialize(BaseGradient.java:124)

          ... 22 more

Caused by: java.util.concurrent.ExecutionException: org.richfaces.skin.SkinNotFoundException: Skin with name photoalbum not found

          at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:252)

          at java.util.concurrent.FutureTask.get(FutureTask.java:111)

          at org.richfaces.skin.AbstractSkinFactory.getSkin(AbstractSkinFactory.java:157)

          ... 24 more

Caused by: org.richfaces.skin.SkinNotFoundException: Skin with name photoalbum not found

          at org.richfaces.skin.AbstractSkinFactory.loadProperties(AbstractSkinFactory.java:133)

          at org.richfaces.skin.AbstractSkinFactory.buildSkin(AbstractSkinFactory.java:107)

          at org.richfaces.skin.AbstractSkinFactory$SkinBuilder.call(AbstractSkinFactory.java:56)

          at org.richfaces.skin.AbstractSkinFactory$SkinBuilder.call(AbstractSkinFactory.java:47)

          at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)

          at java.util.concurrent.FutureTask.run(FutureTask.java:166)

          at org.richfaces.skin.AbstractSkinFactory.getSkin(AbstractSkinFactory.java:156)

          at org.richfaces.cdk.skin.SkinFactoryImpl.getSkin(SkinFactoryImpl.java:49)

          at org.richfaces.resource.CompiledCSSResource.getSkinHashCode(CompiledCSSResource.java:142)

          at org.richfaces.resource.CompiledCSSResource.writeState(CompiledCSSResource.java:217)

          at org.richfaces.util.Util.saveResourceState(Util.java:468)

          at org.richfaces.cdk.resource.handler.impl.DynamicResourceHandler.createResource(DynamicResourceHandler.java:89)

          ... 12 more

If you encounter this error during the maven build (the actual stacktrace will be far longer) your custom skin is missing from the classpath. To fix it add the directory containing the skin as a resource to pom.xml:

 

<build>
     <resources>
          <resource>
               <directory>path/to/your/skin</directory>
          </resource>
            …
     </resources>
        …
</build>