Skip to content

Commit

Permalink
webui views: sysconfig to configure how much time we keep the v… (#1407)
Browse files Browse the repository at this point in the history
* Make `DefaultViewsRepositoryStorage`'s view expiration timeout configurable

metasfresh/metasfresh#6480

* Read viewExpirationTimeout from sysconfig

metasfresh/metasfresh#6480

* Change expiration timeout unit to Minutes from Hours

metasfresh/metasfresh#6480

* Remove redundant import

metasfresh/metasfresh#6480
  • Loading branch information
TheBestPessimist committed Apr 16, 2020
1 parent 90af899 commit 39f76f8
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 55 deletions.
@@ -1,6 +1,7 @@
package de.metas.ui.web.bankstatement_reconciliation;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -59,7 +60,7 @@ public class BankStatementReconciliationViewFactory implements IViewFactory, IVi
private final IMsgBL msgBL = Services.get(IMsgBL.class);
private final IADProcessDAO adProcessDAO = Services.get(IADProcessDAO.class);
private final BankStatementLineAndPaymentsToReconcileRepository rowsRepo;
private final DefaultViewsRepositoryStorage views = new DefaultViewsRepositoryStorage();
private final DefaultViewsRepositoryStorage views = new DefaultViewsRepositoryStorage(TimeUnit.HOURS.toMinutes(1));

public BankStatementReconciliationViewFactory(
@NonNull final BankStatementLineAndPaymentsToReconcileRepository rowsRepo)
Expand Down
@@ -1,5 +1,6 @@
package de.metas.ui.web.material.cockpit;

import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.compiere.model.I_M_Product;
Expand Down Expand Up @@ -48,7 +49,7 @@
@Service
public class MaterialCockpitViewsIndexStorage implements IViewsIndexStorage
{
private final DefaultViewsRepositoryStorage defaultViewsRepositoryStorage = new DefaultViewsRepositoryStorage();
private final DefaultViewsRepositoryStorage defaultViewsRepositoryStorage = new DefaultViewsRepositoryStorage(TimeUnit.HOURS.toMinutes(1));

public MaterialCockpitViewsIndexStorage()
{
Expand Down
Expand Up @@ -2,6 +2,7 @@

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.adempiere.exceptions.AdempiereException;
Expand Down Expand Up @@ -66,7 +67,7 @@ public class PaymentsViewFactory implements IViewFactory, IViewsIndexStorage

private final IMsgBL msgBL = Services.get(IMsgBL.class);
private final PaymentAndInvoiceRowsRepo rowsRepo;
private final DefaultViewsRepositoryStorage views = new DefaultViewsRepositoryStorage();
private final DefaultViewsRepositoryStorage views = new DefaultViewsRepositoryStorage(TimeUnit.HOURS.toMinutes(1));

public PaymentsViewFactory(
@NonNull final PaymentAndInvoiceRowsRepo rowsRepo)
Expand Down
@@ -1,15 +1,17 @@
package de.metas.ui.web.view;

import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalNotification;

import de.metas.logging.LogManager;
import de.metas.ui.web.view.event.ViewChangesCollector;
import de.metas.ui.web.window.datatypes.WindowId;
import lombok.NonNull;
import org.slf4j.Logger;

import javax.annotation.Nullable;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

/*
* #%L
Expand All @@ -36,10 +38,17 @@
// NOTE: don't add it to spring context! i.e. don't annotate it with @Component or similar
public final class DefaultViewsRepositoryStorage implements IViewsIndexStorage
{
private final Cache<ViewId, IView> views = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.HOURS)
.removalListener(notification -> onViewRemoved(notification))
.build();
private static transient final Logger logger = LogManager.getLogger(DefaultViewsRepositoryStorage.class);

private final Cache<ViewId, IView> views;

public DefaultViewsRepositoryStorage(final long viewExpirationTimeoutInMinutes)
{
views = CacheBuilder.newBuilder()
.expireAfterAccess(viewExpirationTimeoutInMinutes, TimeUnit.MINUTES)
.removalListener(this::onViewRemoved)
.build();
}

@Override
public WindowId getWindowId()
Expand All @@ -53,6 +62,7 @@ public void put(@NonNull final IView view)
views.put(view.getViewId(), view);
}

@Nullable
@Override
public IView getByIdOrNull(@NonNull final ViewId viewId)
{
Expand Down Expand Up @@ -85,6 +95,7 @@ public void closeById(@NonNull final ViewId viewId, @NonNull final ViewCloseActi
private void onViewRemoved(final RemovalNotification<Object, Object> notification)
{
final IView view = (IView)notification.getValue();
logger.debug("View <" + view.getViewId() + "> removed from cache. Cause: " + notification.getCause());
view.afterDestroy();
}

Expand Down
27 changes: 19 additions & 8 deletions src/main/java/de/metas/ui/web/view/IViewsIndexStorage.java
@@ -1,9 +1,10 @@
package de.metas.ui.web.view;

import java.util.stream.Stream;

import de.metas.ui.web.window.datatypes.WindowId;

import javax.annotation.Nullable;
import java.util.stream.Stream;

/*
* #%L
* metasfresh-webui-api
Expand All @@ -30,25 +31,35 @@
* Implementations of this interface are responsible of storing {@link IView} references for a particular window ID identified by {@link #getWindowId()}.
*
* @author metas-dev <dev@metasfresh.com>
*
*/
public interface IViewsIndexStorage
{
/** @return the window ID for whom this storage is storing the {@link IView} references. This method will be called by API on registration time. */
/**
* @return the window ID for whom this storage is storing the {@link IView} references. This method will be called by API on registration time.
*/
WindowId getWindowId();

/** Don't call it directly. Will be called by API. */
/**
* Don't call it directly. Will be called by API.
*/
default void setViewsRepository(final IViewsRepository viewsRepository)
{
}

/** Adds given view to the index. If the view already exists, it will be overridden. */
/**
* Adds given view to the index. If the view already exists, it will be overridden.
*/
void put(IView view);

/** @return the {@link IView} identified by <code>viewId</code> or <code>null</code> if not found. */
/**
* @return the {@link IView} identified by <code>viewId</code> or <code>null</code> if not found.
*/
@Nullable
IView getByIdOrNull(ViewId viewId);

/** Closes and removes the view identified by given <code>viewId</code>. If the view does not exist, the method will do nothing, i.e. not failing. */
/**
* Closes and removes the view identified by given <code>viewId</code>. If the view does not exist, the method will do nothing, i.e. not failing.
*/
void closeById(ViewId viewId, ViewCloseAction closeAction);

Stream<IView> streamAllViews();
Expand Down
74 changes: 38 additions & 36 deletions src/main/java/de/metas/ui/web/view/ViewsRepository.java
@@ -1,32 +1,9 @@
package de.metas.ui.web.view;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import javax.annotation.PostConstruct;

import org.adempiere.ad.trx.api.ITrx;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.util.lang.IAutoCloseable;
import org.adempiere.util.lang.MutableInt;
import org.adempiere.util.lang.impl.TableRecordReferenceSet;
import org.compiere.Adempiere;
import org.compiere.util.DB;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;

import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Streams;

import de.metas.logging.LogManager;
import de.metas.ui.web.base.model.I_T_WEBUI_ViewSelection;
import de.metas.ui.web.base.model.I_T_WEBUI_ViewSelectionLine;
Expand All @@ -41,7 +18,28 @@
import de.metas.ui.web.window.controller.DocumentPermissionsHelper;
import de.metas.ui.web.window.datatypes.WindowId;
import de.metas.util.Check;
import de.metas.util.Services;
import lombok.NonNull;
import org.adempiere.ad.trx.api.ITrx;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.service.ISysConfigBL;
import org.adempiere.util.lang.IAutoCloseable;
import org.adempiere.util.lang.MutableInt;
import org.adempiere.util.lang.impl.TableRecordReferenceSet;
import org.compiere.Adempiere;
import org.compiere.util.DB;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

/*
* #%L
Expand Down Expand Up @@ -71,27 +69,26 @@ public class ViewsRepository implements IViewsRepository
private static final Logger logger = LogManager.getLogger(ViewsRepository.class);

private final ImmutableMap<ViewFactoryKey, IViewFactory> factories;
@Autowired
private SqlViewFactory defaultFactory;
private final SqlViewFactory defaultFactory;

@Autowired
private MenuTreeRepository menuTreeRepo;
private final MenuTreeRepository menuTreeRepo;

@Value("${metasfresh.webui.view.truncateOnStartUp:true}")
private boolean truncateSelectionOnStartUp;

private final ImmutableMap<WindowId, IViewsIndexStorage> viewsIndexStorages;
private final IViewsIndexStorage defaultViewsIndexStorage = new DefaultViewsRepositoryStorage();
private final IViewsIndexStorage defaultViewsIndexStorage;

/**
*
* @param neededForDBAccess not used in here, but we need to cause spring to initialize it <b>before</b> this component can be initialized.
* So, if you clean this up, please make sure that the webui-API still starts up ^^.
* @param DO_NOT_DELETE_neededForDBAccess not used in here, but we need to cause spring to initialize it <b>before</b> this component can be initialized.
* So, if you clean this up, please make sure that the webui-API still starts up ^^.
*/
public ViewsRepository(
@NonNull final Adempiere neededForDBAccess,
@SuppressWarnings("unused") @NonNull final Adempiere DO_NOT_DELETE_neededForDBAccess,
@NonNull final List<IViewFactory> viewFactories,
@NonNull final Optional<List<IViewsIndexStorage>> viewIndexStorages)
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") @NonNull final Optional<List<IViewsIndexStorage>> viewIndexStorages,
final SqlViewFactory defaultFactory,
final MenuTreeRepository menuTreeRepo)
{
factories = createFactoriesMap(viewFactories);
factories.values().forEach(viewFactory -> viewFactory.setViewsRepository(this));
Expand All @@ -100,6 +97,11 @@ public ViewsRepository(
this.viewsIndexStorages = createViewIndexStoragesMap(viewIndexStorages.orElseGet(ImmutableList::of));
this.viewsIndexStorages.values().forEach(viewsIndexStorage -> viewsIndexStorage.setViewsRepository(this));
logger.info("Registered following view index storages: {}", this.viewsIndexStorages);
this.defaultFactory = defaultFactory;
this.menuTreeRepo = menuTreeRepo;

final int viewExpirationTimeoutInMinutes = Services.get(ISysConfigBL.class).getIntValue("de.metas.ui.web.view.ViewExpirationTimeoutInMinutes", 60);
defaultViewsIndexStorage = new DefaultViewsRepositoryStorage(viewExpirationTimeoutInMinutes);
}

@PostConstruct
Expand Down Expand Up @@ -163,7 +165,7 @@ private static ImmutableMap<ViewFactoryKey, IViewFactory> createFactoriesMap(fin
return ImmutableMap.copyOf(factories);
}

private static ImmutableMap<WindowId, IViewsIndexStorage> createViewIndexStoragesMap(List<IViewsIndexStorage> viewsIndexStorages)
private static ImmutableMap<WindowId, IViewsIndexStorage> createViewIndexStoragesMap(final List<IViewsIndexStorage> viewsIndexStorages)
{
final ImmutableMap.Builder<WindowId, IViewsIndexStorage> map = ImmutableMap.builder();

Expand All @@ -184,7 +186,7 @@ private static ImmutableMap<WindowId, IViewsIndexStorage> createViewIndexStorage
return map.build();
}

private final IViewFactory getFactory(final WindowId windowId, final JSONViewDataType viewType)
private IViewFactory getFactory(final WindowId windowId, final JSONViewDataType viewType)
{
IViewFactory factory = factories.get(ViewFactoryKey.of(windowId, viewType));
if (factory != null)
Expand Down Expand Up @@ -398,7 +400,7 @@ public void notifyRecordsChanged(@NonNull final TableRecordReferenceSet recordRe
return;
}

try (final IAutoCloseable c = ViewChangesCollector.currentOrNewThreadLocalCollector())
try (final IAutoCloseable ignored = ViewChangesCollector.currentOrNewThreadLocalCollector())
{
final MutableInt notifiedCount = MutableInt.zero();
streamAllViews()
Expand Down

0 comments on commit 39f76f8

Please sign in to comment.