/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal.utils.cache;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.Properties;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.event.CacheEventListener;
import net.sf.ehcache.event.CacheEventListenerAdapter;
import net.sf.ehcache.event.CacheEventListenerFactory;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/** Returns references to Spring configured {@link CacheEventListener}s */
@Service
public class SpringCacheEventListenerFactory extends CacheEventListenerFactory
implements DisposableBean {
public static final String BEAN_NAME = "beanName";
private static final Logger LOGGER =
LoggerFactory.getLogger(SpringCacheEventListenerFactory.class);
private static final CacheEventListener NOOP_CACHE_EVENT_LISTENER =
new CacheEventListenerAdapter();
private static volatile Map<String, CacheEventListener> cacheEventListeners;
@Autowired
public void setCacheEventListeners(Map<String, CacheEventListener> cacheEventListeners) {
SpringCacheEventListenerFactory.cacheEventListeners =
ImmutableMap.copyOf(cacheEventListeners);
}
@Override
public void destroy() throws Exception {
cacheEventListeners = null;
}
@Override
public CacheEventListener createCacheEventListener(Properties properties) {
final String beanName = StringUtils.trimToNull(properties.getProperty(BEAN_NAME));
if (beanName == null) {
throw new IllegalArgumentException("The " + BEAN_NAME + " property must be set");
}
return new LazyCacheEventListener(beanName);
}
private static class LazyCacheEventListener implements CacheEventListener {
private final String beanName;
private CacheEventListener delegate;
public LazyCacheEventListener(String beanName) {
this.beanName = beanName;
}
/** Always resolves to the same delegate object, no need for thread-sync checks */
private CacheEventListener getDelegate() {
CacheEventListener d = this.delegate;
if (d == null) {
//Need a local reference here to avoid locking around cacheEventListeners reference changes
final Map<String, CacheEventListener> cel = cacheEventListeners;
if (cel == null) {
//either pre-init or post-destroy, return noop logger
return NOOP_CACHE_EVENT_LISTENER;
}
final CacheEventListener cacheEventListener = cel.get(beanName);
if (cacheEventListener == null) {
//If no listener is found just use the noop listener
LOGGER.warn(
"No CacheEventListener bean found for name '"
+ beanName
+ "', using NOOP CacheEventListener instead.");
d = NOOP_CACHE_EVENT_LISTENER;
} else {
d = cacheEventListener;
}
this.delegate = d;
}
return d;
}
@Override
public void notifyElementRemoved(Ehcache cache, Element element) throws CacheException {
this.getDelegate().notifyElementRemoved(cache, element);
}
@Override
public void notifyElementPut(Ehcache cache, Element element) throws CacheException {
this.getDelegate().notifyElementPut(cache, element);
}
@Override
public void notifyElementUpdated(Ehcache cache, Element element) throws CacheException {
this.getDelegate().notifyElementUpdated(cache, element);
}
@Override
public void notifyElementExpired(Ehcache cache, Element element) {
this.getDelegate().notifyElementExpired(cache, element);
}
@Override
public void notifyElementEvicted(Ehcache cache, Element element) {
this.getDelegate().notifyElementEvicted(cache, element);
}
@Override
public void notifyRemoveAll(Ehcache cache) {
this.getDelegate().notifyRemoveAll(cache);
}
@Override
public void dispose() {
this.getDelegate().dispose();
this.delegate = null;
}
@Override
public Object clone() throws CloneNotSupportedException {
return new LazyCacheEventListener(beanName);
}
}
}