3535import com .igormaznitsa .jcp .expression .functions .xml .FunctionXML_TEXT ;
3636import com .igormaznitsa .jcp .expression .functions .xml .FunctionXML_XELEMENT ;
3737import com .igormaznitsa .jcp .expression .functions .xml .FunctionXML_XLIST ;
38+ import java .util .Comparator ;
39+ import java .util .List ;
3840import java .util .Map ;
3941import java .util .concurrent .atomic .AtomicLong ;
42+ import java .util .concurrent .atomic .AtomicReference ;
4043import java .util .stream .Collectors ;
41- import java .util .stream .Stream ;
4244
4345/**
4446 * The abstract class is the base for each function handler in the preprocessor
@@ -51,59 +53,69 @@ public abstract class AbstractFunction implements ExpressionItem {
5153 * The string contains the prefix for all executing methods of functions
5254 */
5355 public static final String EXECUTION_PREFIX = "execute" ;
56+
5457 /**
55- * Inside counter to generate UID for some cases
58+ * Internal counter to generate UID for some cases
5659 */
5760 protected static final AtomicLong UID_COUNTER = new AtomicLong (1 );
61+
5862 /**
59- * Inside array contains all functions supported by the preprocessor
63+ * Current internal map contains all preprocessor functions, mapped by their names
6064 */
61- private static volatile AbstractFunction [] allFunctions ;
62- private static volatile Map <String , AbstractFunction > functionNameMap ;
63-
64-
65- public static AbstractFunction [] getAllFunctions () {
66- if (allFunctions == null ) {
67- allFunctions = new AbstractFunction [] {
68- new FunctionABS (),
69- new FunctionROUND (),
70- new FunctionESC (),
71- new FunctionSTR2INT (),
72- new FunctionSTR2WEB (),
73- new FunctionSTR2CSV (),
74- new FunctionSTR2JS (),
75- new FunctionSTR2JSON (),
76- new FunctionSTR2XML (),
77- new FunctionSTR2JAVA (),
78- new FunctionSTR2GO (),
79- new FunctionTRIMLINES (),
80- new FunctionSTRLEN (),
81- new FunctionISSUBSTR (),
82- new FunctionIS (),
83- new FunctionEVALFILE (),
84- new FunctionBINFILE (),
85- new FunctionXML_GET (),
86- new FunctionXML_SIZE (),
87- new FunctionXML_ATTR (),
88- new FunctionXML_ROOT (),
89- new FunctionXML_NAME (),
90- new FunctionXML_LIST (),
91- new FunctionXML_TEXT (),
92- new FunctionXML_OPEN (),
93- new FunctionXML_XLIST (),
94- new FunctionXML_XELEMENT ()
95- };
65+ private static final AtomicReference <Map <String , AbstractFunction >> allFunctions =
66+ new AtomicReference <>();
67+
68+ @ SuppressWarnings ("StaticInitializerReferencesSubClass" )
69+ private static final List <AbstractFunction > DEFAULT_INTERNAL_FUNCTIONS = List .of (
70+ new FunctionABS (),
71+ new FunctionROUND (),
72+ new FunctionESC (),
73+ new FunctionSTR2INT (),
74+ new FunctionSTR2WEB (),
75+ new FunctionSTR2CSV (),
76+ new FunctionSTR2JS (),
77+ new FunctionSTR2JSON (),
78+ new FunctionSTR2XML (),
79+ new FunctionSTR2JAVA (),
80+ new FunctionSTR2GO (),
81+ new FunctionTRIMLINES (),
82+ new FunctionSTRLEN (),
83+ new FunctionISSUBSTR (),
84+ new FunctionIS (),
85+ new FunctionEVALFILE (),
86+ new FunctionBINFILE (),
87+ new FunctionXML_GET (),
88+ new FunctionXML_SIZE (),
89+ new FunctionXML_ATTR (),
90+ new FunctionXML_ROOT (),
91+ new FunctionXML_NAME (),
92+ new FunctionXML_LIST (),
93+ new FunctionXML_TEXT (),
94+ new FunctionXML_OPEN (),
95+ new FunctionXML_XLIST (),
96+ new FunctionXML_XELEMENT ()
97+ );
98+ private static final Map <String , AbstractFunction > DEFAULT_INTERNAL_FUNCTIONS_MAP =
99+ DEFAULT_INTERNAL_FUNCTIONS .stream ()
100+ .collect (Collectors .toMap (AbstractFunction ::getName , x -> x ));
101+
102+ public static List <AbstractFunction > findAllFunctions () {
103+ Map <String , AbstractFunction > currentAllFunctions = allFunctions .get ();
104+ if (currentAllFunctions == null ) {
105+ return DEFAULT_INTERNAL_FUNCTIONS ;
106+ } else {
107+ return currentAllFunctions .values ().stream ()
108+ .sorted (Comparator .comparing (AbstractFunction ::getName ))
109+ .collect (Collectors .toList ());
96110 }
97- return allFunctions ;
98111 }
99112
100-
101113 public static Map <String , AbstractFunction > getFunctionNameMap () {
102- if ( functionNameMap == null ) {
103- functionNameMap =
104- Stream . of ( getAllFunctions ()). collect ( Collectors . toMap ( AbstractFunction :: getName , x -> x )) ;
114+ final Map < String , AbstractFunction > result = allFunctions . get ();
115+ if ( result == null ) {
116+ return DEFAULT_INTERNAL_FUNCTIONS_MAP ;
105117 }
106- return functionNameMap ;
118+ return result ;
107119 }
108120
109121 /**
@@ -117,7 +129,7 @@ public static Map<String, AbstractFunction> getFunctionNameMap() {
117129 */
118130 public static <E extends AbstractFunction > E findForClass (final Class <E > functionClass ) {
119131 E result = null ;
120- for (final AbstractFunction function : getAllFunctions ()) {
132+ for (final AbstractFunction function : findAllFunctions ()) {
121133 if (function .getClass () == functionClass ) {
122134 result = functionClass .cast (function );
123135 break ;
0 commit comments