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

org.efaps.util.cache.AbstractCache Maven / Gradle / Ivy

/*
 * Copyright 2003 - 2013 The eFaps Team
 *
 * Licensed 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.
 *
 * Revision:        $Rev: 8848 $
 * Last Changed:    $Date: 2013-02-19 10:49:59 -0500 (Tue, 19 Feb 2013) $
 * Last Changed By: $Author: [email protected] $
 */

package org.efaps.util.cache;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

The class is used to cache three not independent information which are * completely defined once but needed many times within eFaps. An example * is to load all types at startup and access the cached * data instead of reading the cached information each time they are * needed.

*

If a reload of the cache is needed, the cached object could be accessed, * but returns the "old" values until the old cache is replaced by * the new read values.

*

The class is thread save, but a cached instance could be accessed much * faster than a synchronized hash map.

* * @author The eFaps Team * @param class implementing CacheObjectInterface * @version $Id: AbstractCache.java 8848 2013-02-19 15:49:59Z [email protected] $ */ public abstract class AbstractCache { /** * Logging instance used to give logging information of this class. */ private static final Logger LOG = LoggerFactory.getLogger(AbstractCache.class); /** * Set that stores all initialized Caches. */ private static Set> CACHES = Collections.synchronizedSet(new HashSet>()); /** * The map holds all cached data instances by Id. Because of the * double-checked locking idiom, the instance variable is defined * volatile. * * @see #get(Long) */ private volatile Map cache4Id = null; /** * The map holds all cached data instances by Name. Because of the * double-checked locking idiom, the instance variable is defined * volatile. * * @see #get(String) */ private volatile Map cache4Name = null; /** * The map holds all cached data instances by UUID. Because of the * double-checked locking idiom, the instance variable is defined * volatile. * * @see #get(UUID) */ private volatile Map cache4UUID = null; /** * Stores the class name of the class that initialized this cache. */ private String initializer; /** * Constructor adding this Cache to the set of Caches. */ protected AbstractCache() { AbstractCache.CACHES.add(this); } /** * Returns for given key id the cached object from the cache4Id cache. If * the cache was not initialized yet, null is returned. * * @see #getCache4Id() * @param _id id of the searched cached object * @return cached object * */ public T get(final long _id) { return getCache4Id() == null ? null : getCache4Id().get(new Long(_id)); } /** * Returns for given key id the cached object from the cache4Id cache. If * the cache was not initialized yet, null is returned. * * @see #getCache4Name() * @param _name name the cached object * @return cached object */ public T get(final String _name) { return getCache4Name() == null ? null : getCache4Name().get(_name); } /** * Returns for given key id the cached object from the cache4Id cache. If * the cache was not initialized yet, null is returned. * * @see #getCache4UUID() * @param _uuid UUID of the cached object * @return cached object * */ public T get(final UUID _uuid) { return getCache4UUID() == null ? null : getCache4UUID().get(_uuid); } /** * Add an object to this Cache. This method should only be used to add some * objects, due to the reason that it is very slow!!! Normally the values * should be added by using abstract method * {@link #readCache(Map, Map, Map)}. * * @param _object Object to be added */ public void addObject(final T _object) { final Map newCache4Id = getNewCache4Id(); final Map newCache4Name = getNewCache4Name(); final Map newCache4UUID = getNewCache4UUID(); if (getCache4Id() != null) { newCache4Id.putAll(getCache4Id()); } if (getCache4Name() != null) { newCache4Name.putAll(getCache4Name()); } if (getCache4UUID() != null) { newCache4UUID.putAll(getCache4UUID()); } newCache4Id.put(_object.getId(), _object); newCache4Name.put(_object.getName(), _object); newCache4UUID.put(_object.getUUID(), _object); // replace old cache with new values // it is thread save because of volatile setCache4Id(newCache4Id); setCache4Name(newCache4Name); setCache4UUID(newCache4UUID); } /** * The method tests, if the cache has stored some entries. * * @return true if the cache has some entries, otherwise * false */ public boolean hasEntries() { return (getCache4Id() != null && !getCache4Id().isEmpty()) || (getCache4Name() != null && !getCache4Name().isEmpty()) || (getCache4UUID() != null && !getCache4UUID().isEmpty()); } /** * The method initialize the cache. * * @param _initializer class name of the class initializing * */ public void initialize(final Class _initializer) { this.initializer = _initializer.getName(); synchronized (this) { try { readCache(); } catch (final CacheReloadException e) { AbstractCache.LOG.error("Unexpected error while initializing Cache for " + getClass(), e); } } } /** * The complete cache is read and then replaces the current stored values * in the cache. The cache must be read in this order: *
    *
  • create new cache map
  • *
  • read cache in the new cache map
  • *
  • replace old cache map with the new cache map
  • *
* This order is imported, otherwise *
    *
  • if the cache initialized first time, the cache is not * null and returns then wrong values
  • *
  • existing and read values could not be read while a reload is * done
  • *
* * @throws CacheReloadException if the cache could not be read (the * exception is also written into the error * log) */ private void readCache() throws CacheReloadException { // if cache is not initialized, the correct order is required! // otherwise the cache is not null and returns wrong values! final Map newCache4Id = getNewCache4Id(); final Map newCache4Name = getNewCache4Name(); final Map newCache4UUID = getNewCache4UUID(); try { readCache(newCache4Id, newCache4Name, newCache4UUID); } catch (final CacheReloadException e) { AbstractCache.LOG.error("Read Cache for " + getClass() + " failed", e); throw e; //CHECKSTYLE:OFF } catch (final Exception e) { //CHECKSTYLE:ON AbstractCache.LOG.error("Unexpected error while reading Cache for " + getClass(), e); throw new CacheReloadException("Unexpected error while reading Cache " + "for " + getClass(), e); } // replace old cache with new values // it is thread save because of volatile this.cache4Id = newCache4Id; this.cache4Name = newCache4Name; this.cache4UUID = newCache4UUID; } /** * Method to fill this cache with objects. * * @param _newCache4Id cache for id * @param _newCache4Name cache for name * @param _newCache4UUID cache for UUID * @throws CacheReloadException on error during reading */ protected abstract void readCache(final Map _newCache4Id, final Map _newCache4Name, final Map _newCache4UUID) throws CacheReloadException; /** * Method to get a new empty Map for the id Cache. * The method is implemented to provide the possibility to use * different Map types in the extending classes. * * @return new empty Instance of a HashMap */ protected Map getNewCache4Id() { return new HashMap(); } /** * Method to get a new empty Map for the id Cache. * The method is implemented to provide the possibility to use * different Map types in the extending classes. * * @return new empty Instance of a HashMap */ protected Map getNewCache4Name() { return new HashMap(); } /** * Method to get a new empty Map for the id Cache. * The method is implemented to provide the possibility to use * different Map types in the extending classes. * * @return new empty Instance of a HashMap */ protected Map getNewCache4UUID() { return new HashMap(); } /** * Getter method for instance variable {@link #cache4Id}. * * @return value of instance variable {@link #cache4Id} */ public Map getCache4Id() { return this.cache4Id; } /** * Setter method for instance variable {@link #cache4Id}. * * @param _cache4Id value for instance variable {@link #cache4Id} */ protected void setCache4Id(final Map _cache4Id) { this.cache4Id = _cache4Id; } /** * Getter method for instance variable {@link #cache4Name}. * * @return value of instance variable {@link #cache4Name} */ protected Map getCache4Name() { return this.cache4Name; } /** * Setter method for instance variable {@link #cache4Name}. * * @param _cache4Name value for instance variable {@link #cache4Name} */ protected void setCache4Name(final Map _cache4Name) { this.cache4Name = _cache4Name; } /** * Setter method for instance variable {@link #cache4UUID}. * * @param _cache4uuid value for instance variable {@link #cache4UUID} */ protected void setCache4UUID(final Map _cache4uuid) { this.cache4UUID = _cache4uuid; } /** * Getter method for instance variable {@link #cache4UUID}. * * @return value of instance variable {@link #cache4UUID} */ protected Map getCache4UUID() { return this.cache4UUID; } /** * Getter method for instance variable {@link #initializer}. * * @return value of instance variable {@link #initializer} */ public String getInitializer() { return this.initializer; } /** * Clear all values of this Cache. */ public void clear() { if (getCache4Id() != null) { getCache4Id().clear(); } if (getCache4Name() != null) { getCache4Name().clear(); } if (getCache4UUID() != null) { getCache4UUID().clear(); } } /** * The static method removes all values in all caches. */ public static void clearCaches() { synchronized (AbstractCache.CACHES) { for (final AbstractCache cache : AbstractCache.CACHES) { cache.getCache4Id().clear(); cache.getCache4Name().clear(); cache.getCache4UUID().clear(); } } } /** * Getter method for variable {@link #CACHES}. * * @return value of variable {@link #CACHES} */ public static Set> getCaches() { return AbstractCache.CACHES; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy