/*
*
* * Copyright (c) 2016. David Sowerby
* *
* * 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.
*
*/
package uk.q3c.krail.core.guice.vsscope;
import com.google.common.collect.ImmutableList;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.servlet.SessionScoped;
import com.vaadin.server.VaadinSession;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.slf4j.Logger;
import java.util.HashMap;
import java.util.Map;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provides a Guice scope based on a {@link VaadinSession}. This was necessary because the standard
* {@link SessionScoped} will only work with a UI (and not things like Views, which where a session scope is most
* useful) if a UI has server push enabled. See https://github.com/davidsowerby/krail/issues/241
*
* @author David Sowerby 2014
*/
@SuppressFBWarnings("CD_CIRCULAR_DEPENDENCY")
public class VaadinSessionScope implements Scope {
private static Logger log = getLogger(VaadinSessionScope.class);
private static volatile VaadinSessionScope current;
private final Map<VaadinSession, Map<Key<?>, Object>> cache = new HashMap<>();
public VaadinSessionScope() {
super();
log.debug("creating VaadinSessionScope {}", this);
}
public static VaadinSessionScope getCurrent() {
// double-checked locking with volatile
VaadinSessionScope scope = current;
if (scope == null) {
synchronized (VaadinSessionScope.class) {
scope = current;
if (scope == null) {
current = new VaadinSessionScope();
scope = current;
}
}
}
return scope;
}
Map<Key<?>, Object> getScopedObjectMap(VaadinSession vaadinSession) {
// return an existing cache instance
if (cache.containsKey(vaadinSession)) {
Map<Key<?>, Object> scopedObjects = cache.get(vaadinSession);
log.debug("scope cache retrieved for VaadinSession: {}", vaadinSession);
return scopedObjects;
} else {
return createCacheEntry(vaadinSession);
}
}
private Map<Key<?>, Object> createCacheEntry(VaadinSession vaadinSession) {
Map<Key<?>, Object> sessionEntry = new HashMap<Key<?>, Object>();
cache.put(vaadinSession, sessionEntry);
log.debug("created a scope cache for VaadinSessionScope with key: {}", vaadinSession);
return sessionEntry;
}
public void startScope(VaadinSession vaadinSession) {
if (!cacheHasEntryFor(vaadinSession)) {
createCacheEntry(vaadinSession);
}
}
public boolean cacheHasEntryFor(VaadinSession vaadinSession) {
return cache.containsKey(vaadinSession);
}
public void releaseScope(VaadinSession vaadinSession) {
cache.remove(vaadinSession);
}
/**
* Removes all entries in the cache
*/
public void flush() {
cache.clear();
}
@Override
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
return new VaadinSessionScopeProvider<T>(this, key, unscoped);
}
public ImmutableList<VaadinSession> scopeKeys() {
return ImmutableList.copyOf(cache.keySet());
}
public boolean containsInstance(VaadinSession vaadinSession, Object containedInstance) {
return cache.get(vaadinSession)
.containsValue(containedInstance);
}
}