org.milyn.calc.Counter Maven / Gradle / Ivy
/*
* Milyn - Copyright (C) 2006 - 2010
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (version 2.1) as published
* by the Free Software Foundation.
*
* This library 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 Lesser General Public License for more details:
* http://www.gnu.org/licenses/lgpl.txt
*/
package org.milyn.calc;
import java.io.IOException;
import java.util.Set;
import org.milyn.SmooksException;
import org.milyn.cdr.annotation.AppContext;
import org.milyn.cdr.annotation.ConfigParam;
import org.milyn.cdr.annotation.ConfigParam.Use;
import org.milyn.container.ApplicationContext;
import org.milyn.container.ExecutionContext;
import org.milyn.delivery.Fragment;
import org.milyn.delivery.annotation.Initialize;
import org.milyn.delivery.annotation.VisitAfterIf;
import org.milyn.delivery.annotation.VisitBeforeIf;
import org.milyn.delivery.dom.DOMVisitAfter;
import org.milyn.delivery.dom.DOMVisitBefore;
import org.milyn.delivery.ordering.Producer;
import org.milyn.delivery.sax.SAXElement;
import org.milyn.delivery.sax.SAXUtil;
import org.milyn.delivery.sax.SAXVisitAfter;
import org.milyn.delivery.sax.SAXVisitBefore;
import org.milyn.expression.MVELExpressionEvaluator;
import org.milyn.javabean.context.BeanContext;
import org.milyn.javabean.repository.BeanId;
import org.milyn.util.CollectionsUtil;
import org.w3c.dom.Element;
import javax.xml.namespace.QName;
/**
* The counter can increment or decrement a value.
*
* This counter has extended xml schema configuration. Take a look at the
* schema {@link http://www.milyn.org/xsd/smooks/calc-1.1.xsd} for more
* information.
*
* Example basic configuration:
*
* <resource-config selector="orderItems">
* <resource>org.milyn.calc.Counter</resource>
* <param name="beanId">count</param>
* </resource-config>
*
* Optional parameters:
* <param name="start">1</param>
* <param name="amount">2</param>
* <param name="amountExpression">incrementAmount</param>
* <param name="startExpression">startValue</param>
* <param name="resetCondition">count == 10</param>
* <param name="direction">DECREMENT</param>
* <param name="executeAfter>false</param>
*
* Description of configuration properties:
*
*
* - beanId: The beanId in which the counter value is stored. The value is always stored as a Long type.
* - start: The counter start value.
* - startExpression: The result of this expression is the counter start value.
* This expression is executed at the first count and every time the counter
* is reset. The expression must result in an integer or a long.
* If the startIndex attribute of the counter is set then this expression never gets
* executed.
* - amount: The amount that the counter increments or decrements the counter value.
* - amountExpression: The result of this expression is the amount the counter increments or decrements.
* This expression is executed every time the counter counts.
* The expression must result in an integer.
* If the amount attribute of the counter is set then this expression never gets
* executed.
* - resetCondition: When the expression is set and results in a true value then the counter is reset to
* the start index. The expression must result in a boolean.
* - direction: The direction that the counter counts. Can be INCREMENT (default) or DECREMENT.
* - executeAfter: If the counter is executed after the element else it will execute before the element.
* Default is 'false'.
*
* @author [email protected]
* @since 1.1
*/
@VisitBeforeIf( condition = "!parameters.containsKey('executeAfter') || parameters.executeAfter.value != 'true'")
@VisitAfterIf( condition = "parameters.containsKey('executeAfter') && parameters.executeAfter.value == 'true'")
public class Counter implements SAXVisitBefore, SAXVisitAfter, DOMVisitBefore, DOMVisitAfter, Producer {
public static final Long DEFAULT_START_INDEX = new Long(0);
public static final int DEFAULT_AMOUNT = 1;
@ConfigParam(name="beanId")
private String beanIdName;
@ConfigParam(use=Use.OPTIONAL)
private Long start;
@ConfigParam(use=Use.OPTIONAL)
private Integer amount;
@ConfigParam(use=Use.OPTIONAL)
private MVELExpressionEvaluator amountExpression;
@ConfigParam(use=Use.OPTIONAL)
private MVELExpressionEvaluator startExpression;
@ConfigParam(use=Use.OPTIONAL)
private MVELExpressionEvaluator resetCondition;
@ConfigParam(defaultVal="INCREMENT", choice = { "INCREMENT", "DECREMENT" })
private String direction;
private CountDirection countDirection;
private BeanId beanId;
@AppContext
private ApplicationContext appContext;
@Initialize
public void initialize() {
beanId = appContext.getBeanIdStore().register(beanIdName);
countDirection = CountDirection.valueOf(direction);
}
public void visitBefore(SAXElement element,
ExecutionContext executionContext) throws SmooksException,
IOException {
count(executionContext, new Fragment(element));
}
public void visitAfter(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException {
count(executionContext, new Fragment(element));
}
public void visitBefore(Element element, ExecutionContext executionContext)
throws SmooksException {
count(executionContext, new Fragment(element));
}
public void visitAfter(Element element, ExecutionContext executionContext)
throws SmooksException {
count(executionContext, new Fragment(element));
}
public void count(ExecutionContext executionContext, Fragment source) {
BeanContext beanContext = executionContext.getBeanContext();
Long value = (Long) beanContext.getBean(beanId);
if(value == null || (resetCondition != null && resetCondition.eval(beanContext.getBeanMap()))) {
value = getStart(beanContext);
} else {
int amount = getAmount(beanContext);
if(countDirection == CountDirection.INCREMENT) {
value = value + amount;
} else {
value = value - amount;
}
}
beanContext.addBean(beanId, value, source);
}
private Long getStart(BeanContext beanContext) {
if(start == null && startExpression == null) {
return DEFAULT_START_INDEX;
} else if(start != null) {
return start;
} else {
Object result = startExpression.getValue(beanContext.getBeanMap());
if(!(result instanceof Long || result instanceof Integer)) {
throw new SmooksException("The start expression must result in a Integer or a Long");
}
return new Long(result.toString());
}
}
private int getAmount(BeanContext beanContext) {
if(amount == null && amountExpression == null) {
return DEFAULT_AMOUNT;
} else if(amount != null) {
return amount;
} else {
Object result = amountExpression.getValue(beanContext.getBeanMap());
if(result instanceof Integer == false) {
throw new SmooksException("The amount expression must result in a Integer");
}
return (Integer) result;
}
}
public Set extends Object> getProducts() {
return CollectionsUtil.toSet(beanIdName);
}
}