How to use JSF versioning for resources in jar - jsf-2

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
<h:outputStylesheet library="mylib" name="css/mycss.css">.
In html it is rendered to the following: localhost:8080/cms/javax.faces.resource/css/mycss.css.jsf?ln=mylib
CSS file of primefaces is rendered to:
localhost:8080/cms/javax.faces.resource/primefaces.js.jsf?ln=primefaces&v=3.5.10
Notice the library version (&3.5.10) at the end. How can I do the same thing ? Should I write version in Manifest.mf. Or how can I use jsf-versioning in jar file?

That's unfortunately not possible. Library versioning is not supported for resources in JAR.
You've basically 2 options:
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
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>

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>

#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&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.

Related

How to integrate swaggerUI with spring secure Rest services?

I have my spring project war which contains Secure REST services.I need to integrate these Rest Services with swagger UI but everytime I am getting an exception like:-"HTTP-401 Full Authenticatuion required to access the resource" for my below snippet code:
This is the configuration class which load REst APIS of my project war file
#Configuration
#EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurerAdapter {
#Bean
public Docket petApi() {
This is docket class which creates swagger documentation.
return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build()
.pathMapping("/").directModelSubstitute(LocalDate.class, String.class).genericModelSubstitutes(ResponseEntity.class);
}
}
This is the controller class which has customized method getdocumentation method which will internally invoke the spring controllers and get the documentation provided I am using springfox-swagger-ui 2.0 maven dependency.
#Controller
public class Swagger2Controller {
public static final String DEFAULT_URL = "/v2/api-docs";
#Value("${springfox.documentation.swagger.v2.host:DEFAULT}")
private String hostNameOverride;
#Autowired
private DocumentationCache documentationCache;
#Autowired
private ServiceModelToSwagger2Mapper mapper;
#Autowired
private JsonSerializer jsonSerializer;
#RequestMapping(value = { "/Vijay" }, method = { org.springframework.web.bind.annotation.RequestMethod.GET })
#ResponseBody
public ResponseEntity<Json> getDocumentation(#RequestParam(value = "group", required = false) String swaggerGroup) {
String groupName = Optional.fromNullable(swaggerGroup).or("default");
Documentation documentation = this.documentationCache.documentationByGroup(groupName);
if (documentation == null) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
Swagger swagger = this.mapper.mapDocumentation(documentation);
swagger.host(hostName());
return new ResponseEntity(this.jsonSerializer.toJson(swagger), HttpStatus.OK);
}
private String hostName() {
if ("DEFAULT".equals(this.hostNameOverride)) {
URI uri = ControllerLinkBuilder.linkTo(Swagger2Controller.class).toUri();
String host = uri.getHost();
int port = uri.getPort();
if (port > -1) {
return String.format("%s:%d", new Object[] { host, Integer.valueOf(port) });
}
return host;
}
return this.hostNameOverride;
}
}
Any Help or suggestion will be highly appreciated. provided I have already written security as non in context.xml file of respective spring project like
<mvc:default-servlet-handler />
<mvc:resources mapping="/webjars/*" location="classpath:/META-INF/resources/webjars" />
<mvc:resources mapping="/swagger-resources/*" location="classpath:/META-INF/resources/" />
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
<bean class="com.swagger.config.SwaggerConfig" />
<bean class="com.swagger.controller.Swagger2Controller" />
But still getting exception as mentioned above

There is no Action mapped for namespace /controller and action name

I am trying to learn Struts2, I have used a view page that hits action , the action class is using a bean where getter setter methods are written and the action is also using a dao where the connection is written.I want to mention that I am using jboss v5.0 and eclipse, I have added all the jar files.
Now , when I am trying to run this application the welcome jsp page is hitting properly then on clicking submit button the below error is showing:
There is no Action mapped for namespace /controller and action name
I am placing my code and directory structure. I have tried the using namespace="/"
<result name="SUCCESS">/success.jsp</result>, still its is not working
passing
+JAX-WS Web Services
+Deployment Descriptor:Passing
-Java Resources
-src
-controller
-TestAction.java
-TestAction
-execute(HttpServletRequest request , HttpServletResponse response) : String
-model
-TestBean.java
-TestBean
-age
-ocation
-name
-getAge() :String
-getName() :String
-getLocation() :String
-setAge(String) : void
-setName(String) : void
-getlocation(String) : void
-UserDao.java
- UserDao
-Logincheck() :Connection
registration.jsp
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>Passing</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>registration.jsp</welcome-file>
</welcome-file-list>
</web-app>
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="default" extends="sturts-default">
<action name="TestAction" class="controller.TestAction">
<result name="SUCCESS">/success.jsp</result>
</action>
</package>
</struts>
success.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<center> Welcome, Data successfully inserted</center>
</body>
</html>
registration.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%# taglib uri="/struts-tags" prefix="s"/%>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<s:form action="TestAction" method="post" >
<s:textfield name="Name" label="Name"/>
<s:textfield name="Age" label="Age"/>
<s:textfield name="Location" label="Location"/>
<s:submit label="Submit"></s:submit>
</s:form>
</body>
</html>
TestAction.java
package controller;
import java.sql.Connection;
import java.sql.PreparedStatement;
import com.opensymphony.xwork2.ActionSupport;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.TestBean;
import model.UserDao;
import org.apache.struts2.ServletActionContext;
public class TestAction extends ActionSupport{
public String execute(HttpServletRequest request , HttpServletResponse response) throws Exception
{
String Name = request.getParameter("Name");
String Age = request.getParameter("Age");
String Location = request.getParameter("Location");
TestBean bean = new TestBean();
bean.setName(Name);
bean.setAge(Age);
bean.setLocation(Location);
UserDao obj = new UserDao();
Connection x= obj.Logincheck();
if(x!=null)
{
PreparedStatement ps= x.prepareStatement("insert into Registration values(?,?,?)");
ps.setString(1, bean.getName());
ps.setString(2, bean.getAge());
ps.setString(3, bean.getLocation());
int i = ps.executeUpdate();
System.out.println("The value of i =" +i);
if(i>0)
{
return SUCCESS;
}
}
return null;
}
}
TestBean.java
package model;
public class TestBean {
String name;
String age;
String location;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
UserDao.java
package model;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class UserDao {
public Connection Logincheck()
{
Connection con=null;
try
{
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
con= DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:XE", "username", "password");
if(con!=null)
{
return con;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
that's all.
This error
There is no Action mapped for namespace /controller and action name
generally means Struts can't find the action specified in a namespace specified (/controller in this case). BTW in your case you've not specified /controller anywhere and the action name is missing in the error message, so this error could be probably generated by the bunch of other errors you have in your action / JSP / configuration.
you also have two typos, preventing anything to work:
sturts-default instead of struts-default:
<package name="default" extends="struts-default">
"SUCCESS" instead of "success", that is the result mapped to the constant SUCCESS that you are returning from the Action method.
<result name="success">/success.jsp</result>
If using Struts version newer than or equals to 2.1.3, you need the new filter, StrutsPrepareAndExecuteFilter instead of the deprecated FilterDispatcher;
The action method must be a public String something() with no parameters. This:
public String execute(HttpServletRequest request , HttpServletResponse response) throws Exception
is simply wrong, and should be:
public String execute(){}
Here
String Name = request.getParameter("Name");
String Age = request.getParameter("Age");
String Location = request.getParameter("Location");
TestBean bean = new TestBean();
bean.setName(Name);
bean.setAge(Age);
bean.setLocation(Location);
you are reinventing the wheel really badly. Attributes must be private, at class level, with getters and setters, and they'll be populated automatically, with no need to access the request. In your case:
private TestBean bean;
/* GETTER AND SETTER */
public String execute(){
System.out.println(bean.getName());
// ...
}
Unrelated, but Java naming conventions use lower-case names for local variables and instance properties.
In JSP page, you need to access the getter with a starting lowercase character:
<s:textfield name="Name" label="Name"/>
must be
<s:textfield name="name" label="Name"/>
and so the other fields. Also if you point to an object like TestBean, you need to do like this:
<s:textfield name="bean.name" label="Name"/>
This are the main problems... BTW consider start coding after having read a book, or some good tutorial. Starting in the dark like this is not the right way, IMHO.
Following are points which you should notice,
If you are using TestBean class as data carrier, you have to implement ModelDriven Interface.
TestAction.java should present in "Controller" package.
If you want HttpServletRequest and HttpServletResponse in your execute() method, then the simplest way you can get that is to implement ServletRequestAware and ServletResponseAware interfaces and implement respective methods.
And most important if your success.jsp is in Web Content folder, then you dont need to specify
<result name="SUCCESS">/success.jsp</result>
Just make it like
<result name="SUCCESS">success.jsp</result>
And if you have any folder suppose, "Folder1" in Web Content, Then specify like
<result name="SUCCESS">Folder1/success.jsp</result>

Using #Interceptor in #ManagedBean

Interception with CDI works perfectly in #Named , but doesn't in #ManagedBean:
Logable.java
#InterceptorBinding
#Retention(RUNTIME)
#Target({TYPE, METHOD})
public #interface Logable {
}
LoggingInterceptor.java
#Logable
#Interceptor
public class LoggingInterceptor {
#AroundInvoke
public Object log(InvocationContext ctx) throws Exception {
//log smth. with ctx.
}
}
WorkingBean.java
#Named
#Logable
public class WorkingBean implements Serializable {
//works : methods will be logged
}
beans.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>LoggingInterceptor</class>
</interceptors>
</beans>
ViewScopedBean.java
#Logable
#ManagedBean
public class ViewScopedBean implements Serializable {
//doesn't work
}
I'm aware, that this kind of Interceptor is meant to work with WebBeans (and EJB),
but i'm searching for solution for both worlds (described + JSF) with same Interceptor concept
I need #ViewScoped #ManagedBean, thats why i cant get rid of #ManagedBean in favour of pure WebBeans
System:
Mojarra 2.1.7
Primefaces 3.2
As far as I understand, there isn't one. JSF doesn't have anything supporting interception.
JSF does not support the CDI interception like you have posted per se. A CDI interceptor will work for lifecycle methods like #PostConstruct
#Inherited
#InterceptorBinding
#Retention(RUNTIME)
#Target({TYPE})
public #interface TypeLogger {
#Nonbinding
public LoggingLevel logLevel() default LoggingLevel.INFO;
}
Here is how it would be used since it only binds to the #Target({TYPE})
#ManagedBean
#ViewScoped
#TypeLogger
public class Index implements Serializable {
private static final long serialVersionUID = 3336392241545517919L;
#PostConstruct
private void init() {
setup();
}
}

How to add Method Expression to a custom JSF component

I'm trying to create a custom JSF component and add to it a method expression. This is the code of my custom component:
#FacesComponent(AjaxCommand2.COMPONENT_TYPE)
public class AjaxCommand2 extends UIComponentBase {
public static final String COMPONENT_TYPE = "local.test.component.AjaxCommand2";
public static final String COMPONENT_FAMILY = "local.test.component.AjaxCommand2";
private MethodExpression listener;
public MethodExpression getListener() {
return listener;
}
public void setListener(MethodExpression listener) {
this.listener = listener;
}
#Override
public String getRendererType() {
return null;
}
#Override
public String getFamily() {
return COMPONENT_FAMILY;
}
}
This is my tag lib file:
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib id="test"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd" version="2.0">
<namespace>http://local.test/ui</namespace>
<tag>
<tag-name>ajaxCommand2</tag-name>
<component>
<component-type>local.test.component.AjaxCommand2</component-type>
</component>
<attribute>
<name>listener</name>
<required>false</required>
<type>javax.el.MethodExpression</type>
</attribute>
</tag>
</facelet-taglib>
And this is the relevant code in the JSF page:
<test:ajaxCommand2 listener="#{testSessionBean.testActionAjax}" />
My problem is that the setter for listener never is called in my custom component and always I'm getting null in listener property.
I cannot see whrere is the problem.
Any idea?, I would like set the listener property to point to a specific method of one backed bean.
Write a Handler for the Component like this:
public class MoveHandler extends ComponentHandler {
public MoveHandler(ComponentConfig config) {
super(config);
}
#Override
protected MetaRuleset createMetaRuleset(Class type) {
MetaRuleset metaRuleset = super.createMetaRuleset(type);
MetaRule metaRule = new MethodRule("listener", void.class, new Class[] {MoveEvent.class});
metaRuleset.addRule(metaRule);
return metaRuleset;
}
}

Migrating from facelets 1.1 to faclets 2.0 - FaceletViewHandler

I have read the following post which was very helpful
Migrating from JSF 1.2 to JSF 2.0
but I am having a problem with the migration as I have a custom view handler which extends from FaceletViewHandler - this is not part of faclets 2.
I am migrating on JBoss 4.2.2 the following:
- JSF 1.2 to JSF 2.0
I also want to migrate the faclets - which i have a problem described above.
In my application, I am also using Tomahawk - is there any problem with this migration?
Thanks in advance.
Elico.
Right, you need to replace FaceletViewHandler by ViewHandlerWrapper.
So the following basic FaceletViewHandler implementation:
import javax.faces.application.ViewHandler;
import com.sun.facelets.FaceletViewHandler;
public class MyViewHandler extends FaceletViewHandler {
public MyViewHandler(ViewHandler parent) {
super(parent);
}
// ...
}
needs to be updated as follows:
import javax.faces.application.ViewHandler;
import javax.faces.application.ViewHandlerWrapper;
public class MyViewHandler extends ViewHandlerWrapper {
private ViewHandler wrapped;
public MyViewHandler(ViewHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ViewHandler getWrapped() {
return wrapped;
}
// ...
}
I've updated my answer on the migration question accordingly.
To activate MyViewHandler e.g. for JEE7, WEB-INF/faces-config.xml should be defined like:
<?xml version="1.0"?>
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<application>
<view-handler>pkg.MyViewHandler</view-handler>
</application>
</faces-config>

Resources