Refactor dblib
[ccsdk/sli/core.git] / sliPluginUtils / provider / src / main / java / org / openecomp / sdnc / sli / SliPluginUtils / SliPluginUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : CCSDK
4  * ================================================================================
5  * Copyright (C) 2017 ONAP
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdnc.sli.SliPluginUtils;
22
23 import java.io.File;
24 import java.io.FileOutputStream;
25 import java.io.PrintStream;
26 import java.text.SimpleDateFormat;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.Date;
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.Objects;
33 import java.util.Properties;
34 import java.util.Set;
35 import java.util.UUID;
36
37 import org.apache.commons.lang3.StringUtils;
38 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
39 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
40 import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * A utility class used to streamline the interface between Java plugins,
46  * the Service Logic Context, and Directed Graphs.
47  * @version 7.0.1
48  * @see org.onap.ccsdk.sli.core.sli.SvcLogicContext
49  */
50 public class SliPluginUtils implements SvcLogicJavaPlugin {
51         public enum LogLevel {
52                 TRACE, DEBUG, INFO, WARN, ERROR;
53         }
54
55         private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtils.class);
56
57
58         // ========== CONSTRUCTORS ==========
59
60         public SliPluginUtils() {}
61
62         public SliPluginUtils( Properties props ) {}
63
64
65
66         // ========== CONTEXT MEMORY FUNCTIONS ==========
67
68         /**
69          * Removes 1 or more elements from a list in context memory.
70          * <p>
71          * Values are removed based on either the index in the list, a key-value
72          * pair, or a list of key-value pairs that all must match in the element.
73          * @param parameters
74          * @param ctx Reference to context memory
75          * @throws SvcLogicException All exceptions are wrapped in
76          * SvcLogicException for compatibility with SLI.
77          * @since 7.0.1
78          */
79         public void ctxListRemove( Map<String,String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
80                 try{
81                         LOG.debug( "ENTERING Execute Node \"ctxListRemove\"" );
82
83                         // Validate, Log, & read parameters
84                         checkParameters(parameters, new String[]{"list_pfx"}, LOG);
85                         logExecuteNodeParameters(parameters, LOG, LogLevel.DEBUG);
86                         String list_pfx = parameters.get("list_pfx");
87                         String param_index = parameters.get("index");
88                         String param_key = parameters.get("key");
89                         String param_value = parameters.get("value");
90                         String param_keys_length = parameters.get("keys_length");
91
92                         // Initialize context memory list mimic
93                         SvcLogicContextList list;
94
95                         // Process based on input parameters:
96                         //   index: remove object at specific index
97                         //   key & value: remove all objects with key-value pair
98                         //   keys_length: remove all objects that match all key-value pairs
99                         //                in list
100                         if( param_index != null ) {
101                                 // Parse index
102                                 LOG.trace("executing remove by index logic");
103                                 int index;
104                                 try {
105                                         index = Integer.parseInt(param_index);
106                                 }
107                                 catch( NumberFormatException e ) {
108                                         throw new IllegalArgumentException("\"index\" parameter is not a number. index = " + param_index, e);
109                                 }
110
111                                 // Extract list from context memory & remove object @ index
112                                 LOG.trace("extracting list from context memory");
113                                 list = SvcLogicContextList.extract(ctx, list_pfx);
114                                 LOG.trace("removing elements from list");
115                                 list.remove(index);
116                         }
117                         else if( param_value != null ) {
118                                 if( param_key == null ) { param_key = ""; }
119
120                                 // Extract list from context memory & remove objects with
121                                 // key-value pair
122                                 LOG.trace("executing remove by key-value pair logic");
123                                 LOG.trace("extracting list from context memory");
124                                 list = SvcLogicContextList.extract(ctx, list_pfx);
125                                 LOG.trace("removing elements from list");
126                                 list.remove( param_key, param_value );
127                         }
128                         else if( param_keys_length != null ) {
129                                 // Parse keys_length
130                                 LOG.trace("executing remove by key-value pair list logic");
131                                 int keys_length;
132                                 try {
133                                         keys_length = Integer.parseInt(param_keys_length);
134                                 }
135                                 catch( NumberFormatException e ) {
136                                         throw new IllegalArgumentException("\"keys_length\" parameters is not a number. keys_length = " + param_keys_length, e);
137                                 }
138
139                                 // Obtain key-value pairs to check from parameters
140                                 LOG.trace("reading keys parameter list");
141                                 HashMap<String,String> keys_values = new HashMap<String,String>();
142                                 for( int i = 0; i < keys_length; i++ ) {
143                                         keys_values.put(parameters.get("keys[" + i + "].key"), parameters.get("keys[" + i + "].value"));
144                                 }
145
146                                 // Extract list from context memory & remove objects with all
147                                 // key-value pairs matching
148                                 LOG.trace("extracting list from context memory");
149                                 list = SvcLogicContextList.extract(ctx, list_pfx);
150                                 LOG.trace("removing elements from list");
151                                 list.remove(keys_values);
152                         }
153                         else {
154                                 throw new IllegalArgumentException("Required parameters missing. Requires one of: index, key & value, or keys_length array");
155                         }
156
157                         // Remove index from list
158                         LOG.trace("writing list back into context memory");
159                         list.writeToContext(ctx);
160                 }
161                 catch( Exception e ) {
162                         throw new SvcLogicException( "An error occurred in the ctxListRemove Execute node", e );
163                 }
164                 finally {
165                         LOG.debug( "EXITING Execute Node \"ctxListRemove\"" );
166                 }
167         }
168
169     /**
170      * ctxSortList
171      * @param parameters - the set of required parameters must contain list and delimiter.
172      * @param ctx Reference to context memory
173      * @throws SvcLogicException if a required parameter is missing an exception is thrown
174      */
175         public void ctxSortList( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
176                 checkParameters(parameters, new String[]{"list","delimiter"}, LOG);
177                 ArrayList<SortableCtxListElement> list = new ArrayList<SortableCtxListElement>();
178
179                 String[] sort_fields = null;
180                 if( parameters.containsKey("sort-fields") ) {
181                         sort_fields = parameters.get("sort-fields").split(parameters.get("delimiter"), 0);
182                 }
183
184                 String ctx_list_str = parameters.get("list");
185                 int listSz = getArrayLength(ctx, ctx_list_str);
186
187
188
189                 for( int i = 0; i < listSz; i++ ) {
190                         list.add( new SortableCtxListElement(ctx, ctx_list_str + '[' + i + ']', sort_fields) );
191                 }
192                 Collections.sort(list);
193
194                 ctxBulkErase(ctx, ctx_list_str);
195                 int i = 0;
196                 for( SortableCtxListElement list_element : list ) {
197                         for( Map.Entry<String,String> entry : list_element.child_elements.entrySet() ) {
198                                 if( sort_fields == null ) {
199                                         ctx.setAttribute(ctx_list_str + '[' + i + ']', entry.getValue());
200                                 }
201                                 else {
202                                         ctx.setAttribute(ctx_list_str + '[' + i + "]." + entry.getKey(), entry.getValue());
203                                 }
204                         }
205                         i++;
206                 }
207                 // Reset list length (removed by ctxBulkErase above)
208                 ctx.setAttribute(ctx_list_str+"_length",  ""+listSz);
209         }
210
211     /**
212      * generates a UUID and writes it to context memory
213      * @param parameters - ctx-destination is a required parameter
214      * @param ctx Reference to context memory
215      * @throws SvcLogicException thrown if a UUID cannot be generated or if ctx-destination is missing or null
216      */
217         public void generateUUID( Map<String, String> parameters, SvcLogicContext ctx )  throws SvcLogicException {
218                 checkParameters(parameters, new String[]{"ctx-destination"}, LOG);
219                 ctx.setAttribute(parameters.get("ctx-destination"), UUID.randomUUID().toString() );
220         }
221
222         /**
223          * Provides substring functionality to Directed Graphs.
224          * <p>
225          * Calls either String.substring(String beginIndex) or
226          * String.substring(String beginInded, String endIndex) if the end-index
227          * is present or not.
228          * @param parameters HashMap<String,String> of parameters passed by the DG to this function
229          * <table border="1">
230          *      <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
231          *      <tbody>
232          *              <tr><td>string</td><td>Mandatory</td><td>String to perform substring on</td></tr>
233          *              <tr><td>result</td><td>Mandatory</td><td>Key in context memory to populate the resulting string in</td></tr>
234          *              <tr><td>begin-index</td><td>Mandatory</td><td>Beginning index to pass to Java substring function</td></tr>
235          *              <tr><td>end-index</td><td>Optional</td><td>Ending index to pass to Java substring function. If not included, String.substring(begin) will be called.</td></tr>
236          *      </tbody>
237          * </table>
238          * @param ctx Reference to context memory
239          * @throws SvcLogicException
240          * @since 8.0.1
241          * @see SliPluginUtils#substring(Map, SvcLogicContext)
242          */
243         @Deprecated
244         public void substring( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
245                 try {
246                         checkParameters( parameters, new String[]{"string","begin-index","result"}, LOG );
247                         final String string = parameters.get("string");
248                         final String result = parameters.get("result");
249                         final String begin = parameters.get("begin-index");
250                         final String end = parameters.get("end-index");
251
252                         if( StringUtils.isEmpty(end) ) {
253                                 ctx.setAttribute( result, string.substring(Integer.parseInt(begin)) );
254                         }
255                         else {
256                                 ctx.setAttribute( result, string.substring(Integer.parseInt(begin), Integer.parseInt(end)) );
257                         }
258                 }
259                 catch( Exception e ) {
260                         throw new SvcLogicException( "An error occurred while the Directed Graph was performing a substring", e );
261                 }
262         }
263
264
265
266         // ========== PUBLIC STATIC UTILITY FUNCTIONS ==========
267
268         /**
269          * Throws an exception and writes an error to the log file if a required
270          * parameters is not found in the parametersMap.
271          * <p>
272          * Use at the beginning of functions that can be called by Directed Graphs
273          * and can take parameters to verify that all parameters have been provided
274          * by the Directed Graph.
275          * @param parametersMap parameters Map passed to this node
276          * @param requiredParams Array of parameters required by the calling function
277          * @param log Reference to Logger to log to
278          * @throws SvcLogicException if a String in the requiredParams array is
279          * not a key in parametersMap.
280          * @since 1.0
281          */
282         public static final void checkParameters(Map<String, String> parametersMap, String[] requiredParams, Logger log) throws SvcLogicException {
283         if( requiredParams == null || requiredParams.length < 1){
284             log.debug("required parameters was empty, exiting early.");
285             return;
286         }
287         if (parametersMap == null || parametersMap.keySet().size() < 1){
288             String errorMessage = "This method requires the parameters [" +   StringUtils.join(requiredParams,",") + "], but no parameters were passed in.";
289             log.error(errorMessage);
290             throw new SvcLogicException(errorMessage);
291         }
292
293         for (String param : requiredParams) {
294             if (!parametersMap.containsKey(param)) {
295                 String errorMessage = "Required parameter \"" + param + "\" was not found in parameter list.";
296                 log.error(errorMessage);
297                 log.error("Total list of required parameters is [" + StringUtils.join(requiredParams, ",") + "].");
298                 throw new SvcLogicException(errorMessage);
299             }
300         }
301         }
302
303         /**
304          * Removes all key-value pairs with keys that begin with pfx
305          * @param ctx Reference to context memory
306          * @param pfx Prefix of key-value pairs to remove
307          * @since 1.0
308          */
309         public static final void ctxBulkErase( SvcLogicContext ctx, String pfx ) {
310                 ArrayList<String> Keys = new ArrayList<String>( ctx.getAttributeKeySet() );
311                 for( String key : Keys ) {
312                         if( key.startsWith( pfx ) ) {
313                                 ctx.setAttribute( pfx + key.substring(pfx.length()) , null);
314                         }
315                 }
316         }
317
318         /**
319          * Copies all context memory key-value pairs that start with src_pfx to
320          * the keys that start with dest_pfx + suffix, where suffix is the result
321          * of {@code key.substring(src_pfx.length())}.
322          * <p>
323          * Does NOT guarantee removal of all keys at the destination before
324          * copying, but will overwrite any destination keys that have a
325          * corresponding source key. Use {@link #ctxBulkErase(SvcLogicContext, String) ctxBulkErase}
326          * before copy to erase destination root before copying from source.
327          * @param ctx Reference to context memory.
328          * @param src_pfx Prefix of the keys to copy values from.
329          * @param dest_pfx Prefix of the keys to copy values to.
330          * @since 1.0
331          */
332         public static final void ctxBulkCopy( SvcLogicContext ctx, String src_pfx, String dest_pfx ) {
333                 // Remove trailing period from dest_pfx
334                 if( dest_pfx.charAt(dest_pfx.length()-1) == '.' ) {
335                         dest_pfx = dest_pfx.substring(0,dest_pfx.length()-1);
336                 }
337
338                 // For each context key that begins with src_pfx, set the value of the
339                 // key dest_pfx + the suffix of the key to the key's value
340                 ArrayList<String> Keys = new ArrayList<String>(ctx.getAttributeKeySet());
341                 for( String key : Keys ) {
342                         if( key.startsWith(src_pfx) ) {
343                                 // Get suffix (no leading period)
344                                 String suffix = key.substring(src_pfx.length());
345                                 if( suffix.charAt(0) == '.') {
346                                         suffix = suffix.substring(1);
347                                 }
348
349                                 // Set destination's value to key's value
350                                 ctx.setAttribute(dest_pfx + '.' + suffix, ctx.getAttribute(key));
351                         }
352                 }
353         }
354
355         /**
356          * Creates and returns a {@code Map<String, String>} that is a subset of
357          * context memory where all keys begin with the prefix.
358          * @param ctx Reference to context memory.
359          * @param prefix Returned map's keys should all begin with this value.
360          * @return A {@code Map<String, String>} containing all the key-value pairs
361          * in ctx whose key begins with prefix.
362          */
363         public static final Map<String, String> ctxGetBeginsWith( SvcLogicContext ctx, String prefix ) {
364                 Map<String, String> prefixMap = new HashMap<String, String>();
365
366                 for( String key : ctx.getAttributeKeySet() ) {
367                         if( key.startsWith(prefix) ) {
368                                 prefixMap.put( key, ctx.getAttribute(key) );
369                         }
370                 }
371
372                 return prefixMap;
373         }
374
375         /**
376          * Returns true if key's value in context memory is "" or if it doesn't
377          * exist in context memory.
378          * @param ctx Reference to context memory.
379          * @param key Key to search for.
380          * @return true if key's value in context memory is "" or if it doesn't
381          * exist in context memory.
382          * @since 1.0
383          */
384         public static final boolean ctxKeyEmpty( SvcLogicContext ctx, String key ) {
385                 String value = ctx.getAttribute(key);
386                 return value == null || value.isEmpty();
387         }
388
389         /**
390          * Adds all key-value pairs in the entries Map to context memory.
391          * @param ctx Reference to context memory. Value's {@code toString()}
392          * function is used to add it.
393          * @param entries {@code Map<String, ?>} of key-value pairs to add to
394          * context memory. Value's {@code toString()} function is used to add it.
395          * @return Reference to context memory to be used for function chaining.
396          */
397         public static final SvcLogicContext ctxPutAll( SvcLogicContext ctx, Map<String, ?> entries ) {
398                 for( Map.Entry<String, ?> entry : entries.entrySet() ) {
399                         ctxSetAttribute( ctx, entry.getKey(), entry.getValue() );
400                         //ctx.setAttribute(entry.getKey(), entry.getValue().toString());
401                 }
402
403                 return ctx;
404         }
405
406         /**
407          * Sets a key in context memory to the output of object's toString(). The
408          * key is deleted from context memory if object is null.
409          * @param ctx Reference to context memory.
410          * @param key Key to set.
411          * @param object Object whose toString() will be the value set
412          */
413         public static final void ctxSetAttribute( SvcLogicContext ctx, String key, Object object ) {
414                 if( object == null ) {
415                         ctx.setAttribute(key, null);
416                 }
417                 else {
418                         ctx.setAttribute(key, object.toString());
419                 }
420         }
421
422         /**
423          * Sets a key in context memory to the output of object's toString().
424          * <p>
425          * The key is deleted from context memory if object is null. The key and
426          * value set in context memory are logged to the Logger at the provided
427          * logLevel level.
428          * @param <O> Any Java object
429          * @param ctx Reference to context memory.
430          * @param key Key to set.
431          * @param obj Object whose toString() will be the value set
432          * @param LOG Logger to log to
433          * @param logLevel level to log at in Logger
434          */
435         public static final <O extends Object> void ctxSetAttribute( SvcLogicContext ctx, String key, O obj, Logger LOG, LogLevel logLevel ) {
436                 String value = Objects.toString( obj, null );
437                 ctx.setAttribute( key, value );
438                 if( logLevelIsEnabled(LOG, logLevel ) ) {
439                         if( value == null ) {
440                                 logMessageAtLevel( LOG, logLevel, "Deleting " + key );
441                         }
442                         else {
443                                 logMessageAtLevel( LOG, logLevel, "Setting " + key + " = " + value );
444                         }
445                 }
446         }
447
448         /**
449          * Utility function used to get an array's length from context memory.
450          * Will return 0 if key doesn't exist in context memory or isn't numeric.
451          * <p>
452          * Use to obtain a context memory array length without having to worry
453          * about throwing a NumberFormatException.
454          * @param ctx Reference to context memory
455          * @param key Key in context memory whose value is the array's length. If
456          * the key doesn't end in "_length", then "_length is appended.
457          * @param log Reference to Logger to log to
458          * @return The array length or 0 if the key is not found in context memory.
459          * @since 1.0
460          */
461         public static final int getArrayLength( SvcLogicContext ctx, String key ) {
462                 return getArrayLength(ctx, key, null, null, null);
463         }
464
465         /**
466          * Utility function used to get an array's length from context memory.
467          * Will return 0 if key doesn't exist in context memory or isn't numeric
468          * and print the provided log message to the configured log file.
469          * <p>
470          * Use to obtain a context memory array length without having to worry
471          * about throwing a NumberFormatException.
472          * @param ctx Reference to context memory.
473          * @param key Key in context memory whose value is the array's length. If
474          * the key doesn't end in "_length", then "_length is appended.
475          * @param log Reference to Logger to log to. Doesn't log if null.
476          * @param logLevel Logging level to log the message at if the context
477          * memory key isn't found. Doesn't log if null.
478          * @param log_message Message to log if the context memory key isn't found.
479          * Doesn't log if null.
480          * @return The array length or 0 if the key is not found in context memory.
481          * @since 1.0
482          */
483         public static final int getArrayLength( SvcLogicContext ctx, String key, Logger log, LogLevel logLevel, String log_message ) {
484                 String ctxKey = ( key.endsWith("_length") ) ? key : key + "_length";
485                 try {
486                         return Integer.parseInt(ctx.getAttribute(ctxKey));
487                 }
488                 catch( NumberFormatException e ) {
489                         if( log != null && logLevel != null && log_message != null ) {
490                                 switch( logLevel ) {
491                                         case TRACE:
492                                                 log.trace(log_message);
493                                         case DEBUG:
494                                                 log.debug(log_message);
495                                                 break;
496                                         case INFO:
497                                                 log.info(log_message);
498                                                 break;
499                                         case WARN:
500                                                 log.warn(log_message);
501                                                 break;
502                                         case ERROR:
503                                                 log.error(log_message);
504                                                 break;
505                                 }
506                         }
507                 }
508
509                 return 0;
510         }
511
512         /**
513          * Prints sorted context memory key-value pairs to the log file at the log
514          * level. Returns immediately if the log level isn't enabled.
515          * <p>
516          * O(n log(n)) time where n = size of context memory
517          * @param ctx Reference to context memory
518          * @param log Reference to Logger to log to
519          * @param logLevel Logging level to log the context memory key-value pairs
520          * at.
521          * @since 1.0
522          */
523         public static final void logContextMemory( SvcLogicContext ctx, Logger log, LogLevel logLevel ) {
524                 logLevelIsEnabled( log, logLevel );
525
526                 // Print sorted context memory key-value pairs to the log
527                 ArrayList<String> keys = new ArrayList<String>(ctx.getAttributeKeySet());
528                 Collections.sort(keys);
529                 for( String key : keys ) {
530                         logMessageAtLevel( log, logLevel, key + " = " + ctx.getAttribute(key) );
531                 }
532         }
533
534
535
536         // ========== PRIVATE FUNCTIONS ==========
537
538         // TODO: javadoc
539         /**
540          *
541          * @param parameters
542          * @param log
543          * @param loglevel
544          * @since 7.0.1
545          */
546         public static final void logExecuteNodeParameters( Map<String,String> parameters, Logger log, LogLevel loglevel ) {
547                 logLevelIsEnabled( log, loglevel );
548
549                 for( Map.Entry<String,String> param : parameters.entrySet() ) {
550                         logMessageAtLevel( log, loglevel, "PARAM: " + param.getKey() + " = " + param.getValue() );
551                 }
552         }
553
554         // TODO: javadoc
555         /**
556          * Returns true if the loglevel is enabled. Otherwise, returns false.
557          * @param log Reference to logger
558          * @param loglevel Log level to check if enabled
559          * @return True if the loglevel is enabled. Otherwise, false
560          * @since 7.0.1
561          */
562         private static final boolean logLevelIsEnabled( Logger log, LogLevel loglevel ) {
563                 // Return immediately if logging level isn't enabled
564                 switch( loglevel ) {
565                         case TRACE:
566                                 if( log.isTraceEnabled() ) { return true; }
567                                 return false;
568                         case DEBUG:
569                                 if( log.isDebugEnabled() ) { return true; }
570                                 return false;
571                         case INFO:
572                                 if( log.isInfoEnabled() ) { return true; }
573                                 return false;
574                         case WARN:
575                                 if( log.isWarnEnabled() ) { return true; }
576                                 return false;
577                         case ERROR:
578                                 if( log.isErrorEnabled() ) { return true; }
579                                 return false;
580                         default:
581                                 throw new IllegalArgumentException("Unknown LogLevel: " + loglevel.toString());
582                 }
583         }
584
585         // TODO: javadoc
586         /**
587          *
588          * @param log
589          * @param loglevel
590          * @param msg
591          * @since 7.0.1
592          */
593         private static final void logMessageAtLevel( Logger log, LogLevel loglevel, String msg ) {
594                 switch( loglevel ) {
595                         case TRACE:
596                                 log.trace(msg);
597                                 return;
598                         case DEBUG:
599                                 log.debug(msg);
600                                 return;
601                         case INFO:
602                                 log.info(msg);
603                                 return;
604                         case WARN:
605                                 log.warn(msg);
606                                 return;
607                         case ERROR:
608                                 log.error(msg);
609                                 return;
610                 }
611         }
612
613
614
615         // ========== LOCAL CLASSES ==========
616
617         private class SortableCtxListElement implements Comparable<SortableCtxListElement> {
618                 HashMap<String,String> child_elements = new HashMap<String,String>();
619                 String[] sort_fields;
620
621                 public SortableCtxListElement( SvcLogicContext ctx, String root, String[] sort_fields ) {
622                         this.sort_fields = sort_fields;
623
624                         for( String key : ctx.getAttributeKeySet() ) {
625                                 if( key.startsWith(root) ) {
626                                         if( key.length() == root.length() ) {
627                                                 child_elements.put("", ctx.getAttribute(key));
628                                                 break;
629                                         }
630                                         else {
631                                                 child_elements.put(key.substring(root.length()+1), ctx.getAttribute(key));
632                                         }
633                                 }
634                         }
635                 }
636
637                 @Override
638                 public int compareTo(SortableCtxListElement arg0) {
639                         if( sort_fields == null ) {
640                                 return this.child_elements.get("").compareTo(arg0.child_elements.get(""));
641                         }
642
643                         for( String field : this.sort_fields ) {
644                                 int result = this.child_elements.get(field).compareTo(arg0.child_elements.get(field));
645                                 if( result != 0 ) {
646                                         return result;
647                                 }
648                         }
649
650                         return 0;
651                 }
652         }
653
654         /**
655      * Creates a file that contains the content of context memory.
656      * @param parameters - must contain the parameter filename
657      * @param ctx Reference to context memory
658      * @throws SvcLogicException thrown if file cannot be created or if parameters are missing
659      */
660         public static void printContext(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
661                 if (parameters == null || parameters.isEmpty()) {
662                         throw new SvcLogicException("no parameters passed");
663                 }
664
665                 checkParameters(parameters, new String[]{"filename"}, LOG);
666
667                 String fileName = parameters.get("filename");
668
669
670                 try (FileOutputStream fstr = new FileOutputStream(new File(fileName));
671                          PrintStream pstr = new PrintStream(fstr, true);)
672                 {
673                         pstr.println("#######################################");
674                         for (String attr : ctx.getAttributeKeySet()) {
675                                 pstr.println(attr + " = " + ctx.getAttribute(attr));
676                         }
677                 } catch (Exception e) {
678                         throw new SvcLogicException("Cannot write context to file " + fileName, e);
679                 }
680
681
682         }
683
684          /**
685      * Checks context memory for a set of required parameters
686      * Every parameter aside from prefix will be treated as mandatory
687      * @param parameters HashMap<String,String> of parameters passed by the DG to this function
688      * <table border="1">
689      *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
690      *  <tbody>
691      *      <tr><td>prefix</td><td>Optional</td><td>the prefix will be added to each parameter</td></tr>
692      *  </tbody>
693      * </table>
694      * @param ctx Reference to context memory
695      * @throws SvcLogicException
696      * @since 11.0.2
697      */
698         public static void requiredParameters(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
699                 if (parameters == null || parameters.keySet().size() < 1) {
700             String errorMessage = "requiredParameters should not be called if the parameters hashmap is null or empty!";
701             LOG.error(errorMessage);
702             throw new SvcLogicException(errorMessage);
703                 }
704                 String prefixValue = null;
705                 String prefix = "prefix";
706                 if(parameters.containsKey(prefix)){
707                     prefixValue = parameters.get(prefix);
708                     parameters.remove(prefix);
709                 }
710                 checkParameters(prefixValue, ctx.getAttributeKeySet(), parameters.keySet(), LOG);
711         }
712
713     private static void checkParameters(String prefixValue, Set<String> ctx, Set<String> parameters, Logger log) throws SvcLogicException {
714         for (String param : parameters) {
715             if (prefixValue != null) {
716                 param = prefixValue + param;
717             }
718             if (!ctx.contains(param)) {
719                 String errorMessage = "This method requires the parameters [" + StringUtils.join(parameters, ",")
720                         + "], but " + param + " was not passed in.";
721                 log.error(errorMessage);
722                 throw new SvcLogicException(errorMessage);
723             }
724         }
725     }
726
727     /**
728      *  is in a different DG invocation just before/after we call NCS and set the state to InProgress
729      */
730     /**
731     * setTime write the current date time to a string located at outputPath
732     * @param parameters - requires outputPath to not be null
733     * @param ctx Reference to context memory
734     * @throws SvcLogicException if a required parameter is missing an exception is thrown
735     */
736     public static void setTime(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException
737     {
738         checkParameters(parameters, new String[] { "outputPath" }, LOG);
739
740         // Set the DateFormat
741         // "2015-03-16T12:18:35.138Z"
742         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
743
744         // Parse the date
745         String ctxVariable = parameters.get("outputPath");
746         try {
747             String dateTime = format.format(new Date());
748             ctx.setAttribute(ctxVariable, dateTime);
749         } catch (Exception ex) {
750             throw new SvcLogicException("problem with setTime", ex);
751         }
752     }
753 }