blob: f40d5b996064b8dc69f2af73fe979c28afc50b02 [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.tobago.internal.config;
import org.apache.myfaces.tobago.config.TobagoConfig;
import org.apache.myfaces.tobago.context.Theme;
import org.apache.myfaces.tobago.context.ThemeImpl;
import org.apache.myfaces.tobago.exception.TobagoConfigurationException;
import org.apache.myfaces.tobago.sanitizer.Sanitizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* <p>
* Implementation of the Tobago configuration.
* </p>
* <p>
* All setters must are protected, so EL can't modify this config.
* </p>
*/
//@Named("tobagoConfig") // todo
//@ApplicationScoped // todo
public class TobagoConfigImpl extends TobagoConfig {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private List<Theme> supportedThemes;
private List<String> supportedThemeNames;
private Theme defaultTheme;
private String defaultThemeName;
private Map<String, ThemeImpl> availableThemes;
private boolean createSessionSecret;
private boolean checkSessionSecret;
private boolean preventFrameAttacks;
private final ContentSecurityPolicy contentSecurityPolicy;
private SecurityAnnotation securityAnnotation;
private boolean setNosniffHeader;
private Map<String, String> defaultValidatorInfo;
private Sanitizer sanitizer;
private boolean decodeLineFeed;
private Map<String, String> mimeTypes;
private boolean locked = false;
protected TobagoConfigImpl(String fixme) { // CDI workaround fixme
supportedThemeNames = new ArrayList<>();
supportedThemes = new ArrayList<>();
availableThemes = new HashMap<>();
createSessionSecret = true;
checkSessionSecret = true;
preventFrameAttacks = true;
setNosniffHeader = true;
securityAnnotation = SecurityAnnotation.disable;
decodeLineFeed = true;
contentSecurityPolicy = new ContentSecurityPolicy(ContentSecurityPolicy.Mode.OFF.getValue());
mimeTypes = new HashMap<>();
}
/**
* Lock the configuration, so it cannot be modified any more.
*/
protected void lock() {
locked = true;
supportedThemes = Collections.unmodifiableList(supportedThemes);
for (final Theme theme : supportedThemes) {
((ThemeImpl) theme).lock();
}
supportedThemeNames = Collections.unmodifiableList(supportedThemeNames);
availableThemes = Collections.unmodifiableMap(availableThemes);
contentSecurityPolicy.lock();
mimeTypes = Collections.unmodifiableMap(mimeTypes);
}
private void checkUnlocked() throws IllegalStateException {
if (locked) {
throw new TobagoConfigurationException("The configuration must not be changed after initialization!");
}
}
protected void addSupportedThemeName(final String name) {
checkUnlocked();
supportedThemeNames.add(name);
}
// TODO one init method
protected void resolveThemes() {
checkUnlocked();
if (defaultThemeName != null) {
defaultTheme = availableThemes.get(defaultThemeName);
checkThemeIsAvailable(defaultThemeName, defaultTheme);
if (LOG.isDebugEnabled()) {
LOG.debug("name = '{}'", defaultThemeName);
LOG.debug("defaultTheme = '{}'", defaultTheme);
}
} else {
int deep = 0;
for (final Map.Entry<String, ThemeImpl> entry : availableThemes.entrySet()) {
final Theme theme = entry.getValue();
if (theme.getFallbackList().size() > deep) {
defaultTheme = theme;
deep = theme.getFallbackList().size();
}
}
if (defaultTheme == null) {
final String error = "Did not found any theme! "
+ "Please ensure you have a tobago-config.xml with a theme-definition in your "
+ "theme JAR. Please add a theme JAR to your WEB-INF/lib";
LOG.error(error);
throw new TobagoConfigurationException(error);
} else {
if (LOG.isInfoEnabled()) {
LOG.info("Using default Theme {}", defaultTheme.getName());
}
}
}
if (!supportedThemeNames.isEmpty()) {
for (final String name : supportedThemeNames) {
final Theme theme = availableThemes.get(name);
checkThemeIsAvailable(name, theme);
supportedThemes.add(theme);
if (LOG.isDebugEnabled()) {
LOG.debug("name = '{}'", name);
LOG.debug("supportedThemes.last() = '{}'", supportedThemes.get(supportedThemes.size() - 1));
}
}
}
}
private void checkThemeIsAvailable(final String name, final Theme theme) {
if (theme == null) {
final String error = "Theme not found! name: '" + name + "'. "
+ "Please ensure you have a tobago-config.xml with a theme-definition in your "
+ "theme JAR. Found the following themes: " + availableThemes.keySet();
LOG.error(error);
throw new TobagoConfigurationException(error);
}
}
@Override
public Theme getTheme(final String name) {
if (name == null) {
LOG.debug("searching theme: null");
return defaultTheme;
}
if (defaultTheme != null && defaultTheme.getName().equals(name)) {
return defaultTheme;
}
for (final Theme theme : supportedThemes) {
if (theme.getName().equals(name)) {
return theme;
}
}
LOG.debug("searching theme '{}' not found. Using default: {}", name, defaultTheme);
return defaultTheme;
}
protected void setDefaultThemeName(final String defaultThemeName) {
checkUnlocked();
this.defaultThemeName = defaultThemeName;
}
@Override
public List<Theme> getSupportedThemes() {
return supportedThemes;
}
@Override
public Theme getDefaultTheme() {
return defaultTheme;
}
protected void addAvailableTheme(final ThemeImpl availableTheme) {
checkUnlocked();
availableThemes.put(availableTheme.getName(), availableTheme);
}
public Map<String, ThemeImpl> getAvailableThemes() {
return availableThemes;
}
protected synchronized void initDefaultValidatorInfo() {
if (defaultValidatorInfo != null) {
checkUnlocked();
}
final FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext != null) {
try {
final Application application = facesContext.getApplication();
final Map<String, String> map = application.getDefaultValidatorInfo();
if (map.size() > 0) {
defaultValidatorInfo = Collections.unmodifiableMap(map);
} else {
defaultValidatorInfo = Collections.emptyMap();
}
} catch (final Exception e) {
LOG.error("Can't initialize default validators (this happens with JBoss GateIn 3.6.0).", e);
defaultValidatorInfo = Collections.emptyMap();
}
}
}
@Override
public boolean isCreateSessionSecret() {
return createSessionSecret;
}
protected void setCreateSessionSecret(final boolean createSessionSecret) {
checkUnlocked();
this.createSessionSecret = createSessionSecret;
}
@Override
public boolean isCheckSessionSecret() {
return checkSessionSecret;
}
protected void setCheckSessionSecret(final boolean checkSessionSecret) {
checkUnlocked();
this.checkSessionSecret = checkSessionSecret;
}
@Override
public boolean isPreventFrameAttacks() {
return preventFrameAttacks;
}
protected void setPreventFrameAttacks(final boolean preventFrameAttacks) {
checkUnlocked();
this.preventFrameAttacks = preventFrameAttacks;
}
@Override
public ContentSecurityPolicy getContentSecurityPolicy() {
return contentSecurityPolicy;
}
@Override
public boolean isSetNosniffHeader() {
return setNosniffHeader;
}
protected void setSetNosniffHeader(final boolean setNosniffHeader) {
checkUnlocked();
this.setNosniffHeader = setNosniffHeader;
}
@Override
public SecurityAnnotation getSecurityAnnotation() {
return securityAnnotation;
}
public void setSecurityAnnotation(final SecurityAnnotation securityAnnotation) {
checkUnlocked();
this.securityAnnotation = securityAnnotation;
}
public Map<String, String> getDefaultValidatorInfo() {
// TODO: if the startup hasn't found a FacesContext and Application, this may depend on the order of the listeners.
if (defaultValidatorInfo == null) {
initDefaultValidatorInfo();
}
return defaultValidatorInfo;
}
@Override
public Sanitizer getSanitizer() {
return sanitizer;
}
protected void setSanitizer(final Sanitizer sanitizer) {
checkUnlocked();
this.sanitizer = sanitizer;
}
@Override
public boolean isDecodeLineFeed() {
return decodeLineFeed;
}
public void setDecodeLineFeed(final boolean decodeLineFeed) {
checkUnlocked();
this.decodeLineFeed = decodeLineFeed;
}
@Override
public Map<String, String> getMimeTypes() {
return mimeTypes;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("TobagoConfigImpl{");
builder.append("\nsupportedThemes=[");
for (final Theme supportedTheme : supportedThemes) {
builder.append(supportedTheme.getName());
builder.append(", ");
}
builder.append("], \ndefaultTheme=");
builder.append(defaultTheme != null ? defaultTheme.getName() : null);
builder.append(", \navailableThemes=");
builder.append(availableThemes.keySet());
builder.append(", \ncreateSessionSecret=");
builder.append(createSessionSecret);
builder.append(", \ncheckSessionSecret=");
builder.append(checkSessionSecret);
builder.append(", \npreventFrameAttacks=");
builder.append(preventFrameAttacks);
builder.append(", \ncontentSecurityPolicy=");
builder.append(contentSecurityPolicy);
builder.append(", \nsecurityAnnotation=");
builder.append(securityAnnotation);
builder.append(", \nsetNosniffHeader=");
builder.append(setNosniffHeader);
builder.append(", \ndefaultValidatorInfo=");
builder.append(defaultValidatorInfo);
builder.append(", \nsanitizer=");
builder.append(sanitizer);
builder.append(", \ndecodeLineFeed=");
builder.append(decodeLineFeed);
// to see only different (ignore alternative names for the same theme)
builder.append(", \nthemes=");
final Set<Theme> all = new HashSet<>(availableThemes.values());
builder.append(all);
builder.append(", \nmimeTypes=");
builder.append(mimeTypes);
builder.append('}');
return builder.toString();
}
}