Trinidad 1.2.14 is MyFaces implementation for JSF 1.2 specification. It’s mainly released by Apache MyFaces and it’s considered last official release that you can download from Apache MyFaces Trinidad site.
Actually, Trinidad library is a leading library that truly help you getting JSF application in the most easiest way, it’s contained a lot of important components that can help you avoid wasting your time creating or developing any component you may need.
This version of Trinidad is almost ideal but there’s one issue you may be suffering from when it comes to deal with, it’s actually doesn’t understand Ajaxifying request on IE 11 and that may cause a headache for a lot of developers whom want to use this feature.
This tutorial is a solid trial that would help you getting full-fledged Trinidad 1.2.14 library ajaxified comfortably on all version of IE including IE 11. You may review the internet and Trinidad JIRA but actually, you my be wondering that the Trinidad itself doesn’t provide any solution for that. All what you may find is just a scattered patch that’s required you to work on it to justify the needed solution.
Tools Used
I’ve assumed that you will use the below Tools/Envs for getting this practice applied:
- Any JEE container.
- JSF Trinidad 1.2.14 API & Impl.
- JDK 1.6.
- Eclipse Kepler 4.3.
- Maven 3.2.1.
Ajax Concept In Trinidad
Ajax concept hasn’t vary differ from what already most of developers were knew. It’s simple partial submission for the page; instead of sending a full JSF Post-Back request into server, you’re just sending part of the page into server and update part of it in the response.
Here, you would see a true Ajax application that uses a Trinidad 1.2.14 upon Chrome browser. In fact and indeed the implementations of Ajax aren’t analogous to that degree that you may use different mechanisms for ِAjaxifying your application if you’re decided to use different JSF vendors. That is, there’s no standard way to Ajaxify, so it depends on the library that you’re going to use.
index.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="f" uri="https://java.sun.com/jsf/core"%> <%@ taglib prefix="h" uri="https://java.sun.com/jsf/html"%> <%@ taglib prefix="tr" uri="https://myfaces.apache.org/trinidad"%> <%@ taglib prefix="trh" uri="https://myfaces.apache.org/trinidad/html"%> <f:view> <tr:form> <h:panelGrid columns="4"> <h:outputLabel value="Enter your message here"></h:outputLabel> <tr:inputText value="#{messageBackingBean.message}" partialTriggers="ajaxAction"></tr:inputText> <tr:commandButton id="ajaxAction" text="Ajax Sending" action="#{messageBackingBean.addMessage}" partialSubmit="true"></tr:commandButton> <tr:commandButton id="nonAjaxAction" text="Non-Ajax Sending" action="#{messageBackingBean.addMessage}"></tr:commandButton> </h:panelGrid> <tr:statusIndicator inlineStyle="padding-left:400px;"> <f:facet name="busy"> <h:graphicImage url="/images/ajax-loader.gif"></h:graphicImage> </f:facet> </tr:statusIndicator> <h:panelGrid columns="1"> <f:facet name="header"> <h:outputText value="Sent Messages"></h:outputText> </f:facet> <tr:table value="#{messageBackingBean.messages}" var="message" partialTriggers="ajaxAction"> <tr:column> <h:outputText value="#{message}"></h:outputText> </tr:column> </tr:table> </h:panelGrid> </tr:form> </f:view> |
MessageBackingBean.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package com.journaldev; import java.util.ArrayList; public class MessageBackingBean { private String message = ""; private ArrayList<String> messages = new ArrayList<String>(); public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public ArrayList<String> getMessages() { return messages; } public void setMessages(ArrayList<String> messages) { this.messages = messages; } @SuppressWarnings("static-access") public String addMessage() throws InterruptedException{ // Wait for 5 seconds, just to ensure the action is invoked in an Ajax behavior Thread.currentThread().sleep(5000); this.messages.add(message); this.message = ""; return ""; } } |
faces-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?xml version="1.0" encoding="UTF-8" ?> <faces-config xmlns="https://java.sun.com/xml/ns/javaee" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd" version="1.2"> <application> <default-render-kit-id>org.apache.myfaces.trinidad.core</default-render-kit-id> </application> <managed-bean> <managed-bean-name>messageBackingBean</managed-bean-name> <managed-bean-class>com.journaldev.MessageBackingBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config> |
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<?xml version="1.0"?> <project xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>com.journaldev</groupId> <artifactId>Trinidad-JSF-APP</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>Trinidad-JSF-APP Maven Webapp</name> <url>https://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>jsf-api</artifactId> <version>1.2_13</version> </dependency> <dependency> <groupId>javax</groupId> <artifactId>jsf-impl</artifactId> <version>1.2_13</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.apache.myfaces.trinidad</groupId> <artifactId>trinidad-api</artifactId> <version>1.2.14</version> </dependency> <dependency> <groupId>org.apache.myfaces.trinidad</groupId> <artifactId>trinidad-impl</artifactId> <version>1.2.14</version> </dependency> </dependencies> <build> <finalName>Trinidad-JSF-APP</finalName> </build> </project> |
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xmlns:web="https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>Trinidad-JSF-APP</display-name> <context-param> <param-name>javax.faces.CONFIG_FILES</param-name> <param-value> /WEB-INF/faces-config.xml </param-value> </context-param> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>server</param-value> </context-param> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>resources</servlet-name> <servlet-class>org.apache.myfaces.trinidad.webapp.ResourceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>resources</servlet-name> <url-pattern>/adf/*</url-pattern> </servlet-mapping> </web-app> |
Here’s detailed explanation for the code listed above:
- Trinidad has initiated a PPR through using of its library that’s grabbed by
resources
Servlet. This script library will be injected into your JSF page as soon as it’s rendered and it would have this name/CONTEXT/adf/jsLibs/Common1_2_14.js
if you’re explored your page header. - The action
Ajax Sending
will be used to ajaxify the calling ofaddMessage
method/action. - The action
Non-Ajax Sending
will be used to initiate normalPostBack
request. - As soon as the Ajax request is triggered, the Ajax loader image will be displayed by
statusIndicator
Trinidad Tag. This will give you a good indicator for being the request is initiated using Ajax manner. - At the
MessageBackingBean
, you will be waiting there in for 5 seconds, just to give you a chance simulating heavy processing.
Now, let’s see a simple demonstration for what already implemented till now using a non error prone Chrome browser.
Below figure shows you the initial view of the index.jsp
that’s already considered as default page.
Enter a message inside the box below and submit the Ajax Sending action. You will notice that the ajax indicator loading image will be displayed, just wait for 5 seconds before the message is sent.
The same behavior can be achieved through using a default Post Back
JSF action and the same result would be occurred with one major difference is being the request is Post back.
What’s The Problem
As you’ve noticed above, Ajax Trinidad has functioned properly on the Chrome where no issues were noticed. But what if you’re going to IE 11, you will absolutely get Ajax failed due to Trinidad Implementation missing.
Let’s look at the behavior below that shows you the impact of browsing the same Application above on the IE 11 – Notice, this issue weren’t noticed at any version of IE and that what i will explore in the next coming lines
Here’s below a detailed explanation for the behavior seen above:
- Once you’ve clicked on the Ajax action, the ajax loading image will be displayed but actually the behavior is little bit different where the IE won’t get updated the Table of Sent Messages as well as an error message will be thrown says Connection Failed.
- If you’ve reviewed your Console or Logger, you’re likely get an exception like below.
Thrown Exception
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
SEVERE: Servlet.service() for servlet Faces Servlet threw exception java.lang.IllegalArgumentException at org.apache.myfaces.trinidadinternal.renderkit.core.ppr.PPRResponseWriter.<init>(PPRResponseWriter.java:59) at org.apache.myfaces.trinidadinternal.renderkit.core.CoreRenderKit.createResponseWriter(CoreRenderKit.java:609) at org.apache.myfaces.trinidadinternal.renderkit.RenderKitDecorator.createResponseWriter(RenderKitDecorator.java:54) at com.sun.faces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:189) at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:189) at org.apache.myfaces.trinidadinternal.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:193) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:110) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:266) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:662) |
- Actually, the above listed exception wasn’t thrown on any browser except the IE 11, even if you’re used IE 7, 8, 9 or 10 this issue won’t be noticed.
- This above exception is caused due to unavailability of correct Agent value. That is,
RequestContextImpl
getAgent will be asked to determine the type of the Agent that actually try to display the view. By its turn, theAgentFactoryImpl
_populateMozillaAgentImpl method will be called because the Agent description starts with Mozilla keyword. - The _populateMozillaAgentImpl method will return wrong value that’s affected the normal procedure of your Partial Page Trigger (PPR) handling. User agent of IE 11 is
Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
and the _populateMozillaAgentImpl method won’t be able to recognize the Agent Type which will be finally just like in the figure below:
- But if you’re modifying the user agent string from your IE browser to be Internet Explorer 10 or less and you tried to initiate a new Partial Page Request, you will find a different agent string, that will be
Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)
and the agent type will be just like figure below:
- The same correct value you will still be able to receive as long as you used an IE version less than 11. Look below for the value of IE 8.
As a conclusion, the main issue is relevant for _populateMozillaAgentImpl that should be fixed to contain a proper handling for IE 11.
Importing Trinidad 1.2.14 Source Code Impl Library into Eclipse Project
To know the main cause of this issue, it’s worthy to get Trinidad Impl debugged to know from where we can start the fix procedure. Upon that, let’s basically download Trinidad 1.2.14 and look inside to know what the cause of this behavior.
- Download Trinidad impl 1.2.14 source code from Trinidad Apache official site.
- Unzip
trinidad-1.2.14-src-all.zip
into your hard storage. - From your Eclipse Project Explorer, click new – import and choose Maven project.
- Paste your Trinidad location just as you see below.
- Now, you’re able of getting Trinidad Impl compiled and packaged through using of both Maven command & Eclipse. Figure below shows you the success cleaning and packaging for Trinidad Impl library.
- Now, you can provide your Fix for the AgentFactoryImpl and provide your own Trinidad Impl library.
Fixing AgentFactoryImpl
According for the previous investigation and to fix the issue of IE 11, I’ve provided you the new implementation of _populateMozillaAgentImpl to be like below:
_populateMozillaAgentImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
/** * Returns an AgentEntry for the "Mozilla" family of browsers - which * most at least pretend to be. */ private void _populateMozillaAgentImpl(String agent,AgentImpl agentObj) { int ieTridentIndex = -1; int paren = agent.indexOf('('); agentObj.setType(Agent.TYPE_DESKTOP); //Is this default realli okay??? These days Mobile agents also use Mozilla/xx.xx // No section to qualify the agent; assume Mozilla/Netscape if (paren == -1) { agentObj.setAgent(TrinidadAgent.AGENT_NETSCAPE); agentObj.setAgentVersion(_getVersion(agent, agent.indexOf('/'))); } else { paren = paren + 1; boolean isJDevVE = agent.indexOf("JDeveloper", paren) > 0; boolean isJDevJSVE = agent.indexOf("JDeveloper JS", paren) > 0; if (agent.indexOf("Konqueror", paren) >= 0) { agentObj.setType(Agent.TYPE_DESKTOP); agentObj.setAgent(Agent.AGENT_KONQUEROR); agentObj.setAgentVersion(_getVersion(agent, agent.lastIndexOf('/'))); } // Added to get IE 11 resolved & to handle all IE browsers else if ((ieTridentIndex = agent.indexOf("Trident", paren)) > -1) { agentObj.setAgent(Agent.AGENT_IE); // As of IE8, the Trident version is the most reliable method to find the // maximum capabilities of IE. The IE WebBrowser Control by default is in IE7 // compatability - MSIE 7.0; // As of IE11, the "MSIE" token no loger exists. //Trident/4.0 -> IE8 //Trident/5.0 -> IE9 //Trident/6.0 -> IE10 //Trident/7.0 -> IE11 Double ieTridentVersion = Double.valueOf(_getVersion(agent, ieTridentIndex + "Trident/".length() - 1)); agentObj.setAgentVersion(String.valueOf(ieTridentVersion + 4.0)); } else if (agent.startsWith("compatible", paren)) { int ieIndex = agent.indexOf("MSIE", paren); if (ieIndex < 0) { // check for Palm int palmIndex = agent.indexOf("Elaine", paren); if (palmIndex > 0) { agentObj.setType(Agent.TYPE_PDA); agentObj.setAgent(TrinidadAgent.AGENT_ELAINE); agentObj.setAgentVersion(_getVersion(agent, palmIndex)); agentObj.setPlatform(Agent.PLATFORM_PALM); } } else { agentObj.setAgent(Agent.AGENT_IE); agentObj.setAgentVersion(_getVersion(agent, ieIndex + 4)); } } else { agentObj.setAgent(TrinidadAgent.AGENT_NETSCAPE); agentObj.setAgentVersion(_getVersion(agent, agent.indexOf('/'))); } // try to determine the OS, if unknown if (agentObj.getPlatformName() == null || agentObj.getPlatformName().equals(Agent.PLATFORM_UNKNOWN)) { // Hack: treat the JDeveloper agent as Windows, // so that we assume IE 6.0 Windows capabilities if ((agent.indexOf("Win", paren) > 0) || isJDevVE) { agentObj.setPlatform(Agent.PLATFORM_WINDOWS); } else if (agent.indexOf("Mac", paren) > 0) { agentObj.setPlatform(Agent.PLATFORM_MACOS); } else if (agent.indexOf("Linux", paren) > 0) { agentObj.setPlatform(Agent.PLATFORM_LINUX); } else if (agent.indexOf("Sun", paren) > 0) { agentObj.setPlatform(Agent.PLATFORM_SOLARIS); } } if (isJDevVE) { agentObj.__addRequestCapability(TrinidadAgent.CAP_IS_JDEV_VE, Boolean.TRUE); if (isJDevJSVE) { agentObj.__addRequestCapability(TrinidadAgent.CAP_IS_JDEV_JAVASCRIPT_VE, Boolean.TRUE); } } } } |
Here’s detailed explanation for the code listed above:
- We added the code commented to handle the IE 11 & all types of IEs.
- You can download the full AgentFactoryImpl right here AgentFactoryImpl.
- Replace the downloaded file or re-implement the method and make your code compiled and package the updated Trinidad impl library just like you saw in the Maven figure above.
- Install your latest Trinidad Impl library using mvn clean package install.
Demonstrate PPR Sample Using IE 11 After Fixing
This figure below shows you a proper handling for the PPR request against IE 11.
Resources
Summary
Trinidad is a leading implementation for JSF and it provides you a different kinds of components that actually have the capability of initiating requests Post back or partially. The main issue you may got when it comes to deal with Trinidad latest release 1.2.14 is handling partial request on IE 11. This tutorial will help you getting this issue resolved, so contribute us by commenting below.