package com.onaro.sanscreen.client.view.common.functions; import java.util.Set; import com.onaro.client.swing.table.functional.BulkFunction; import com.onaro.sanscreen.client.view.refresh.RefreshUtils; import com.onaro.sanscreen.client.view.refresh.RefreshUtils.MethodDescriptor; import com.onaro.sanscreen.client.view.tabular.AbstractTabularTableModel; import com.onaro.sanscreen.server.interfaces.util.UpdateTimeData; import com.onaro.sanscreen.server.interfaces.annotations.InvalidatedBy; import com.onaro.sanscreen.server.interfaces.data.update.UpdateType; /** * Type of bulk function that supports detection that its contents need to be refreshed, based on the * Client/Server {@link UpdateType} refresh mechanism. The {@link AbstractTabularTableModel} will call * {@link #needsRefresh(UpdateTimeData, UpdateTimeData)}, which should return true when the function * needs to be refreshed. When this method returns true, the bulk function is evaluated again against * all of the rows, and any columns that are consumers of this function are refreshed (causing them to * re-evaluate their function calls). *

* The default mechanism for a AbstractRefreshableBulkFunction to check the UpdateTypes that have changed * against the list of UpdateTypes that are included on the {@link InvalidatedBy} annotation on the declarations * of the Server Interface methods the bulk function calls. To perform this check automatically, subclasses * should override the {@link #getMethodCalled()} or {@link #getMethodsCalled()} methods to indicate which * server interface methods that are called by the bulk function implementation. Alternatively, subclasses can * override {@link #getUpdateTypes()} or {@link #needsRefresh(UpdateTimeData, UpdateTimeData)} to provide custom * refresh detection behaviors. If none of these methods are overridden, the AbstractRefreshableBulkFunction * will default to not supporting refreshing. * * @param row type this Function is able to operate on * @param data type returned by this Function * * @see UpdateType * @see InvalidatedBy * @see MethodDescriptor * @see AbstractTabularTableModel#refreshChange(UpdateTimeData, UpdateTimeData) */ public abstract class AbstractRefreshableBulkFunction extends BulkFunction { public AbstractRefreshableBulkFunction() { super(); } public AbstractRefreshableBulkFunction(boolean isMainView) { super(isMainView); } private Set updateTypes = null; /** * Subclasses of this class should override this method to indicate which Server Interface method the * Function implementation uses. This method will be inspected to discover which UpdateTypes cause * the Function's results to be invalidated. If more than one method is used by the Function, getMethodsCalled() * should be overridden instead. * * @return the method descriptor. */ protected MethodDescriptor getMethodCalled() { return null; } /** * Subclasses of this class should override this method to indicate which Server Interface methods the * Function implementation uses. These methods will be inspected to discover which UpdateTypes cause * the Function's results to be invalidated. If only a single method is used by the function, getMethodCalled() * should be overridden instead. * * @return a list of method descriptors. */ protected MethodDescriptor[] getMethodsCalled() { MethodDescriptor descriptor = getMethodCalled(); if (descriptor == null) { return new MethodDescriptor[0]; } else { return new MethodDescriptor[] { descriptor }; } } /** * Determine whether this function needs to be refreshed, based on the changes in the UpdateTimeData. * By default, this method checks for the UpdateTypes that are annotated on the methods returned * by getMethodsCalled(). Subclasses may override to provide different refresh criteria. * * @param oldData the previous UpdateTimeData to compare with * @param newData the new UpdateTimeData * * @return true if the function needs to be refreshed, false otherwise. */ public boolean needsRefresh(UpdateTimeData oldData, UpdateTimeData newData) { Set refreshTypes = getUpdateTypes(); if (refreshTypes.isEmpty()) { return false; } for (UpdateType refreshType : refreshTypes) { if (newData.isUpdated(oldData, refreshType)) { return true; } } return false; } /** * Get the UpdateTypes that should be watched for to refresh this Function. * @return the UpdateTypes for this Function. */ public Set getUpdateTypes() { if (updateTypes == null) { updateTypes = RefreshUtils.getUpdateTypes(getMethodsCalled()); } return updateTypes; } }