Skip to content
This repository has been archived by the owner on Apr 8, 2019. It is now read-only.

Commit

Permalink
GTNPORTAL-2896 Introduce @PortletLifecycleScoped and @PortletRedispla…
Browse files Browse the repository at this point in the history
…yScoped to support portlet lifecycle in CDI portlets
  • Loading branch information
nscavell authored and kenfinnigan committed May 9, 2013
1 parent b23ad43 commit 44fdced
Show file tree
Hide file tree
Showing 24 changed files with 1,397 additions and 206 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*
* 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.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;
import org.gatein.cdi.contexts.beanstore.serial.SerializableBeanStoreInstance;

/**
* @author <a href="mailto:nscavell@redhat.com">Nick Scavelli</a>
*/
public abstract class AbstractCDIPortletContext implements CDIPortletContext {

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();
} 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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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 javax.enterprise.context.spi.Context;
import javax.servlet.http.HttpServletRequest;

/**
* @author <a href="mailto:nscavell@redhat.com">Nick Scavelli</a>
*/
public interface CDIPortletContext extends Context {

void transition(HttpServletRequest request, String windowId, PortletRequestLifecycle.State state);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Extension;

/**
* @author <a href="mailto:nscavell@redhat.com">Nick Scavelli</a>
*/
public class CDIPortletContextExtension implements Extension {

private Collection<CDIPortletContext> contexts;

@SuppressWarnings("unused")
public void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery) {
List<CDIPortletContext> contextList = new ArrayList<CDIPortletContext>(2);
contextList.add(new PortletLifecycleContextImpl());
contextList.add(new PortletRedisplayedContextImpl());

for (CDIPortletContext context : contextList) {
afterBeanDiscovery.addContext(context);
}
contexts = Collections.unmodifiableCollection(contextList);
}

@SuppressWarnings("unchecked")
public <T extends CDIPortletContext> T getContext(Class<T> type) {
if (type == null) return null;

for (CDIPortletContext context : contexts) {
if (type.isAssignableFrom(context.getClass())) {
return (T) context;
}
}

return null;
}

public Collection<CDIPortletContext> getContexts() {
Collection<CDIPortletContext> collection = contexts;
if (collection == null) {
return Collections.emptyList();
}
return collection;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* 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.
*
Expand All @@ -22,54 +22,60 @@

package org.gatein.cdi.contexts;

import org.exoplatform.portal.pc.aspects.PortletLifecyclePhaseInterceptor;

import javax.portlet.PortletRequest;
import javax.inject.Inject;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import static org.exoplatform.portal.pc.aspects.PortletLifecyclePhaseInterceptor.*;

/**
* @author <a href="mailto:nscavell@redhat.com">Nick Scavelli</a>
*/
public class CDIServletListener implements ServletRequestListener {
public class CDIServletListener implements ServletRequestListener, HttpSessionListener {

@Inject
private CDIPortletContextExtension extension;

@Override
public void requestInitialized(ServletRequestEvent event) {
boolean attached = PortletLifecycleContext.isAttached();
if (!attached) {
PortletLifecycleContext.attach();
} else {
if (isActionRequest()) {
// Unlikely to occur, but just as a precaution
PortletLifecycleContext.detach();
PortletLifecycleContext.attach();
final HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
final String windowId = currentWindowId();
final String phase = currentPhase();

// The phase is null when we access the application registry, so we don't need to do anything
if (phase != null) {
for (CDIPortletContext context : extension.getContexts()) {
context.transition(request, windowId, PortletRequestLifecycle.State.starting(phase));
}
}
}

@Override
public void requestDestroyed(ServletRequestEvent event) {
boolean attached = PortletLifecycleContext.isAttached();
if (attached) {
if (isRenderRequest() || isResourceRequest()) {
PortletLifecycleContext.detach();
final HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
final String windowId = currentWindowId();
final String phase = currentPhase();

// The phase is null when we access the application registry, so we don't need to do anything
if (phase != null) {
for (CDIPortletContext context : extension.getContexts()) {
context.transition(request, windowId, PortletRequestLifecycle.State.ending(phase));
}
}
}

private boolean isActionRequest() {
return PortletRequest.ACTION_PHASE.equals(PortletLifecyclePhaseInterceptor.getLifecyclePhase());
}

private boolean isEventRequest() {
return PortletRequest.EVENT_PHASE.equals(PortletLifecyclePhaseInterceptor.getLifecyclePhase());
}

private boolean isRenderRequest() {
return PortletRequest.RENDER_PHASE.equals(PortletLifecyclePhaseInterceptor.getLifecyclePhase());
@Override
public void sessionCreated(HttpSessionEvent event) {
}

private boolean isResourceRequest() {
return PortletRequest.RESOURCE_PHASE.equals(PortletLifecyclePhaseInterceptor.getLifecyclePhase());
@Override
public void sessionDestroyed(HttpSessionEvent event) {
PortletRedisplayedContext context = extension.getContext(PortletRedisplayedContext.class);
if (context != null) {
context.dissociate(event.getSession());
}
}
}

0 comments on commit 44fdced

Please sign in to comment.