/**
* i-net software provides programming examples for illustration only, without warranty
* either expressed or implied, including, but not limited to, the implied warranties
* of merchantability and/or fitness for a particular purpose. This programming example
* assumes that you are familiar with the programming language being demonstrated and
* the tools used to create and debug procedures. i-net software support professionals
* can help explain the functionality of a particular procedure, but they will not modify
* these examples to provide added functionality or construct procedures to meet your
* specific needs.
*
* Copyright © 1999-2025 i-net software GmbH, Berlin, Germany.
**/
package com.inet.samples.formula;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import com.inet.report.Engine;
import com.inet.report.formula.UserDefinedFunction;
/**
* This class shows the usage of user defined Java methods in formulas of an i-net Clear Reports report.
*
* You can find more information about user defined formulas in the section "Programming" of the i-net Clear Reports
* documentation.
*
* i-net Clear Reports adds the methods of this class to the functions, that can be used in a formula, if you set the
* fully qualified class name (e.g. samples.userdefined_formula.FormulaSample) of this class in the property
* "Formula Expander Class". You can find it in the dialog "Customization" of the Configuration Manager.
*
* Also, it is necessary to add this class file to the classpath. You can do this, for example, by creating a jar file
* containing this class and all help files (with command
* "jar cf formula-sample.jar samples/userdefined_formula/FormulaSample.class samples/userdefined_formula/*.html") and
* copying this jar file into the "lib" directory that is included in the installation directory of i-net Clear Reports
* or i-net Designer.
*
* Since version 13 it is possible to use one or more of the following hidden parameters as method parameter in the
* formula expander class: "Engine", "HTTPSession" and "HTTPServletRequest". This can be useful, for example, to use the
* Engine API to get user defined parameters from the report engine.
*/
public class FormulaSample implements UserDefinedFunction {
/**
* Calendar for date operations. You can see this user defined constant in the list of constants in the formula
* editor.
*/
public static final GregorianCalendar GREGCALENDAR = new GregorianCalendar();
/**
* Returns an array of length n containing the first even natural numbers, starting with 0. firstEvens(5) will
* return [0,2,4,6,8].
* @param n length of returned list of even numbers.
* @return Number[] containing the first even natural numbers
*/
public static Number[] firstEvens( Number n ) {
int n_ = n.intValue();
Integer[] evens = new Integer[n_];
for( int i = 0; i < n_; i++ ) {
evens[i] = 2 * i;
}
return evens;
}
/**
* Returns an array of length n containing the first odd natural numbers, starting with 1. firstOdds(5) will return
* [1,3,5,7,9].
* @param n length of returned list of odd numbers.
* @return Number[] containing the first odd natural numbers
*/
public static Number[] firstOdds( Number n ) {
int n_ = n.intValue();
Integer[] odds = new Integer[n_];
for( int i = 0; i < n_; i++ ) {
odds[i] = 2 * i + 1;
}
return odds;
}
/**
* Returns the factorial of n. Parameter n have to be less than 21.
* @param n number to return factorial for
* @return factorial of n
* @throws IllegalArgumentException if n is 21 or greater
*/
public static Number factorial( Number n ) {
if( !(n.intValue() <= 20) ) {
throw new IllegalArgumentException();
}
return Long.valueOf( factorial( n.intValue() ) );
}
/**
* Computes factorial of n.
* @param n number to compute factorial for
* @return factorial of n
*/
private static long factorial( int n ) {
if( n == 0 ) {
return 1;
}
return n * factorial( n - 1 );
}
/**
* Validates a alpha-numerical number string of formats ddddd-AAA-dddddd.
* @param serialstring string to verify pattern for.
* @return Boolean.TRUE if pattern matches, else Boolean.FALSE
*/
public static Boolean verify( String serialstring ) {
return Pattern.matches( "[0-9]{5}-[A-Z]{3}-[0-9]{6}", serialstring );
}
/**
* Validates a string of formats regex. See Java Doc for details.
* @param regex Regular expression to use to verify arg
* @param arg string to verify
* @return result of Pattern.matches(regex, arg) as Boolean
*/
public static Boolean verify( String regex, String arg ) {
return Pattern.matches( regex, arg );
}
/**
* Returns if year is a leap year. Use for values of i-net Clear Reports type Date.
* @param date date to check whether its year is a leap year.
* @return whether the year of the given date is a leap year
*/
public static Boolean leapYear( java.sql.Date date ) {
return GREGCALENDAR.isLeapYear( Calendar.getInstance().get( Calendar.YEAR ) - 1900 );
}
/**
* Returns if year is a leap year. Use for values of i-net Clear Reports type Datetime.
* @param date date time to check whether its year is a leap year
* @return whether the year of the given date time is a leap year
*/
public static Boolean leapYear( java.sql.Timestamp date ) {
return GREGCALENDAR.isLeapYear( Calendar.getInstance().get( Calendar.YEAR ) - 1900 );
}
/**
* This function will roll up the hour field of the time value (in range between 0 and 23).
* @param time time object to roll hour up for
* @return time with hour rolled up by one
*/
public static java.sql.Time rollHour( java.sql.Time time ) {
GregorianCalendar gCal =
new GregorianCalendar( 1970, 1, 1, Calendar.getInstance().get( Calendar.HOUR_OF_DAY ), Calendar.getInstance().get( Calendar.MINUTE ),
Calendar.getInstance().get( Calendar.SECOND ) );
gCal.roll( Calendar.HOUR, 1 );
return new java.sql.Time( gCal.getTimeInMillis() );
}
/**
* Returns true if parity of boolean array args is even.
* @param args parameter expected to be a Boolean array
* @return Boolean if Boolean array has an even parity
* @throws IllegalArgumentException if args is not a Boolean array.
*/
public static Boolean evenParity( Object[] args ) {
int count = 0;
for( int i = 0; i < args.length; i++ ) {
if( !(args[i] instanceof Boolean) ) {
throw new IllegalArgumentException( "Boolean expected." );
}
if( args[i].equals( Boolean.TRUE ) ) {
count++;
}
}
return count % 2 == 0;
}
/**
* Draws a String "Demo" at Position (10,10) of the image in bytes
. If an error occurs, the original
* byte[] is returned.
* @param bytes image data to draw into
* @return the manipulated image; If manipulation fails the original image is returned.
*/
public static byte[] drawDemoToImage( byte[] bytes ) {
try {
ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
BufferedImage img = ImageIO.read( bais );
Graphics2D g2d = img.createGraphics();
g2d.drawString( "Demo", 10, 10 );
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write( img, "png", out );
return out.toByteArray();
} catch( Exception e ) {
e.printStackTrace();
}
return bytes;
}
/**
* Returns the value of a user property that has been set either with engine.setUserProperties(), checkProperties()
* or in the report URL.
* @param propertyKey the key of the property
* @param engine the report engine instance
* @return the user property value or an empty string, if it does not exists
*/
static public String getUserProperty( String propertyKey, Engine engine ) {
Properties properties = engine.getUserProperties();
if( properties != null ) {
return properties.getProperty( propertyKey, "" );
} else {
return "";
}
}
}