<?xml version="1.0" encoding="UTF-8"?>

<sample>

  <name>functions</name>
  <title>Functions Sample</title>
  <description>Shows how the functions could be used inside report template expressions.</description>

  <mainFeature ref="functions"/>
  
  <!-- functions -->
  
  <feature name="functions" title="Custom Functions in Report Expressions">
    <description>
How to use JasperReports built-in functions inside expressions
    </description>
    <since>5.1.2</since>
    <documentedBy>
      <author>
    	<name>Sanda Zaharia</name>
    	<email>shertage@users.sourceforge.net</email>
      </author>
    </documentedBy>
    <content>
<subtitle name="overview">Expressions in JasperReports</subtitle>    
<br/>
<br/>
For most common situations JasperReports expressions represent the perfect tool for acquiring and processing dynamic data. But in 
some particular cases expressions may also prove their own limitations, especially when series of complex calculations are required 
to compute a result. In order to avoid writing too long, often unreadable expressions, such calculations can be stored in Java/Groovy 
methods or Javascript functions. Further, calling a Java method from within an expression requires some specific background in Java 
programming, regarding imports, object initialization and so on. Similar programming background is expected for Groovy or Javascript 
expressions.
<br/>
Custom functions, based on Java annotations and JasperReports extensions mechanism, represent a way to both enhance and simplify expressions. 
Calling custom functions does not require particular programming skills, all we need is to know the function name and its parameters. All other 
programming stuff (package imports, Java objects, complex algorithms, etc) is processed transparently to produce the expected output. Expressions 
also become very simple with custom functions: all their content can be replaced by a function call. Functions perform all necessary calculations 
and return the result you are looking for.
<br/>
Now let's see how to create a custom function and integrate it into the JasperReports library.
<br/>
<br/>
<subtitle name="customFunctions">Creating Custom Functions in JasperReports</subtitle>    
<br/>
<br/>
As based on the JasperReports extensions mechanism, custom functions need an extension point to be enabled first. To do so, in a 
<code>jasperreports_extension.properties</code> file add the following properties:
<ul>
<li><code>net.sf.jasperreports.extension.registry.factory.{registry_id}</code> - the extension registry factory class for custom functions</li>
<li><code>net.sf.jasperreports.extension.{registry_id}.{property_suffix}</code> - one or more properties providing a comma separated list of function classes</li>
</ul>
See a working example in <a href="#extensions">Coding Samples</a>  section below.
<br/>
<br/>
Each function class declared in such a property has to be implemented first, in order to become operational. Basically they are common Java classes containing 
method implementations. Depending on their purpose, methods are allowed to be static and/or non-static. In order to make available non-static methods, a function 
class must implement the <api href="net/sf/jasperreports/functions/FunctionSupport.html">FunctionSupport</api> interface, possibly by extending the built-in 
<api href="net/sf/jasperreports/functions/AbstractFunctionSupport.html">AbstractFunctionSupport</api>. 
<br/>
Notice that since void methods are useless in an expression, properly implemented function classes should expose methods that provide return types.
<br/>
<br/>
<subtitle name="annotations">Functions Annotations</subtitle>    
<br/>
<br/>
Custom function classes are characterized by specific class and method-level annotations. Annotations metadata collected at runtime are used to facilitate 
the function call mechanism, even in complex i18n environments.
<ul>
<li><b>Class-level annotations:</b>
<ul>
<li><api href="net/sf/jasperreports/functions/annotations/FunctionCategories.html">@FunctionCategories</api> - stores metadata for an array of 
<api href="net/sf/jasperreports/functions/annotations/FunctionCategory.html">FunctionCategory</api> classes, used as category identifiers when 
functions are grouped by categories. A given function may belong to different categories. The annotation can be declared as class or method-level. 
As class-level declaration, it applies to all methods in the class.</li>
<li><api href="net/sf/jasperreports/functions/annotations/FunctionCategories.html">@FunctionCategory</api> - stores metadata for any element 
in the <api href="net/sf/jasperreports/functions/annotations/FunctionCategories.html">@FunctionCategories</api> array</li>
<li><api href="net/sf/jasperreports/functions/annotations/FunctionMessagesBundle.html">@FunctionMessagesBundle</api> - stores metadata for 
the message bundle file, including package information. If not provided, the default message bundle is considered a <code>jasperreports_messages.properties</code> 
file in the current package.</li>
</ul>
</li>
<li><b>Method-level annotations:</b>
<ul>
<li><api href="net/sf/jasperreports/functions/annotations/FunctionCategories.html">@FunctionCategories</api> - stores metadata for an array of 
<api href="net/sf/jasperreports/functions/annotations/FunctionCategory.html">FunctionCategory</api> classes at method level</li>
<li><api href="net/sf/jasperreports/functions/annotations/FunctionCategories.html">@FunctionCategory</api> - stores metadata for any element 
in the above <api href="net/sf/jasperreports/functions/annotations/FunctionCategories.html">@FunctionCategories</api> array</li>
<li><api href="net/sf/jasperreports/functions/annotations/FunctionParameters.html">@FunctionParameters</api> - stores metadata for an array of 
<api href="net/sf/jasperreports/functions/annotations/FunctionParameter.html">FunctionParameter</api> elements</li>
<li><api href="net/sf/jasperreports/functions/annotations/FunctionParameter.html">@FunctionParameter</api> - stores metadata for any element 
in the above <api href="net/sf/jasperreports/functions/annotations/FunctionParameters.html">@FunctionParameters</api> array.</li>
</ul>
</li>
</ul>
<subtitle name="builtinFunctions">Built-in Functions in JasperReports Library</subtitle>
<br/>
<br/>
Built-in JasperReports functions are documented <a href="./FunctionsReport.html" target="_blank">here</a>.
<br/>
<br/>
Next, let's see a step-by-step example of adding custom functions to JasperReports library. The built-in JR functions were created this way and are all available 
in the <code>net.sf.jasperreports.functions.standard</code> package (under the <code>/src</code> directory in the present sample). Following are the necessary steps 
to make functions ready-to-use:
<ol>
<li>Depending on your specific criteria, create one or many category classes. Or you can use the existing built-in classes in the <code>net.sf.jasperreports.functions.standard</code> 
package: <code>DateTimeCategory</code>, <code>LogicalCategory</code>, <code>MathCategory</code>, <code>TextCategory</code>.</li>
<li>Implement one or many function classes with annotated methods. In this example, a function class is implemented for each category, but keep in mind that methods in different categories 
may be placed together in the same file, since we have the possibility to declare categories at method-level. There are 4 function classes in the 
<code>net.sf.jasperreports.functions.standard</code> package: <code>DateTimeFunctions</code>, <code>LogicalFunctions</code>, <code>MathFunctions</code>, <code>TextFunctions</code></li>
<li>Create a properties file to store i18n labels for categories, functions and parameters: names, descriptions, other useful informations. Each category, function or parameter 
require a name and a description entry in the properties file. Entry keys are formed according to following rules:
<ul>
<li>Category name key: the category class name (including package) + <code>.name</code> suffix. For instance: 
<code>net.sf.jasperreports.functions.standard.DateTimeCategory.name</code></li>
<li>Category description key: the category class name (including package) + <code>.description</code> suffix. For instance: 
<code>net.sf.jasperreports.functions.standard.DateTimeCategory.description</code></li>
<li>Function name key: the function class name (including package) + the function name (as declared in the <code>@Function</code> method annotation) + <code>.name</code> 
suffix. For instance: <code>net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.name</code></li>
<li>Function description key: the function class name (including package) + the function name (as declared in the <code>@Function</code> method annotation) + 
<code>.description</code> suffix. For instance: <code>net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.description</code></li>
<li>Parameter name key: the function class name (including package) + the function name (as declared in the <code>@Function</code> method annotation) + 
the related parameter name (as declared in the related <code>@FunctionParameter</code> method annotation) + <code>.name</code> suffix. For instance: 
<code>net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.dayOfMonth.name</code></li>
<li>Parameter description key: the function class name (including package) + the function name (as declared in the <code>@Function</code> method annotation) + 
the related parameter name (as declared in the related <code>@FunctionParameter</code> method annotation) + <code>.description</code> suffix. For instance: 
<code>net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.dayOfMonth.description</code></li>
</ul>
</li>
<li>Write the appropriate information in a jasperreports_extension.properties file as shown <a href="#customFunctions">above</a>.</li>
<li>Finally, archive your classes and properties files in a jar file and place it in your application classpath. Your custom functions are now ready to use.</li>
</ol>
<subtitle name="samples">Coding Samples</subtitle>
<br/>
<br/>
<subtitle name="dateTimeCategory">DateTimeCategory.java</subtitle>
<pre>
  package net.sf.jasperreports.functions.standard;
  
  import net.sf.jasperreports.functions.annotations.FunctionCategory;
  
  /**
   * This class should maintain all function methods that belongs to the category {@link #DATE_TIME}.
   */
  @FunctionCategory(
    //"DATE_TIME" // if not specified, the value is the name of the category class
    )
  public final class DateTimeCategory 
  {
  }
</pre>
Notice the <code>@FunctionCategory</code> annotation to ensure it is a function category class.
<br/>
<br/>
<subtitle name="dateTimeFunctions">DateTimeFunctions.java</subtitle>
<br/>
<br/>
Below is a code fragment extracted from the function class <code>DateTimeFunctions</code>:
<pre>
package net.sf.jasperreports.functions.standard;

// import declarations here
// ...

/**
 * This class should maintain all function methods that belongs to the category {@link #DATE_TIME}.
 */
@FunctionCategories({DateTimeCategory.class})
public final class DateTimeFunctions
{
  private static final Log log = LogFactory.getLog(DateTimeFunctions.class);
  
  // ===================== TODAY function ===================== //
  /**
   * Returns the current date as date object.
   */
  @Function("TODAY")
  public static Date TODAY(){
    return new Date();
  }
  
  // other methods declared here 
  // ...
  
  // ===================== DAY function ===================== //
  /**
   * 
   * Returns the day of a given date. Date object can be a String, long value (milliseconds) or Date instance itself.
   */
  @Function("DAY")
  @FunctionParameters({
    @FunctionParameter("dateObject")})
  public static Integer DAY(Object dateObject){
    return getCalendarFieldFromDate(dateObject,Calendar.DAY_OF_MONTH);
  }
  
  // ===================== WEEKDAY function ===================== //
  /**
   * Returns the day of the week for a given date. Date object can be a String, long value (milliseconds) or Date instance itself.
   */
  @Function("WEEKDAY")
  @FunctionParameters({
    @FunctionParameter("dateObject"),
    @FunctionParameter("isSundayFirstDay")})
  public static Integer WEEKDAY(Object dateObject){
    return WEEKDAY(dateObject, false);
  }
  
  public static Integer WEEKDAY(Object dateObject, Boolean isSundayFirstDay){
    Integer dayOfWeek = getCalendarFieldFromDate(dateObject,Calendar.DAY_OF_WEEK);
    if(dayOfWeek==null) {
      if(log.isDebugEnabled()){
        log.debug("Unable to get the correct day of the week.");
      }
      return null;
    }
    if(isSundayFirstDay){
      // By default Sunday is considered first day in Java 
      // Calendar.SUNDAY should be a constant with value 1.
      // See the Calendar.DAY_OF_WEEK javadoc    
      return dayOfWeek;
    }
    else{
      // shift the days
      if(dayOfWeek==Calendar.SUNDAY){
        return 7;
      }
      else{
        return dayOfWeek-1;
      }
    }
  }

  // other public methods declared here 
  // ...
  
  // private methods declared here
  // ...
}  
</pre>
Notice the <code>@FunctionCategories({DateTimeCategory.class})</code> annotation at class level, ensuring that all methods (functions) in this class are 
Date/Time functions.
<br/>
Public methods (excepting the overloaded ones) expose a <code>@Function</code> annotation necessary as function identifier. For overloaded methods the 
<code>@Function</code> and other annotations are declared only once, since these methods are sharing the same function name but provide different number 
of parameters. An example is given by the <code>WEEKDAY</code> overloaded method.
<br/>
Also notice how parameters are annotated where they are present: the <code>@FunctionParameters</code> annotation contains an array of <code>@FunctionParameter</code> 
that stores the parameter identifier.
<br/>
<br/>
<subtitle name="i18n">I18n and Localization</subtitle>
<br/>
<br/>
2 related code fragments are shown below. The first one comes from the default jasperreports_messages.properties file:
<pre>
net.sf.jasperreports.functions.standard.DateTimeCategory.description                           = Category for date and time manipulation functions
net.sf.jasperreports.functions.standard.DateTimeCategory.name                                  = Date &amp; Time
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.dayOfMonth.description          = The day of the new date
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.dayOfMonth.name                 = Day of month
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.description                     = Creates a date object using the specified information on day, month and year.
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.month.description               = The month of the new date
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.month.name                      = Month
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.name                            = DATE
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.year.description                = The year of the new date
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.year.name                       = Year
</pre>
The other one is the Italian translation of this fragment in the jasperreports_messages_it.properties file:
<pre>
net.sf.jasperreports.functions.standard.DateTimeCategory.description                           = Categoria di funzioni per la manipolazione di date e tempo
net.sf.jasperreports.functions.standard.DateTimeCategory.name                                  = Data e tempo
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.dayOfMonth.description          = Il giorno della data
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.dayOfMonth.name                 = Giorno
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.description                     = Crea una nuova data utilizzando le informazioni di giorno, mese e anno specificati.
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.month.description               = Il mese della data
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.month.name                      = Mese
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.name                            = DATE
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.year.description                = L''anno della data
net.sf.jasperreports.functions.standard.DateTimeFunctions.DATE.year.name                       = Anno
</pre>
Running the sample by default, all output texts will result in English. Changing the <code>REPORT_LOCALE</code> to Italian will translate the output texts into Italian.
<br/>
<br/>
<subtitle name="extensions">jasperreports_extension.properties</subtitle>
<br/>
<br/>
Following is the content of the related <code>jasperreports_extension.properties</code> file:
<pre>
net.sf.jasperreports.extension.registry.factory.functions=net.sf.jasperreports.functions.FunctionsRegistryFactory
net.sf.jasperreports.extension.functions.datetime=net.sf.jasperreports.functions.standard.DateTimeFunctions
net.sf.jasperreports.extension.functions.math=net.sf.jasperreports.functions.standard.MathFunctions, net.sf.jasperreports.functions.standard.LogicalFunctions
net.sf.jasperreports.extension.functions.text=net.sf.jasperreports.functions.standard.TextFunctions
</pre> 
Here the <code>{registry_id}</code> is assumed to be <code>functions</code>. There are 3 different function classes properties with specific 
<code>{property_suffix}-es</code>. Math and logical functions are declared in a comma separated list.
<br/>
<br/>
<subtitle name="runningSample">Running the Sample</subtitle>
<br/>
<br/>
Running the sample requires the <a href="http://ant.apache.org/">Apache Ant</a> library. Make sure that <code>ant</code> is already installed on your system (version 1.5 or later).
<br/>
In a command prompt/terminal window set the current folder to <code>demo/samples/functions</code> within the JasperReports source project and run the 
<code>&gt; ant test</code> command.
<br/>
It will generate a PDF sample that enumerates all built-in JR functions grouped by categories and, on the last page, some examples of function usage in JasperReports expressions. 
The generated PDF sample can be found in the <code>demo/samples/functions/build/reports</code> directory. 
    </content>
  </feature>

</sample>
