/*
* 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.ViewAccessScoped;
import org.apache.deltaspike.core.impl.scope.window.WindowContextImpl;
import org.apache.deltaspike.core.spi.scope.viewaccess.ViewAccessContextManager;
import org.apache.deltaspike.core.util.context.AbstractContext;
import org.apache.deltaspike.core.util.context.ContextualInstanceInfo;
import org.apache.deltaspike.core.util.context.ContextualStorage;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.Typed;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.PassivationCapable;
import java.lang.annotation.Annotation;
import java.util.Map;
@Typed()
public class ViewAccessContext extends AbstractContext implements ViewAccessContextManager
{
private static final String KEY = "VAS"; //TODO re-visit key (e.g. view-id instead of using one big storage)
private final BeanManager beanManager;
private final WindowContextImpl windowContext;
private ViewAccessBeanHolder viewAccessBeanHolder;
private ViewAccessBeanAccessHistory viewAccessBeanAccessHistory;
private ViewAccessViewHistory viewAccessViewHistory;
public ViewAccessContext(BeanManager beanManager, WindowContextImpl windowContext)
{
super(beanManager);
this.beanManager = beanManager;
this.windowContext = windowContext;
}
public void init(ViewAccessBeanHolder viewAccessBeanHolder,
ViewAccessBeanAccessHistory viewAccessBeanAccessHistory,
ViewAccessViewHistory viewAccessViewHistory)
{
this.viewAccessBeanHolder = viewAccessBeanHolder;
this.viewAccessBeanAccessHistory = viewAccessBeanAccessHistory;
this.viewAccessViewHistory = viewAccessViewHistory;
}
@Override
public <T> T get(Contextual<T> bean)
{
try
{
return super.get(bean);
}
finally
{
if (bean instanceof PassivationCapable)
{
PassivationCapable pc = (PassivationCapable) bean;
viewAccessBeanAccessHistory.getAccessedBeans().add(pc.getId());
}
}
}
@Override
public <T> T get(Contextual<T> bean, CreationalContext<T> creationalContext)
{
try
{
return super.get(bean, creationalContext);
}
finally
{
if (bean instanceof PassivationCapable)
{
PassivationCapable pc = (PassivationCapable) bean;
viewAccessBeanAccessHistory.getAccessedBeans().add(pc.getId());
}
}
}
@Override
protected ContextualStorage getContextualStorage(Contextual<?> contextual, boolean createIfNotExist)
{
return this.viewAccessBeanHolder.getContextualStorage(this.beanManager, KEY, 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 void onProcessingViewFinished(String view)
{
close(view, false);
}
public void close(String view, boolean force)
{
// ignore if WindowContext isn't active - our ViewAccessViewHistory is WindowScoped
if (!windowContext.isActive())
{
return;
}
// destroy beans only if the view has been changed
if (force || !view.equals(viewAccessViewHistory.getLastView()))
{
viewAccessViewHistory.setLastView(view);
destroyExpiredBeans(force);
}
// clear history after each rendering process
viewAccessBeanAccessHistory.getAccessedBeans().clear();
}
private void destroyExpiredBeans(boolean force)
{
ContextualStorage storage = viewAccessBeanHolder.getContextualStorage(beanManager, KEY, false);
if (storage != null)
{
for (Map.Entry<Object, ContextualInstanceInfo<?>> storageEntry : storage.getStorage().entrySet())
{
if (force || !viewAccessBeanAccessHistory.getAccessedBeans().contains((String) storageEntry.getKey()))
{
Contextual bean = storage.getBean(storageEntry.getKey());
AbstractContext.destroyBean(bean, storageEntry.getValue());
storage.getStorage().remove(storageEntry.getKey()); //ok due to ConcurrentHashMap
}
}
}
}
@Override
public void close()
{
close(null, true);
}
}