Introduction
Recently Microsoft has released its new version 11 of Internet Explorer. When developing ADF-applications the most obvious question is of course: will my application still work? The short answer is: NO, you have to wait until Oracle brings out a new patch. When you try to run your application, you will get a popup-message about the fact that you are using a non-supported browser version, and your application will not work the way you expect. Running the browser in compatibility-mode might work in some situations, but users also get annoying popups, and in many cases the layout and the behaviour of the application is not the way it should be.
But there is a workaround. We introduced this workaround in an ADF 11.1.1.6 application that also had to run under IE10. This is a non-certified combination and running it results in strange client-behavior of the application. E.g. the movement of a splitter results in a complete blank screen as long as you hold the mouse down. As probably in many production environments, we are not (yet) able to migrate to ADF 11.1.1.7, and since the application runs in many different sites, we are not able to control the browser versions. We found a solution that works pretty good. And the good news is: it also seems to work for Internet Explorer 11!
A sample of the solution can be downloaded from IEFilterDemo.zip .
But there is a workaround. We introduced this workaround in an ADF 11.1.1.6 application that also had to run under IE10. This is a non-certified combination and running it results in strange client-behavior of the application. E.g. the movement of a splitter results in a complete blank screen as long as you hold the mouse down. As probably in many production environments, we are not (yet) able to migrate to ADF 11.1.1.7, and since the application runs in many different sites, we are not able to control the browser versions. We found a solution that works pretty good. And the good news is: it also seems to work for Internet Explorer 11!
A sample of the solution can be downloaded from IEFilterDemo.zip .
The problem
When looking for a solution I found some examples that were based on the idea of adding a new header to the HttpServletResponse. E.g. HttpServletResponse response = (HttpServletResponse)ectx.getResponse();
response.addHeader("X-UA-Compatible", "IE=EmulateIE9");
However, this does not work. When ADF receive a request, one of the things that happen is that, based on the request-headers, it determines the user-agent. If this agent is an MSIE agent, the first thing that ADF writes in the response is an meta-tag that contains the browser version. So a request from IE 10 will always result in a response containing an IE 10 meta-tag:
<html class="p_AFMaximized" lang="nl-NL" dir="ltr">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=10.0">
....
Any attempt to add your own response-header to make the IE browser behave like an older version will be ignored.
IE 11 makes it even worse. This version doesn't send a user-agent header containing a reference to MSIE. It sends a header that should make applications believe the request comes from a 'Gecko-like' browser. The idea is that IE 11 is compatible with these browsers.
user-agent header from IE 11:
Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
The solution
The solution is quite simple: we have to make ADF believe that the request comes from an older version of IE, so in return ADF will write the correct meta-tag into the response, and IE will act accordingly.
This can be achieved by creating and adding a custom filter. The filter determines the user-agent, and in case of IE 10 or 11, it wraps the request in our own version of a HttpServletRequestWrapper. The WrapperRequest has a method getHeader() in which we control what string is returned when the "user-agent" header is requested.
When we place our filter in the top of the filter-chain, the request that ADF receives, is our WrappedRequest. When ADF tries to determine the user-agent, it will receive the answer given by our WrapperRequest, which makes ADF think we are using an IE 9 or IE 10 browser.
package view;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class IECompatibleFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String userAgentStr = ((HttpServletRequest)request).getHeader("user-agent");
// Check to see if we have to do with a IE request. If so, we return a wrapped request.
if (userAgentStr != null && (userAgentStr.contains("MSIE 1") ||
userAgentStr.contains("Trident"))) {
ServletRequest wrappedRequest = new WrapperRequest((HttpServletRequest)request);
chain.doFilter(wrappedRequest, response);
} else {
chain.doFilter(request, response);
}
}
public void destroy() {
}
public void init(FilterConfig arg0) throws ServletException {
}
private class WrapperRequest extends HttpServletRequestWrapper {
public WrapperRequest(HttpServletRequest request) {
super(request);
}
public String getHeader(String name) {
// IE 10: replace 'MSIE 10.x' into 'MSIE 9.x' for ADF 11.1.1.6 and below
HttpServletRequest request = (HttpServletRequest)getRequest();
if ("user-agent".equalsIgnoreCase(name) && request.getHeader("user-agent").contains("MSIE 10")) {
return request.getHeader("user-agent").replaceAll("MSIE [^;]*;", "MSIE 9.0;");
}
// IE 11: replace the whole agent-string into an MSIE 9.0 string for ADF 11.1.1.6 and below
// or MSIE 10.0 for ADF 11.1.1.7 or higher
if ("user-agent".equalsIgnoreCase(name) && request.getHeader("user-agent").contains("Trident")) {
//Choose your preferred version
String newAgentStr = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.2; Trident/6.0)";
return newAgentStr;
}
return request.getHeader(name);
}
}
}
The filter has to be defined in the web.xml-file of your project. Make sure it is defined above the trinidad-filter, because this one is used by ADF to determine the user-agent.
web.xml
...
<filter>
<filter-name>IECompatibleFilter</filter-name>
<filter-class>view.IECompatibleFilter</filter-class>
</filter>
<filter>
<filter-name>trinidad</filter-name>
<filter-class>org.apache.myfaces.trinidad.webapp.TrinidadFilter</filter-class>
</filter>
...
<filter-mapping>
<filter-name>IECompatibleFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>trinidad</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
...
Conclusion
The above solution is not the ideal situation, but as long as we are dealing with non-supported combinations of browsers and ADF versions, it might be a workaround. The nice things is that you don't have to change your application, but you only add the filter to the web.xml. Furthermore I think the solution is not limited to ADF applications.I have tested this solution with ADF 11.1.1.6, 11.1.1.7 and 11.1.2.3, and they all seem to work under IE 11, but of course I cannot guarantee that it will work in all situations. Give it a try.