org.smooks.cartridges.calc.Counter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of smooks-calc-cartridge Show documentation
Show all versions of smooks-calc-cartridge Show documentation
The Smooks Calculation Cartridge adds support for counters
/*-
* ========================LICENSE_START=================================
* smooks-calc-cartridge
* %%
* Copyright (C) 2020 Smooks
* %%
* Licensed under the terms of the Apache License Version 2.0, or
* the GNU Lesser General Public License version 3.0 or later.
*
* SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-or-later
*
* ======================================================================
*
* Licensed 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.
*
* ======================================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* =========================LICENSE_END==================================
*/
package org.smooks.cartridges.calc;
import org.smooks.api.ApplicationContext;
import org.smooks.api.ExecutionContext;
import org.smooks.api.SmooksException;
import org.smooks.api.bean.context.BeanContext;
import org.smooks.api.bean.repository.BeanId;
import org.smooks.api.delivery.fragment.Fragment;
import org.smooks.api.delivery.ordering.Producer;
import org.smooks.api.expression.ExpressionEvaluator;
import org.smooks.api.resource.visitor.VisitAfterIf;
import org.smooks.api.resource.visitor.VisitBeforeIf;
import org.smooks.api.resource.visitor.dom.DOMVisitAfter;
import org.smooks.api.resource.visitor.dom.DOMVisitBefore;
import org.smooks.api.resource.visitor.sax.ng.AfterVisitor;
import org.smooks.api.resource.visitor.sax.ng.BeforeVisitor;
import org.smooks.engine.delivery.fragment.NodeFragment;
import org.w3c.dom.Element;
import jakarta.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* The counter can increment or decrement a value.
*
* This counter has extended xml schema configuration. Take a look at the
* schema {@link https://www.smooks.org/xsd/smooks/calc-2.0.xsd} for more
* information.
*
* Example basic configuration:
*
* <resource-config selector="orderItems">
* <resource>org.smooks.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 = "!executeAfter")
@VisitAfterIf(condition = "executeAfter")
public class Counter implements BeforeVisitor, AfterVisitor, DOMVisitBefore, DOMVisitAfter, Producer {
public static final Long DEFAULT_START_INDEX = 0L;
public static final int DEFAULT_AMOUNT = 1;
@Inject
@Named("beanId")
private String beanIdName;
@Inject
private Optional start;
@Inject
private Optional amount;
@Inject
private Optional amountExpression;
@Inject
private Optional startExpression;
@Inject
private Optional resetCondition;
@Inject
private CountDirection direction = CountDirection.INCREMENT;
@Inject
private Boolean executeAfter = false;
private BeanId beanId;
@Inject
private ApplicationContext appContext;
@PostConstruct
public void initialize() {
beanId = appContext.getBeanIdStore().register(beanIdName);
}
@Override
public void visitBefore(Element element, ExecutionContext executionContext)
throws SmooksException {
count(executionContext, new NodeFragment(element));
}
@Override
public void visitAfter(Element element, ExecutionContext executionContext)
throws SmooksException {
count(executionContext, new NodeFragment(element));
}
public void count(ExecutionContext executionContext, Fragment> source) {
BeanContext beanContext = executionContext.getBeanContext();
Long value = (Long) beanContext.getBean(beanId);
if (value == null || (resetCondition.isPresent() && resetCondition.get().eval(beanContext.getBeanMap()))) {
value = getStart(beanContext);
} else {
int amount = getAmount(beanContext);
if (direction == CountDirection.INCREMENT) {
value = value + amount;
} else {
value = value - amount;
}
}
beanContext.addBean(beanId, value, source);
}
private Long getStart(BeanContext beanContext) {
if (!start.isPresent() && !startExpression.isPresent()) {
return DEFAULT_START_INDEX;
} else if (start.isPresent()) {
return start.get();
} else {
Object result = startExpression.get().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());
}
}
public Boolean getExecuteAfter() {
return executeAfter;
}
private int getAmount(BeanContext beanContext) {
if (!amount.isPresent() && !amountExpression.isPresent()) {
return DEFAULT_AMOUNT;
} else if (amount.isPresent()) {
return amount.get();
} else {
Object result = amountExpression.get().getValue(beanContext.getBeanMap());
if (!(result instanceof Integer)) {
throw new SmooksException("The amount expression must result in a Integer");
}
return (Integer) result;
}
}
public Set extends Object> getProducts() {
return Stream.of(beanIdName).collect(Collectors.toSet());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy