/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.gatein.cdi.contexts;
import java.util.HashMap;
import java.util.Map;
import javax.enterprise.context.ContextNotActiveException;
import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.PassivationCapable;
import org.exoplatform.portal.pc.aspects.PortletLifecyclePhaseInterceptor;
import org.gatein.cdi.contexts.beanstore.BeanStore;
import org.gatein.cdi.contexts.beanstore.BeanStoreInstance;
import org.gatein.cdi.contexts.beanstore.LockedBean;
/**
* @author <a href="mailto:nscavell@redhat.com">Nick Scavelli</a>
* @author <a href="http://community.jboss.org/people/kenfinni">Ken Finnigan</a>
*/
public abstract class AbstractCDIPortletContext implements Context {
private final ThreadLocal<BeanStore> beanStore;
private final ThreadLocal<Map<String, PortletRequestLifecycle>> lifecycles;
private final ThreadLocal<PortletRequestLifecycle> currentLifecycle;
private final boolean multithreaded;
protected AbstractCDIPortletContext(boolean multithreaded) {
this.multithreaded = multithreaded;
this.beanStore = new ThreadLocal<BeanStore>();
this.lifecycles = new ThreadLocal<Map<String, PortletRequestLifecycle>>();
this.currentLifecycle = new ThreadLocal<PortletRequestLifecycle>();
}
@Override
public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
if (!isActive()) {
throw new ContextNotActiveException();
}
BeanStore beanStore = getBeanStore();
if (beanStore == null) {
return null;
}
String id = getId(contextual);
BeanStoreInstance<T> beanInstance = beanStore.getBean(id);
if (beanInstance != null) {
return beanInstance.getInstance();
} else if (creationalContext != null) {
LockedBean lock = null;
try {
if (multithreaded) {
lock = beanStore.lock(id);
beanInstance = beanStore.getBean(id);
if (beanInstance != null) {
return beanInstance.getInstance();
}
}
T instance = contextual.create(creationalContext);
if (instance != null) {
beanInstance = new SerializableBeanStoreInstance<T>(contextual, instance, creationalContext);
beanStore.put(id, beanInstance);
}
return instance;
} finally {
if (lock != null) {
lock.unlock();
}
}
} else {
return null;
}
}
@Override
public <T> T get(Contextual<T> contextual) {
return get(contextual, null);
}
@Override
public boolean isActive() {
return currentLifecycle.get() != null;
}
protected void setCurrentLifecycle(String windowId, PortletRequestLifecycle lifecycle) {
if (lifecycle == null) {
currentLifecycle.remove();
Map<String, PortletRequestLifecycle> map = lifecycles.get();
if (null != map) {
map.remove(windowId);
}
} else {
currentLifecycle.set(lifecycle);
Map<String, PortletRequestLifecycle> map = lifecycles.get();
if (map == null) {
map = new HashMap<String, PortletRequestLifecycle>();
lifecycles.set(map);
}
map.put(windowId, lifecycle);
}
}
protected PortletRequestLifecycle getLifecycle(String windowId) {
Map<String, PortletRequestLifecycle> map = lifecycles.get();
if (map == null) {
map = new HashMap<String, PortletRequestLifecycle>();
lifecycles.set(map);
}
return map.get(windowId);
}
protected BeanStore getBeanStore() {
return beanStore.get();
}
protected void setBeanStore(BeanStore beanStore) {
if (beanStore == null) {
this.beanStore.remove();
} else {
this.beanStore.set(beanStore);
}
}
protected void destroy(String windowId) {
try {
BeanStore store = getBeanStore();
if (store != null) {
store.destroy(windowId);
}
} finally {
Map<String, PortletRequestLifecycle> map = lifecycles.get();
if (map != null) {
map.remove(windowId);
if (map.isEmpty()) {
lifecycles.remove();
}
}
}
}
protected void destroy() {
try {
BeanStore store = getBeanStore();
if (store != null) {
store.destroy();
}
} finally {
cleanup();
}
}
protected void cleanup() {
lifecycles.remove();
beanStore.remove();
}
//TODO: Need to revisit this implementation
private static String getId(Contextual contextual) {
String id;
if (contextual instanceof PassivationCapable) {
id = ((PassivationCapable) contextual).getId();
} else {
id = "" + contextual.hashCode();
}
return windowId() + "#" + id;
}
private static String windowId() {
return PortletLifecyclePhaseInterceptor.currentWindowId();
}
}