blob: 5bf1da4835e2b36bc47d5cff2e7a84488d08d154 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.lifecycle.clientwindow;
import javax.faces.context.FacesContext;
import java.io.Serializable;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* Contains information about whether the user has
* JavaScript enabled on his client, etc.
* It also contains the windowhandler html which gets sent to
* the browser to detect the current windowId.
*
* This allows the 'customisation' of this html file to e.g.
* adopt the background colour to avoid screen flickering.
*
* Please note that all subclasses of ClientConfig should also
* be @SessionScoped as well!
*/
public class ClientConfig implements Serializable
{
private static final long serialVersionUID = 581351549574404793L;
/** We will set a cookie with this very name if a noscript link got clicked by the user */
public static final String COOKIE_NAME_NOSCRIPT_ENABLED = "mfNoScriptEnabled";
private volatile Boolean javaScriptEnabled = null;
protected String windowHandlerHtml;
/** lazily initiated via {@link #getUserAgent(javax.faces.context.FacesContext)} */
private volatile String userAgent = null;
/**
* Defaults to <code>true</code>.
* @return if the user has JavaScript enabled
*/
public boolean isJavaScriptEnabled()
{
if (javaScriptEnabled == null)
{
synchronized(this)
{
// double lock checking idiom on volatile variable works since java5
if (javaScriptEnabled == null)
{
// no info means that it is default -> true
javaScriptEnabled = Boolean.TRUE;
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext != null)
{
Cookie cookie = (Cookie) facesContext.getExternalContext().
getRequestCookieMap().get(COOKIE_NAME_NOSCRIPT_ENABLED);
if (cookie!= null)
{
javaScriptEnabled = Boolean.parseBoolean((String) cookie.getValue());
}
}
}
}
}
return javaScriptEnabled;
}
/**
* Set it to <code>false</code> if you don't like to use the
* JavaScript based client side windowhandler. In this case
* the request will be returned directly.
* @param javaScriptEnabled
*/
public void setJavaScriptEnabled(boolean javaScriptEnabled)
{
this.javaScriptEnabled = javaScriptEnabled;
// and now also store this information inside a cookie!
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext != null)
{
Object r = facesContext.getExternalContext().getResponse();
if (r instanceof HttpServletResponse)
{
Cookie cookie = new Cookie(COOKIE_NAME_NOSCRIPT_ENABLED, "" + javaScriptEnabled);
cookie.setPath("/"); // for all the server
HttpServletResponse response = (HttpServletResponse) r;
response.addCookie(cookie);
}
}
}
/**
* For branding the whole windowhandler page - e.g. not only change the
* background color, add some images and empty menu structure
* or the language of the message text - you can just copy the content of the
* {@link #DEFAULT_WINDOW_HANDLER_HTML_FILE} and adopt it to your needs.
*
* The reason for this is to minimize visual side effects on browsers who do
* not properly support html5 localstorage.
*
* @return the location of the <i>windowhandler.html</i> resource
* which should be sent to the users browser.
*/
/*
public String getWindowHandlerResourceLocation()
{
return DEFAULT_WINDOW_HANDLER_HTML_FILE;
}*/
/**
* This might return different windowhandlers based on user settings like
* his language, an affiliation, etc
* @return a String containing the whole windowhandler.html file.
* @throws IOException
*/
/*
public String getWindowHandlerHtml() throws IOException
{
if (FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Development)
&& windowHandlerHtml != null)
{
// use cached windowHandlerHtml except in Development
return windowHandlerHtml;
}
InputStream is = ClassUtils.getContextClassLoader().getResourceAsStream(
getWindowHandlerResourceLocation());
StringBuffer sb = new StringBuffer();
try
{
byte[] buf = new byte[16 * 1024];
int bytesRead;
while ((bytesRead = is.read(buf)) != -1)
{
String sbuf = new String(buf, 0, bytesRead);
sb.append(sbuf);
}
}
finally
{
is.close();
}
windowHandlerHtml = sb.toString();
return windowHandlerHtml;
}*/
/**
* This information will get stored as it cannot
* change during the session anyway.
* @return the UserAgent of the request.
*/
public String getUserAgent(FacesContext facesContext)
{
if (userAgent == null)
{
synchronized (this)
{
if (userAgent == null)
{
Map<String, String[]> requestHeaders =
facesContext.getExternalContext().getRequestHeaderValuesMap();
if (requestHeaders != null &&
requestHeaders.containsKey("User-Agent"))
{
String[] userAgents = requestHeaders.get("User-Agent");
userAgent = userAgents.length > 0 ? userAgents[0] : null;
}
}
}
}
return userAgent;
}
/**
* Users can overload this method to define in which scenarios a request should result
* in an 'intercepted' page with proper windowId detection. This can e.g. contain
* blacklisting some userAgents.
* By default the following User-Agents will be served directly:
* <ul>
* <li>.*bot.*</li>
* <li>.*Bot.*</li>
* <li>.*Slurp.*</li>
* <li>.*Crawler.*</li>
* </ul>
* @return <code>true</code> if the Request should get 'intercepted' and the intermediate
* windowhandler.html page should get rendered first. By returning <code>false</code>
* the requested page will get rendered intermediately.
* @see #getUserAgent(javax.faces.context.FacesContext) for determining the UserAgent
*/
public boolean isClientSideWindowHandlerRequest(FacesContext facesContext)
{
if (!isJavaScriptEnabled())
{
return false;
}
String userAgent = getUserAgent(facesContext);
if (userAgent != null &&
( userAgent.indexOf("bot") >= 0 || // Googlebot, etc
userAgent.indexOf("Bot") >= 0 || // BingBot, etc
userAgent.indexOf("Slurp") >= 0 || // Yahoo Slurp
userAgent.indexOf("Crawler") >= 0 // various other Crawlers
) )
{
return false;
}
return true;
}
}