All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.faces.application.resource.ResourceCache Maven / Gradle / Ivy

There is a newer version: 4.1.1
Show newest version
/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.faces.application.resource;

import com.sun.faces.config.WebConfiguration;
import com.sun.faces.config.WebConfiguration.WebContextInitParameter;
import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.MultiKeyConcurrentHashMap;
import com.sun.faces.util.Util;

import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 

* This is the caching mechanism for caching ResourceInfo instances to * offset the cost of looking up the resource. *

* *

* This cache uses a background thread to check for modifications to the underlying * webapp or JAR files containing resources. This check is periodic, configurable * via context init param com.sun.faces.resourceUpdateCheckPeriod. Through * this config option, the cache can also be made static or completely disabled. * If the value of of this option is 0, then no check will be made * making the cache static. If value of this option is less than 0, * then no caching will be perfomed. Otherwise, the value of the option will * be the number of minutes between modification checks. *

*/ public class ResourceCache { private static final Logger LOGGER = FacesLogger.RESOURCE.getLogger(); /** * The ResourceInfo cache. */ private MultiKeyConcurrentHashMap resourceCache; /** * Resource check period in minutes. */ private long checkPeriod; // ------------------------------------------------------------ Constructors /** * Constructs a new ResourceCache. */ public ResourceCache() { this(WebConfiguration.getInstance()); } private ResourceCache(WebConfiguration config) { this(getCheckPeriod(config)); if (LOGGER.isLoggable(Level.FINE)) { ServletContext sc = config.getServletContext(); LOGGER.log(Level.FINE, "ResourceCache constructed for {0}. Check period is {1} minutes.", new Object[] { getServletContextIdentifier(sc), checkPeriod }); } } // this one is for unit tests ResourceCache(long period) { checkPeriod = ((period != -1) ? period * 1000L * 60L : -1); resourceCache = new MultiKeyConcurrentHashMap<>(30); } // ---------------------------------------------------------- Public Methods /** * Add the {@link ResourceInfo} to the internal cache. * * @param info resource metadata * * @param contracts the contracts * @return previous value associated with specified key, or null * if there was no mapping for key */ public ResourceInfo add(ResourceInfo info, List contracts) { Util.notNull("info", info); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Caching ResourceInfo: {0}", info.toString()); } ResourceInfoCheckPeriodProxy proxy = resourceCache.putIfAbsent(info.name, info.libraryName, info.localePrefix, new ArrayList(contracts), new ResourceInfoCheckPeriodProxy(info, checkPeriod)); return ((proxy != null) ? proxy.getResourceInfo() : null); } /** * @param name the resource name * @param libraryName the library name * @param localePrefix the locale prefix * @param contracts the contracts * @return the {@link ResourceInfo} associated with key * if any. */ public ResourceInfo get(String name, String libraryName, String localePrefix, List contracts) { Util.notNull("name", name); ResourceInfoCheckPeriodProxy proxy = resourceCache.get(name, libraryName, localePrefix, contracts); if (proxy != null && proxy.needsRefreshed()) { resourceCache.remove(name, libraryName, localePrefix, contracts); return null; } else { return ((proxy != null) ? proxy.getResourceInfo() : null); } } /** *

Empty the cache.

*/ public void clear() { resourceCache.clear(); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Cache Cleared"); } } // --------------------------------------------------------- Private Methods private static Long getCheckPeriod(WebConfiguration webConfig) { String val = webConfig.getOptionValue(WebContextInitParameter.ResourceUpdateCheckPeriod); try { return (Long.parseLong(val)); } catch (NumberFormatException nfe) { return Long.parseLong(WebContextInitParameter.ResourceUpdateCheckPeriod.getDefaultValue()); } } private static String getServletContextIdentifier(ServletContext context) { if (context.getMajorVersion() == 2 && context.getMinorVersion() < 5) { return context.getServletContextName(); } else { return context.getContextPath(); } } // ---------------------------------------------------------- Nested Classes private static final class ResourceInfoCheckPeriodProxy { private ResourceInfo resourceInfo; private Long checkTime; // -------------------------------------------------------- Constructors public ResourceInfoCheckPeriodProxy(ResourceInfo resourceInfo, long checkPeriod) { this.resourceInfo = resourceInfo; if (checkPeriod != -1L && (!(resourceInfo.getHelper() instanceof ClasspathResourceHelper))) { checkTime = System.currentTimeMillis() + checkPeriod; } } private boolean needsRefreshed() { return (checkTime != null && (checkTime < System.currentTimeMillis())); } private ResourceInfo getResourceInfo() { return resourceInfo; } } // END ResourceInfoCheckPeriodProxy } // END ResourceCache