Skip to content

Commit

Permalink
Add property skipIfIndirectlyCalled to annotation CalloutMethod (#10433)
Browse files Browse the repository at this point in the history
and used it by setting "manualPrice" to Y only if user manually edits priceEntered

(cherry picked from commit c420424)
  • Loading branch information
metas-ts committed Dec 15, 2020
1 parent ff75b0d commit ca38d95
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public final void start(final String methodName, final ICalloutField calloutFiel
}
} // start

private static final GridField extractGridFieldOrNull(final ICalloutField calloutField)
private static GridField extractGridFieldOrNull(final ICalloutField calloutField)
{
if (calloutField instanceof GridField)
{
Expand Down Expand Up @@ -136,7 +136,7 @@ public final String convert(final String methodName, final String value)
* @param methodName method name
* @return method or null
*/
private static final Method findMethod(final Class<?> clazz, final String methodName)
private static Method findMethod(final Class<?> clazz, final String methodName)
{
if (methodName == null || methodName.isEmpty())
{
Expand All @@ -160,13 +160,13 @@ private interface CalloutMethodExecutor
String execute(final CalloutEngine instance, final ICalloutField calloutField) throws Exception;
}

private final CalloutMethodExecutor getCalloutMethodExecutor(final Class<?> clazz, final String methodName)
private CalloutMethodExecutor getCalloutMethodExecutor(final Class<?> clazz, final String methodName)
{
final String key = clazz.getName() + "." + methodName;
return _calloutMethodExecutorsCache.getOrLoad(key, ()->createCalloutMethodExecutor(clazz, methodName));
}

private static final CalloutMethodExecutor createCalloutMethodExecutor(final Class<?> clazz, final String methodName)
private static CalloutMethodExecutor createCalloutMethodExecutor(final Class<?> clazz, final String methodName)
{
final Method method = findMethod(clazz, methodName);
final int argLength = method.getParameterTypes().length;
Expand All @@ -189,9 +189,7 @@ else if (argLength == 5)
}
else if (argLength == 1)
{
return (instance, calloutField) -> {
return (String)method.invoke(instance, calloutField);
};
return (instance, calloutField) -> (String)method.invoke(instance, calloutField);
}
else
{
Expand All @@ -200,8 +198,6 @@ else if (argLength == 1)

}

/*************************************************************************/

/**
* Is the current callout being called in the middle of
* another callout doing her works.
Expand Down Expand Up @@ -233,11 +229,6 @@ protected final boolean isCalloutActive()
* Set Account Date Value.
* org.compiere.model.CalloutEngine.dateAcct
*
* @param ctx context
* @param WindowNo window no
* @param mTab tab
* @param mField field
* @param value value
* @return null or error message
*/
public String dateAcct(final ICalloutField field)
Expand All @@ -248,7 +239,7 @@ public String dateAcct(final ICalloutField field)
}

final Object value = field.getValue();
if (value == null || !(value instanceof java.util.Date))
if (!(value instanceof java.util.Date)/*this also covers value=null*/)
{
return NO_ERROR;
}
Expand All @@ -265,11 +256,6 @@ public String dateAcct(final ICalloutField field)
* Rate - set Multiply Rate from Divide Rate and vice versa
* org.compiere.model.CalloutEngine.rate
*
* @param ctx context
* @param WindowNo window no
* @param mTab tab
* @param mField field
* @param value value
* @return null or error message
*/
@Deprecated
Expand Down Expand Up @@ -304,7 +290,7 @@ public String rate(final ICalloutField field)
{
InterfaceWrapperHelper.setValue(model, "MultiplyRate", rate2);
}
log.info("{} = {} => ", columnName, rate1, rate2);
log.info("columnName={}; value={} => result={}", columnName, rate1, rate2);

return NO_ERROR;
} // rate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,10 @@
* Skip calling this callout if we are copying (with details).
*/
boolean skipIfCopying() default false;

/**
* Skip calling this callout if it is called via another callout.
* Use case: you want a callout to do stuff only if invoked *directly* by a user (or business logic).
*/
boolean skipIfIndirectlyCalled() default false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,7 @@ public interface ICalloutMethodPointcut

/** @return true if we shall skip invoking this callout if we are in record copying mode */
boolean isSkipIfCopying();

/** @return true if we shall skip invoking this callout if it's called not directly but via another callout */
boolean isSkipIfIndirectlyCalled();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of the
* License, or (at your option) any later version.
*
*
* This program 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 General Public License for more details.
*
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>.
* #L%
*/


import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import lombok.NonNull;
import org.adempiere.ad.callout.annotations.api.ICalloutMethodPointcut;
import org.adempiere.ad.callout.api.ICalloutExecutor;
import org.adempiere.ad.callout.api.ICalloutField;
Expand Down Expand Up @@ -56,11 +56,9 @@ public final class AnnotatedCalloutInstance implements ICalloutInstance
/* package */AnnotatedCalloutInstance(final String id,
final String tableName,
final Collection<String> columnNames,
final Object annotatedObject,
@NonNull final Object annotatedObject,
final ListMultimap<CalloutMethodPointcutKey, CalloutMethodPointcut> mapPointcuts)
{
super();

Check.assumeNotEmpty(id, "id not empty");
this.id = id;

Expand All @@ -70,13 +68,12 @@ public final class AnnotatedCalloutInstance implements ICalloutInstance
Check.assumeNotEmpty(columnNames, "columnNames not empty");
this.columnNames = ImmutableSet.copyOf(columnNames);

Check.assumeNotNull(annotatedObject, "annotatedObject not null");
this.annotatedObject = annotatedObject;

Check.assume(mapPointcuts != null && !mapPointcuts.isEmpty(), "mapPointcuts not empty");
this.mapPointcuts = ImmutableListMultimap.copyOf(mapPointcuts);
}

@Override
public String toString()
{
Expand All @@ -92,7 +89,7 @@ public String getTableName()

/**
* Gets a set of column names on which this callout instance is listening
*
*
* @return set of column names
*/
public Set<String> getColumnNames()
Expand Down Expand Up @@ -123,20 +120,25 @@ public void execute(final ICalloutExecutor executor, final ICalloutField field)
}
}

private void executePointcut(final ICalloutMethodPointcut pointcut, final ICalloutExecutor executor, final ICalloutField field)
private void executePointcut(@NonNull final ICalloutMethodPointcut pointcut, @NonNull final ICalloutExecutor executor, @NonNull final ICalloutField field)
{
// Skip executing this callout if we were asked to skip when record copying mode is active
if (pointcut.isSkipIfCopying() && field.isRecordCopyingMode())
{
logger.info("Skip invoking callout because we are in copying mode: {}", pointcut.getMethod());
return;
}
if (pointcut.isSkipIfIndirectlyCalled() && executor.getActiveCalloutInstancesCount() > 1)
{
logger.info("Skip invoking callout because it is called via another callout: {}", pointcut.getMethod());
return;
}

try
{
final Method method = pointcut.getMethod();
final Object model = field.getModel(pointcut.getModelClass());

// make sure the method can be executed
if (!method.isAccessible())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public final class AnnotatedCalloutInstanceFactory
private Object annotatedCalloutObject;
private String tableName;
private Callout.RecursionAvoidanceLevel recursionAvoidanceLevel;
private final Set<String> columnNames = new HashSet<String>();
private final Set<String> columnNames = new HashSet<>();

private final transient ListMultimap<CalloutMethodPointcutKey, CalloutMethodPointcut> mapPointcuts = ArrayListMultimap.create();

Expand Down Expand Up @@ -124,7 +124,7 @@ else if (Callout.RecursionAvoidanceLevel.CalloutMethod == recursionAvoidanceLeve
return calloutInstances;
}

private final AnnotatedCalloutInstance createCalloutInstance(final String id,
private AnnotatedCalloutInstance createCalloutInstance(final String id,
final Set<String> columnNames,
final ListMultimap<CalloutMethodPointcutKey, CalloutMethodPointcut> mapPointcuts)
{
Expand All @@ -137,13 +137,13 @@ public AnnotatedCalloutInstanceFactory setAnnotatedCalloutObject(final Object an
return this;
}

private final Object getAnnotatedCalloutObject()
private Object getAnnotatedCalloutObject()
{
Check.assumeNotNull(annotatedCalloutObject, "annotatedCalloutObj not null");
return annotatedCalloutObject;
}

private final Class<?> getAnnotatedClass()
private Class<?> getAnnotatedClass()
{
return getAnnotatedCalloutObject().getClass();
}
Expand Down Expand Up @@ -252,12 +252,12 @@ private CalloutMethodPointcut createPointcut(final CalloutMethod annModelChange,
paramCalloutFieldRequired = false;
}

final CalloutMethodPointcut pointcut = new CalloutMethodPointcut(modelClass,
return new CalloutMethodPointcut(modelClass,
method,
annModelChange.columnNames(),
paramCalloutFieldRequired,
annModelChange.skipIfCopying());
return pointcut;
annModelChange.skipIfCopying(),
annModelChange.skipIfIndirectlyCalled());
}

private void addPointcutToMap(final CalloutMethodPointcut pointcut)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,46 @@
import java.util.HashSet;
import java.util.Set;

import lombok.Getter;
import lombok.NonNull;
import org.adempiere.ad.callout.annotations.api.ICalloutMethodPointcut;

import de.metas.util.Check;

public final class CalloutMethodPointcut implements ICalloutMethodPointcut
{
@Getter
private final Method method;

@Getter
private final Set<String> columnNames;

@Getter
private final Class<?> modelClass;

@Getter
private final boolean paramCalloutFieldRequired;

@Getter
private final boolean skipIfCopying;

public CalloutMethodPointcut(final Class<?> modelClass,
final Method method,
final String[] columnNames,
@Getter
private final boolean skipIfIndirectlyCalled;

public CalloutMethodPointcut(
@NonNull final Class<?> modelClass,
@NonNull final Method method,
@NonNull final String[] columnNames,
final boolean paramCalloutFieldRequired,
final boolean skipIfCopying)
final boolean skipIfCopying,
final boolean skipIfIndirectlyCalled)
{
super();

Check.assumeNotNull(modelClass, "modelClass not null");
this.modelClass = modelClass;

Check.assumeNotNull(method, "method not null");
this.method = method;

Check.assumeNotNull(columnNames, "columnNames not null");
Check.assume(columnNames.length > 0, "columnNames not empty");

this.columnNames = new HashSet<String>(columnNames.length);
this.columnNames = new HashSet<>(columnNames.length);
for (final String columnName : columnNames)
{
Check.assumeNotNull(columnName, "columnName not null");
Expand All @@ -66,35 +76,6 @@ public CalloutMethodPointcut(final Class<?> modelClass,
this.paramCalloutFieldRequired = paramCalloutFieldRequired;

this.skipIfCopying = skipIfCopying;
}

@Override
public Method getMethod()
{
return method;
}

@Override
public Set<String> getColumnNames()
{
return columnNames;
}

@Override
public Class<?> getModelClass()
{
return modelClass;
}

@Override
public boolean isParamCalloutFieldRequired()
{
return paramCalloutFieldRequired;
}

@Override
public boolean isSkipIfCopying()
{
return skipIfCopying;
this.skipIfIndirectlyCalled = skipIfIndirectlyCalled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,12 @@ public static Builder builder()

private CalloutExecutor(
final String tableName,
final TableCalloutsMap tableCalloutsMap,
@NonNull final TableCalloutsMap tableCalloutsMap,
final Set<String> executionBlackListIds)
{
super();

Check.assumeNotEmpty(tableName, "tableName is not empty");
this.tableName = tableName;

Check.assumeNotNull(tableCalloutsMap, "Parameter tableCalloutsMap is not null");
this.tableCalloutsMap = tableCalloutsMap;

if (executionBlackListIds == null)
Expand Down Expand Up @@ -122,10 +119,8 @@ public void execute(final ICalloutField field)
}

@Override
public void executeAll(final Function<String, ICalloutField> calloutFieldsSupplier)
public void executeAll(@NonNull final Function<String, ICalloutField> calloutFieldsSupplier)
{
Check.assumeNotNull(calloutFieldsSupplier, "Parameter calloutFieldsSupplier is not null");

logger.trace("executeAll: Begin executing all callouts for {} using fields supplier: {}", this, calloutFieldsSupplier);

//
Expand Down

0 comments on commit ca38d95

Please sign in to comment.