blob: 3fb799114749337518ac87beba93ad89ce3ce07c [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.extensions.cdi.jsf.api.config;
import org.apache.myfaces.extensions.cdi.core.api.projectstage.ProjectStage;
import org.apache.myfaces.extensions.cdi.core.api.util.ClassUtils;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
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.
*/
@SessionScoped
public class ClientConfig implements Serializable
{
private static final long serialVersionUID = 581351549574404793L;
public static final String BODY_ATTRIBUTES_PLACEHOLDER = "$$bodyAttributes$$";
/** 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;
@Inject
private ProjectStage projectStage;
/**
* The location of the default windowhandler resource
*/
private static final String DEFAULT_WINDOW_HANDLER_HTML_FILE = "static/windowhandler.html";
/**
* 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.
*
* If you just like to change the default background color, then use
* {@link #getBodyAttributes()} instead. This will replace the
* {@link #BODY_ATTRIBUTES_PLACEHOLDER} on the windowhandler.html page.
*
* @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;
}
/**
* Overwrite this method to set custom specific body attributes on the
* intermediate windowhandler.html page.
*
* @return
*/
public String getBodyAttributes()
{
return "";
}
/**
* 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 (projectStage != ProjectStage.Development && windowHandlerHtml != null)
{
// use cached windowHandlerHtml except in Development
return windowHandlerHtml;
}
InputStream is = ClassUtils.getClassLoader(null).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;
}
/**
* 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.
*/
public boolean isClientSideWindowHandlerRequest(FacesContext facesContext)
{
if (!isJavaScriptEnabled())
{
return false;
}
Map<String, String[]> requestHeaders = facesContext.getExternalContext().getRequestHeaderValuesMap();
if (requestHeaders != null &&
requestHeaders.containsKey("User-Agent"))
{
String[] userAgents = requestHeaders.get("User-Agent");
String userAgent = userAgents.length > 0 ? userAgents[0] : null;
if (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;
}
}