Repository: deltaspike Updated Branches: refs/heads/master 6d1278201 -> 2983608b2
DELTASPIKE-487 ViewAccessScoped prototype Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/2983608b Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/2983608b Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/2983608b Branch: refs/heads/master Commit: 2983608b213933b18319ea40ddb16e00919c7a68 Parents: 6d12782 Author: tandraschko <[email protected]> Authored: Thu Feb 27 22:39:46 2014 +0100 Committer: tandraschko <[email protected]> Committed: Thu Feb 27 22:39:46 2014 +0100 ---------------------------------------------------------------------- .../core/api/scope/ViewAccessScoped.java | 45 ++++++ .../impl/scope/DeltaSpikeContextExtension.java | 18 ++- .../scope/viewaccess/ViewAccessContext.java | 149 +++++++++++++++++++ .../viewaccess/ViewAccessScopedBeanHistory.java | 71 +++++++++ .../viewaccess/ViewAccessScopedBeanHolder.java | 28 ++++ .../request/DeltaSpikeLifecycleWrapper.java | 15 +- 6 files changed, 324 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2983608b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/ViewAccessScoped.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/ViewAccessScoped.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/ViewAccessScoped.java new file mode 100644 index 0000000..a42901e --- /dev/null +++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/ViewAccessScoped.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 + * + * 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 org.apache.deltaspike.core.api.scope; + +import javax.enterprise.context.NormalScope; +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * The scope is active as long as it's bean is accessed by a view. + * Basically @ViewAccessScoped is a DeltaSpike Conversation which + * automatically gets ended when the next view tree gets restored + * without hitting the bean. + */ +@Target( { METHOD,TYPE,FIELD } ) +@Retention(RUNTIME) +@Inherited +@Documented +@NormalScope(passivating = true) +public @interface ViewAccessScoped +{ +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2983608b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java index 536866b..dfddff5 100644 --- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java +++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java @@ -28,6 +28,9 @@ import javax.enterprise.inject.spi.Extension; import org.apache.deltaspike.core.api.provider.BeanProvider; import org.apache.deltaspike.core.impl.scope.conversation.ConversationBeanHolder; import org.apache.deltaspike.core.impl.scope.conversation.GroupedConversationContext; +import org.apache.deltaspike.core.impl.scope.viewaccess.ViewAccessScopedBeanHistory; +import org.apache.deltaspike.core.impl.scope.viewaccess.ViewAccessScopedBeanHolder; +import org.apache.deltaspike.core.impl.scope.viewaccess.ViewAccessContext; import org.apache.deltaspike.core.impl.scope.window.WindowBeanHolder; import org.apache.deltaspike.core.impl.scope.window.WindowContextImpl; import org.apache.deltaspike.core.impl.scope.window.WindowIdHolder; @@ -41,8 +44,8 @@ import org.apache.deltaspike.core.util.ClassDeactivationUtils; public class DeltaSpikeContextExtension implements Extension, Deactivatable { private WindowContextImpl windowContext; - private GroupedConversationContext conversationContext; + private ViewAccessContext viewAccessScopedContext; private Boolean isActivated = true; @@ -60,8 +63,10 @@ public class DeltaSpikeContextExtension implements Extension, Deactivatable windowContext = new WindowContextImpl(beanManager); conversationContext = new GroupedConversationContext(beanManager, windowContext); + viewAccessScopedContext = new ViewAccessContext(beanManager, windowContext); afterBeanDiscovery.addContext(windowContext); afterBeanDiscovery.addContext(conversationContext); + afterBeanDiscovery.addContext(viewAccessScopedContext); } /** @@ -87,6 +92,12 @@ public class DeltaSpikeContextExtension implements Extension, Deactivatable ConversationBeanHolder conversationBeanHolder = BeanProvider.getContextualReference(beanManager, ConversationBeanHolder.class, false); conversationContext.init(conversationBeanHolder); + + ViewAccessScopedBeanHolder viewAccessScopedBeanHolder = + BeanProvider.getContextualReference(beanManager, ViewAccessScopedBeanHolder.class, false); + ViewAccessScopedBeanHistory viewAccessScopedBeanHistory = + BeanProvider.getContextualReference(beanManager, ViewAccessScopedBeanHistory.class, false); + viewAccessScopedContext.init(viewAccessScopedBeanHolder, windowIdHolder, viewAccessScopedBeanHistory); } public WindowContextImpl getWindowContext() @@ -98,4 +109,9 @@ public class DeltaSpikeContextExtension implements Extension, Deactivatable { return conversationContext; } + + public ViewAccessContext getViewAccessScopedContext() + { + return viewAccessScopedContext; + } } http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2983608b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessContext.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessContext.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessContext.java new file mode 100644 index 0000000..ba6d90c --- /dev/null +++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessContext.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 + * + * 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 org.apache.deltaspike.core.impl.scope.viewaccess; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.List; +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.BeanManager; +import javax.enterprise.inject.spi.PassivationCapable; +import org.apache.deltaspike.core.api.scope.ViewAccessScoped; +import org.apache.deltaspike.core.impl.scope.window.WindowContextImpl; +import org.apache.deltaspike.core.impl.scope.window.WindowIdHolder; +import org.apache.deltaspike.core.util.context.AbstractContext; +import org.apache.deltaspike.core.util.context.ContextualInstanceInfo; +import org.apache.deltaspike.core.util.context.ContextualStorage; + +public class ViewAccessContext extends AbstractContext +{ + private final BeanManager beanManager; + private final WindowContextImpl windowContext; + + private WindowIdHolder windowIdHolder; + private ViewAccessScopedBeanHolder viewAccessScopedBeanHolder; + private ViewAccessScopedBeanHistory viewAccessScopedBeanHistory; + + public ViewAccessContext(BeanManager beanManager, WindowContextImpl windowContext) + { + super(beanManager); + + this.beanManager = beanManager; + this.windowContext = windowContext; + } + + public void init(ViewAccessScopedBeanHolder viewAccessScopedBeanHolder, WindowIdHolder windowIdHolder, + ViewAccessScopedBeanHistory viewAccessScopedBeanHistory) + { + this.viewAccessScopedBeanHolder = viewAccessScopedBeanHolder; + this.windowIdHolder = windowIdHolder; + this.viewAccessScopedBeanHistory = viewAccessScopedBeanHistory; + } + + @Override + public <T> T get(Contextual<T> bean) + { + PassivationCapable pc = (PassivationCapable) bean; + viewAccessScopedBeanHistory.getAccessedBeans().add(pc.getId()); + + return super.get(bean); + } + + @Override + public <T> T get(Contextual<T> bean, CreationalContext<T> creationalContext) + { + PassivationCapable pc = (PassivationCapable) bean; + viewAccessScopedBeanHistory.getAccessedBeans().add(pc.getId()); + + return super.get(bean, creationalContext); + } + + @Override + protected ContextualStorage getContextualStorage(Contextual<?> contextual, boolean createIfNotExist) + { + String windowId = getCurrentWindowId(); + if (windowId == null) + { + throw new ContextNotActiveException("WindowContext: no windowId set for the current Thread yet!"); + } + + return this.viewAccessScopedBeanHolder.getContextualStorage(this.beanManager, windowId, createIfNotExist); + } + + @Override + public Class<? extends Annotation> getScope() + { + return ViewAccessScoped.class; + } + + @Override + public boolean isActive() + { + return this.windowContext.isActive(); //autom. active once a window is active + } + + public String getCurrentWindowId() + { + return windowIdHolder.getWindowId(); + } + + public void onRenderingFinished(String view) + { + if (!view.equals(viewAccessScopedBeanHistory.getLastView())) + { + viewAccessScopedBeanHistory.setLastView(view); + + destroyExpiredBeans(); + + // clear list from last request + List<String> lastAccessedBeans = viewAccessScopedBeanHistory.getLastAccessedBeans(); + lastAccessedBeans.clear(); + + // move used beans from this request to last request + viewAccessScopedBeanHistory.setLastAccessedBeans(viewAccessScopedBeanHistory.getAccessedBeans()); + viewAccessScopedBeanHistory.setAccessedBeans(lastAccessedBeans); + } + } + + private void destroyExpiredBeans() + { + List<String> usedBeans = new ArrayList<String>(); + usedBeans.addAll(viewAccessScopedBeanHistory.getAccessedBeans()); + usedBeans.addAll(viewAccessScopedBeanHistory.getLastAccessedBeans()); + + ContextualStorage storage = + viewAccessScopedBeanHolder.getContextualStorage(beanManager, getCurrentWindowId(), false); + if (storage != null) + { + for (Map.Entry<Object, ContextualInstanceInfo<?>> storageEntry : storage.getStorage().entrySet()) + { + if (!usedBeans.contains((String) storageEntry.getKey())) + { + Contextual bean = storage.getBean(storageEntry.getKey()); + AbstractContext.destroyBean(bean, storageEntry.getValue()); + storage.getStorage().remove(storageEntry.getKey()); //ok due to ConcurrentHashMap + break; + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2983608b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessScopedBeanHistory.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessScopedBeanHistory.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessScopedBeanHistory.java new file mode 100644 index 0000000..b422f07 --- /dev/null +++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessScopedBeanHistory.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 + * + * 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 org.apache.deltaspike.core.impl.scope.viewaccess; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import org.apache.deltaspike.core.api.scope.WindowScoped; + +@WindowScoped +public class ViewAccessScopedBeanHistory implements Serializable +{ + private static final long serialVersionUID = 3617603930728148927L; + + private List<String> accessedBeans; + private List<String> lastAccessedBeans; + private String lastView; + + public ViewAccessScopedBeanHistory() + { + accessedBeans = new ArrayList<String>(); + lastAccessedBeans = new ArrayList<String>(); + } + + public List<String> getAccessedBeans() + { + return accessedBeans; + } + + public void setAccessedBeans(List<String> accessedBeans) + { + this.accessedBeans = accessedBeans; + } + + public List<String> getLastAccessedBeans() + { + return lastAccessedBeans; + } + + public void setLastAccessedBeans(List<String> lastAccessedBeans) + { + this.lastAccessedBeans = lastAccessedBeans; + } + + public String getLastView() + { + return lastView; + } + + public void setLastView(String lastView) + { + this.lastView = lastView; + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2983608b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessScopedBeanHolder.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessScopedBeanHolder.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessScopedBeanHolder.java new file mode 100644 index 0000000..87279df --- /dev/null +++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/viewaccess/ViewAccessScopedBeanHolder.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 + * + * 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 org.apache.deltaspike.core.impl.scope.viewaccess; + +import org.apache.deltaspike.core.api.scope.WindowScoped; +import org.apache.deltaspike.core.impl.scope.AbstractBeanHolder; + +@WindowScoped +public class ViewAccessScopedBeanHolder extends AbstractBeanHolder<String> +{ + private static final long serialVersionUID = 6313403410718143908L; +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2983608b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java index 864b867..7e610f1 100644 --- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java +++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java @@ -26,6 +26,8 @@ import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow; import javax.faces.context.FacesContext; import javax.faces.event.PhaseListener; import javax.faces.lifecycle.Lifecycle; +import org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension; +import org.apache.deltaspike.core.impl.scope.viewaccess.ViewAccessContext; class DeltaSpikeLifecycleWrapper extends Lifecycle { @@ -35,6 +37,7 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle private ClientWindow clientWindow; private WindowContext windowContext; + private DeltaSpikeContextExtension contextExtension; private volatile Boolean initialized; @@ -106,6 +109,15 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle public void render(FacesContext facesContext) { this.wrapped.render(facesContext); + + if (!facesContext.isPostback() && facesContext.getViewRoot() != null) + { + ViewAccessContext viewAccessContext = contextExtension.getViewAccessScopedContext(); + if (viewAccessContext != null) + { + viewAccessContext.onRenderingFinished(facesContext.getViewRoot().getViewId()); + } + } } private void broadcastInitializedJsfRequestEvent(FacesContext facesContext) @@ -137,7 +149,8 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle clientWindow = BeanProvider.getContextualReference(ClientWindow.class, true); windowContext = BeanProvider.getContextualReference(WindowContext.class, true); - + contextExtension = BeanProvider.getContextualReference(DeltaSpikeContextExtension.class, true); + this.initialized = true; } }
