TangCheng
2025-02-28 d787e447e95c7b897c2cc9c0e832f8d2e5084934
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
package com.smtservlet.util;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import javax.servlet.http.HttpServletRequest;
 
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
 
import com.fasterxml.uuid.Generators;
 
 
public final class SMTStatic 
{
    /**
     * 数据转换类型
     */
    public enum SMTConvType
    {
        Integer,
        Long,
        Float,
        Double,
        Date,
        String,
        MergeDate,
        MD5,
    }
    
    /**
     * 数据转换对于空字符串的处理
     */
    public enum SMTConvEmpty
    {
        SkipEmpty,
        KeepEmpty,
        ErrorEmpty,
    }
    
    /**
     * 计算时间用枚举
     */
    public enum SMTCalcTime
    {
        SET_MILLISECOND,
        ADD_SECOND,
        ADD_MINUTE,
        ADD_HOUR,
        ADD_DATE,
        ADD_MONTH,
        ADD_YEAR,
        SET_SECOND,
        SET_MINUTE,
        SET_HOUR,
        SET_DATE,
        SET_MONTH,
        SET_YEAR,
        ZERO_TIME,
    }
       
    /**
     * stringFormat使用的格式化类
     */
    public static class StringNamedFormat
    {
        /**
         * 参数名
         */
        public String _name;
        
        /**
         * 参数索引
         */
        public int _index;
        
        /**
         * 构造函数
         * 
         * @param name - 参数名
         * @param index - 参数索引
         */
        public StringNamedFormat(String name, int index)
        {
            _name = name;
            _index = index;
        }
        
    }
    private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String LOWER = UPPER.toLowerCase();
    private static final String DIGITS = "0123456789";
    private static final String SPECIAL = "!@#$%^&*()-_=+";
 
    private static final String ALL_CHARACTERS = UPPER + LOWER + DIGITS + SPECIAL;
 
    /**
     * stringFormat使用的参数通知函数
     */
    public static interface StringNamedNotify
    {
        /**
         * 通过命名参数获取值
         * 
         * @param name - 参数名
         * @param args - 输入的参数列表
         * @return - 转换后的字符串
         */
        Object getNamedValue(String name, Object[] args) throws Exception;
    }
    
    /**
     * 空json对象
     */
    public static Json emptyObject = Json.object();
    
    /**
     * stringFormat使用的正则匹配
     */
    private static final Pattern _patStringFormat = Pattern.compile("^\\{(\\d+|[#_A-Za-z\\$][^\\{%\\}]+)(\\%[^\\}]+)?\\}", 0);
    
    /**
     * 分析日期格式用的正则匹配
     */
    private static final Pattern _patDateFormat = Pattern.compile("^(\\d+)-(\\d+)-(\\d+)(?: (\\d+):(\\d+)(?::(\\d+))?)?$", 0);
 
    /**
     * html转换使用的映射表
     */
    private static final String[] _convCharToHtml = new String[]{"<", "&lt;", ">", "&gt;"};
 
    private static final Pattern _patTimeSpanFormat = Pattern.compile("(\\d+)([smhd])");
    
    private static final char[] _charSeqList = new char[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    
    private static final ThreadLocal <SimpleDateFormat> _dateFmt = SMTStatic.newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    /**
     * 生成线程安全的SimpleDateFormat对象
     * 
     * @param fmt - date格式
     * @return - 返回SimpleDateFormat对象
     */
    public static ThreadLocal <SimpleDateFormat> newSimpleDateFormat(final String fmt)
    {
        return new ThreadLocal <SimpleDateFormat>(){
             @Override 
             protected SimpleDateFormat initialValue() {
                 return new SimpleDateFormat(fmt);
         }
        };
    }
    
 
    
    /**
     * 判断字符串是否为空或null
     * 
     * @param str - 要判断的字符串
     * @return - 判断结果
     */
    public static boolean isNullOrEmpty(String str)
    {
        return (str == null || str.length() == 0);
    }
    
    /**
     * 格式化字符串
     * 
     * @param format - 要格式化的内容,可以用'{名称}'或'{索引}'来表示
     * @param args - 要格式化的参数,最后的参数可以跟StringNamedFormat或StringNamedNotify
     * @return - 返回格式化后的字符串
     */
    public static String stringFormat(String format, Object...args)
    {
        try
        {
            StringBuilder sbOut = new StringBuilder();
            Map<String, Integer> mapName2Index = null;
            StringNamedNotify notify = null;
            
            // 如果最后一个参数是StringNamedNotify,则按照这个设置
            if(args.length > 0 && args[args.length - 1] instanceof StringNamedNotify)
                notify = (StringNamedNotify)args[args.length - 1];
            
            for(int i = 0; i < format.length(); i ++)
            {
                char ch = format.charAt(i);
                if(ch == '\\')
                {
                    i++;
                    ch = format.charAt(i);
                    switch(ch)
                    {
                    case 'r':ch = '\r';break;
                    case 'n':ch = '\n';break;
                    case 'b':ch = '\b';break;
                    case 't':ch = '\t';break;
                    }
                    sbOut.append(ch);
                }
                else if(ch == '{')
                {
                    Matcher mat = _patStringFormat.matcher(format.substring(i));
                    if(!mat.find())
                        throw new RuntimeException(String.format("unknow format match for [%s] at [%d]", format.substring(i), i));
                    String fullFmt = mat.group();
                    String dataName = mat.group(1);
                    String dataFmt = mat.group(2);
                    Object value = null;
                    
                    // 如果当前是通知类型,则调用通知函数获得值
                    if(notify != null)
                    {
                        value = notify.getNamedValue(dataName, args);
                    }
                    // 如果参数第一个符号不是数字,则解析名称
                    else if(dataName.charAt(0) < '0' || dataName.charAt(0) > '9')
                    {
                        if(mapName2Index == null)
                        {
                            mapName2Index = new HashMap<String, Integer>();
                            
                            // 如果最后一个参数是名称数组,则只解析名称数组
                            if(args[args.length - 1] instanceof StringNamedFormat[])
                            {
                                for(StringNamedFormat named : (StringNamedFormat[])args[args.length - 1])
                                {
                                    mapName2Index.put(named._name, named._index);
                                }
                            }
                            // 最后一个参数不是名称数组,则解析每一个名称对象
                            else
                            {
                                for(int j = 0; j < args.length; j ++)
                                {
                                    if(args[j] instanceof StringNamedFormat)
                                    {
                                        StringNamedFormat named = (StringNamedFormat)args[j];
                                        mapName2Index.put(named._name, named._index);
                                    }
                                }
                            }
                            
                            if(!mapName2Index.containsKey(dataName))
                                throw new RuntimeException(String.format("format name [%s] is not found for string [%s]", dataName, format));
                            int dataIndex = mapName2Index.get(dataName);
                            if(dataIndex >= args.length)
                                throw new RuntimeException(String.format("format argument name [%s] index [%d] is out of range for string [%s]", dataName, dataIndex, format));
                            value = args[dataIndex];
                        }
                    }
                    // 如果第一个字符是数字,则解析索引
                    else
                    {
                        int dataIndex = Integer.parseInt(dataName);
                        if(dataIndex >= args.length)
                            throw new RuntimeException(String.format("format argument index [%d] is out of range for string [%s]", dataIndex, format));
                        value = args[dataIndex];
                    }
                    
                    
                    if(dataFmt == null)
                    {
                        sbOut.append(value == null ? "" : value.toString());
                    }
                    else
                    {
                        sbOut.append(String.format(dataFmt, value));
                    }
                    
                    i += fullFmt.length() - 1;
                }
                else
                {
                    sbOut.append(ch);
                }
            }
            
            return sbOut.toString();
        }
        catch(Exception ex)
        {
            throw new RuntimeException(String.format("stringFormat [%s] exception", format), ex);
        }
    }
 
    /**
     * 转换字符串成html格式
     * 
     * @param text - 要转换的字符串
     * @return - 返回转换后的html内容
     */
    public static String convStringToHtmlBody(String text)
    {
        for(int i = 0; i < _convCharToHtml.length; i += 2)
        {
            text = text.replace(_convCharToHtml[i + 0], _convCharToHtml[i + 1]);
        }
        return text;
    }
    
    public static String convHtmlBodyToString(String text)
    {
        for(int i = 0; i < _convCharToHtml.length; i += 2)
        {
            text = text.replace(_convCharToHtml[i + 1], _convCharToHtml[i + 0]);
        }
        return text;
    }
 
    /**
     * 读取UTF-8文本流的内容
     * 
     * @param inputStream - 要读取的文本流
     * @return - 返回读取的内容
     */
    public static String readTextStream(InputStream inputStream)
    {
        InputStreamReader rd = null;
        
        try
        {
            StringBuilder sb = new StringBuilder();
            int size = 0;
            char[] data = new char[10240];
            rd=new InputStreamReader(inputStream, "UTF-8");
            while((size = rd.read(data)) > 0)
            {
                sb.append(data, 0, size);
            }
            return sb.toString();
        }
        catch(Exception ex)
        {
            throw new RuntimeException(ex);
        }
        finally
        {
            if(rd != null)
                try {
                    rd.close();
                } catch (IOException e) {
                }
        }
    }
 
    /**
     * 从文本文件中读取UTF-8的文本
     * 
     * @param fileName - 文件名
     * @return - 返回文件内容
     */
    public static String readAllText(String fileName)
    {
        return readAllText(new File(fileName));
    }
    
    
    /**
     * 从文本文件中读取UTF-8的文本
     * 
     * @param fileName - 文件名
     * @return - 返回文件内容
     */
    public static String readAllText(File file)
    {
        FileInputStream fi = null;
        try
        {
            fi = new FileInputStream(file);
            return readTextStream(fi);
        }
        catch(Exception ex)
        {
            throw new RuntimeException(String.format("read file [%s] error", file.getAbsolutePath()), ex);
        }
        finally
        {
            if(fi != null)
            {
                try {
                    fi.close();
                } catch (IOException e) {
                }
            }
        }
    }
 
    /**
     * 将文本数据以UTF-8格式写入文件
     * 
     * @param file - 要写入的文件名
     * @param text - 要写入的内容
     */
    public static void saveTextFile(File file, String text) throws Exception
    {
        OutputStreamWriter wr = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
        
        try
        {
            wr.write(text);
        }
        finally
        {
            wr.close();
        }
    }
 
    /**
     * 将文本数据以UTF-8格式写入文件
     * 
     * @param file - 要写入的文件名
     * @param text - 要写入的内容
     * @param append-是否要追加
     */
    public static void saveTextFile(File file, String text, boolean append) throws Exception
    {
        OutputStreamWriter wr = new OutputStreamWriter(new FileOutputStream(file, append), "UTF-8");
        
        try
        {
            wr.write(text);
        }
        finally
        {
            wr.close();
        }
    }
 
    
    /**
     * 将字符串或日期类型转换成日期类型
     * 
     * @param value - 要转换的内容
     * @return - 返回转换后的日期
     */
    public static Date toDate(Object value)
    {
        if(value instanceof String)
        {
            Matcher m = _patDateFormat.matcher(value.toString());
            if(!m.find())
                throw new RuntimeException("parse time error");
            int year = Integer.parseInt(m.group(1));
            int month = Integer.parseInt(m.group(2));
            int day = Integer.parseInt(m.group(3));
            int hour = (m.group(4) != null) ? Integer.parseInt(m.group(4)) : 0;
            int minute = (m.group(5) != null) ? Integer.parseInt(m.group(5)) : 0;
            int second = (m.group(6) != null) ? Integer.parseInt(m.group(6)) : 0;
            //objValue = new Date(year - 1900, month, day, hour, minute, second);
            Calendar cal = Calendar.getInstance();
            cal.set(year, month - 1, day, hour, minute, second);
            cal.set(Calendar.MILLISECOND, 0);
            return cal.getTime();
        }
        
        if(value instanceof Date)
            return (Date)value;
        
        throw new RuntimeException("unknow date type");
    }
    
    /**
     * 通过json配置,将字符串转换成值,并保存在map中
     * 
     * @param jsonParams - json配置列表
     * @param mapName2Value - 返回的映射数据
     * @param skipEmpty - 对于空白的缺省处理
     * @param throwError - 出错是否抛异常
     * @return - true:全部成功,false:有错
     */
    public static boolean convStrByJson(String value, Json jsonParam, Map<String, Object> mapName2Value, SMTConvEmpty skipEmpty, boolean throwError) throws Exception
    {
        if(!jsonParam.isObject())
            throw new Exception("current is not map json:" + jsonParam.toString());
            
        // 如果没有field或ctrl属性,则直接忽略
        if(!jsonParam.has("field") || !jsonParam.has("ctrl") || !jsonParam.has("type"))
            return true;
        
        try
        {
            // 获取字段名
            boolean ret = true;
            String field = jsonParam.at("field").asString();
            SMTConvType type  = Enum.valueOf(SMTConvType.class, jsonParam.at("type").asString());
            String mode  = jsonParam.safeGetStr("mode", "only");
            if(jsonParam.has("empty"))
                skipEmpty = Enum.valueOf(SMTConvEmpty.class, jsonParam.at("empty").asString());
            
            // 取值
            if(mode.equals("array"))
            {
                String split = jsonParam.safeGetStr("split", ",");
                ret = insertValueToMap(field, convStrToArray(value, type, skipEmpty, split), mapName2Value, ret);
            }
            else if(mode.equals("only"))
            {
                ret = insertValueToMap(field, convStrToValue(value, type, skipEmpty), mapName2Value, ret);
            }
            else
                throw new Exception(String.format("mode [%s] is not 'between' or 'array' or 'only'", mode));
            
            return ret;
        }
        catch(Exception ex)
        {
            if(throwError)
                throw ex;
            
            return false;
        }
    }
    
    /**
     * 如果value是有效输入则插入map,否则返回false
     * @param key - 要插入的key
     * @param value - 要插入的值
     * @param mapName2Value - 返回插入的map
     * @param prevStat - 前一次的状态
     * @return - 如果失败则返回false, 如果成功则返回prevStat
     */
    protected static boolean insertValueToMap(String key, Object value, Map<String, Object> mapName2Value, boolean prevStat)
    {
        if(value == null)
            return true;
        if(value instanceof Exception)
            return false;
        
        mapName2Value.put(key, value);
        return prevStat;
    }
 
    /**
     * 将字符串转换成对应的数组类型
     * 
     * @param str - 字符串
     * @param type - 要转换的类型
     * @param skipEmpty - 是否跳过空字串
     * @param split - 数据切分
     * @return - null:无数据,Exception:有错误,其他:数组类型数据
     */
    public static Object convStrToArray(String str, SMTConvType type, SMTConvEmpty skipEmpty, String split)
    {
        if(str == null)
            return null;
        
        List<Object> list = new ArrayList<Object>();
        for(String value : str.split(split, -1))
        {
            Object ovalue = convStrToValue(value, type, skipEmpty);
            if(ovalue == null)
                continue;
            if(ovalue instanceof Throwable)
                return ovalue;
            list.add(ovalue);
        }
        
        if(list.size() == 0)
            return null;
        
        Object[] ret = new Object[list.size()];
        list.toArray(ret);
        return ret;
        
    }
    
    /**
     * 将字符串转换成指定的类型数据
     * 
     * @param str - 要转换的字符串
     * @param type - 要转换的类型
     * @param skipEmpty - 如果str为空是否返回null
     * @return - null:不需要转换,Throwable:转换出错,其他:正确的数据
     */
    public static Object convStrToValue(String str, SMTConvType type, SMTConvEmpty convEmpty)
    {
        try
        {
            if(str == null)
                return null;
            
            if(str.length() == 0)
            {
                if(convEmpty == SMTConvEmpty.SkipEmpty)
                    return null;
                
                if(convEmpty == SMTConvEmpty.ErrorEmpty)
                    throw new Exception("value is empty");
            }
            
            if(type == SMTConvType.String)
            {
                return str;
            }
            else if(type == SMTConvType.MD5)
            {
                return SMTStatic.convStrToMD5(str);
            }
            
            if(str.length() == 0)
            {
                if(convEmpty == SMTConvEmpty.KeepEmpty)
                    return null;
                throw new Exception("value is empty");
            }
            
            if(type == SMTConvType.Integer)
            {
                return Integer.parseInt(str, 10);
            }
            else if(type == SMTConvType.Long)
            {
                return Long.parseLong(str, 10);
            }
            else if(type == SMTConvType.Float)
            {
                return Float.parseFloat(str);
            }
            else if(type == SMTConvType.Double)
            {
                return Double.parseDouble(str);
            }
            else if(type == SMTConvType.Date)
            {
                return SMTStatic.toDate(str);
            }
            else if(type == SMTConvType.MergeDate)
            {
                // 将当前字符串转换成日期
                Date date = SMTStatic.toDate(str);
                
                // 如果当前字符串未设定时间,则将当前时间加入
                if(str.indexOf(":") < 0)
                {
                    Date now = new Date();
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(now);
                    date = SMTStatic.calculateTime(date, 
                            SMTCalcTime.SET_HOUR, cal.get(Calendar.HOUR_OF_DAY), 
                            SMTCalcTime.SET_MINUTE, cal.get(Calendar.MINUTE),
                            SMTCalcTime.SET_SECOND, cal.get(Calendar.SECOND));
                }
                return date;
            }
            throw new Exception("unsupport convert type:" + type.toString());
        }
        catch(Exception ex)
        {
            return new Exception(String.format("convert [%s] to [%s] error:[%s]", str, type, ex.getMessage()), ex);
        }
    }
    
    /**
     * 将任意类型转换成int
     * 
     * @param value - 要转换的类型
     * @return - 转换后的结果
     */
    public static int toInt(Object value)
    {
        try
        {
            if(value instanceof Integer)
                return (Integer)value;
            
            if(value instanceof Long)
                return (int)(long)(Long)value;
            
            if(value instanceof String)
                return Integer.parseInt((String)value);
            
            return (Integer)(value.getClass().getMethod("intValue").invoke(value));
        }
        catch(Exception ex)
        {
            return Integer.parseInt(value.toString());
        }
    }
    
    /**
     * 将任意类型转换成int
     * 
     * @param value - 要转换的类型
     * @return - 转换后的结果
     */
    public static long toLong(Object value)
    {
        try
        {
            if(value instanceof Long)
                return (Long)value;
            
            if(value instanceof Integer)
                return (long)(Integer)value;
            
            if(value instanceof String)
                return Long.parseLong((String)value);
 
            return (Long)(value.getClass().getMethod("longValue").invoke(value));
        }
        catch(Exception ex)
        {
            return Long.parseLong(value.toString());
        }
    }
 
    
    /**
     * 将任意类型转换成double
     * 
     * @param value - 要转换的类型
     * @return - 转换后的结果
     */
    public static double toDouble(Object value)
    {
        try
        {
            if(value instanceof Double)
                return (Double)value;
            
            if(value instanceof String)
                return Double.parseDouble((String)value);
            
            return (Double)(value.getClass().getMethod("doubleValue").invoke(value));
        }
        catch(Exception ex)
        {
            return Double.parseDouble(value.toString());
        }
    }
 
    
    /**
     * 将字符串转换成MD5模式
     * 
     * @param text - 原始字符串
     * @return - 转换后的MD5字符串
     */
    public static String convStrToMD5(String text)
    {
        try
        {
            StringBuilder sb = new StringBuilder();
            sb.append("PA");
            MessageDigest md = MessageDigest.getInstance("MD5"); 
            md.update(text.getBytes("UTF8")); 
            byte b[] = md.digest();
            for(int i = 0; i < b.length; i ++)
            {
                sb.append(((int)b[i]) & 0xFF);
            }
            sb.append("SS");
            return sb.toString();
        }
        catch(Exception ex)
        {
            throw new RuntimeException(ex);
        }
    }
 
    /**
     * 生成唯一序列号
     * 
     * @return - 返回唯一序列号
     */
    public static String newSequence()
    {
        //String time = _GuidFmtTime.get().format(new Date());
        //return  time + UUID.randomUUID().toString().replace("-", "").substring(15);
        StringBuilder sb = new StringBuilder();
        Date date = new Date();
        encodeSeqValue(date.getYear(), sb); //2
        encodeSeqValue(date.getMonth(), sb); // 1
        encodeSeqValue(date.getDate(), sb);// 1
        encodeSeqValue(date.getHours(), sb); //1
        encodeSeqValue(date.getMinutes(), sb);//1
        encodeSeqValue(date.getSeconds(), sb);//1
        encodeSeqValue((int)(date.getTime() % 1000), sb); //2
        sb.append(UUID.randomUUID().toString().replace("-", "").substring(9));
        return sb.toString();
    }
    
    private static void encodeSeqValue(int value, StringBuilder sb)
    {
        if(value < 60)
        {
            sb.append(_charSeqList[value]);
        }
        else
        {
            sb.append(_charSeqList[value / 60]);
            sb.append(_charSeqList[value % 60]);
        }
    }
    
 
    /**
     * 生成uuid序列号
     * 
     * @return - uuid序列号
     */
    public static String newUUID()
    {
        return Generators.timeBasedEpochRandomGenerator().generate().toString().replace("-", "");
        //return UUID.randomUUID().toString().replace("-", "");
    }
    
    /**
     * 转换成C语言类型的字符串
     * 
     * @param str - 原始字符串
     * @return - C语言类型字符串
     */
    public static String toCStr(String str)
    {
        return str.replace("\\", "\\\\").replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t").replace("\"", "\\\"");
    }
 
    /**
     * 从json中获取字段名
     * 
     * @param jsonField - 要获取的json对象
     * @param subKey - != null:子对象的路径,==null:获取当前对象
     * @param defField - 缺省字段值
     * @return - 返回取到的字段名或缺省字段名
     */
    public static String getFieldByJson(Json jsonField, String subKey, String defField)
    {
        if(subKey != null)
        {
            if(jsonField.has(subKey))
                jsonField = jsonField.getJson(subKey);
            else
                return defField;
        }
        
        if(jsonField.isString())
            return jsonField.asString();
        
        if(jsonField.isObject() && jsonField.has("field"))
            return jsonField.getJson("field").asString();
        
        return defField;
    }
    
    /**
     * 生成字典表的map list
     * 
     * @param recs - 字典表对应的记录集
     * @param typeKey - 类型字段名
     * @param nameKey - 名称字段名
     * @return - 返回创建后的列表
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Map<Object, Map<String, Object>>> getDictionaryMapList(List<Object> recs, String typeKey, String nameKey) 
    {
        Map<String, Map<Object, Map<String, Object>>> mapList = new HashMap<String, Map<Object, Map<String, Object>>>();
        
        for(Object rec : recs)
        {
            Map<String, Object> orec = (Map<String, Object>)rec;
            
            // 获取类型map表 
            String type = ((String)orec.get(typeKey)).toUpperCase();
            Map<Object, Map<String, Object>> mapType = mapList.get(type);
            if(mapType == null)
            {
                mapType = new LinkedHashMap<Object, Map<String, Object>>();
                mapList.put(type, mapType);
            }
 
            // 保存当前记录
            Object key = orec.get(nameKey);
            orec.remove(typeKey);
            mapType.put(key, orec);
        }
        return mapList;
    }
 
    /**
     * 将字符串转换成值
     * 
     * @param value - 字符串表现的值
     * @param type - 数据类型
     * @param skipEmpty - 空值是否返回null
     * @param throwError - 出错是否抛异常
     * @return - Exception:错误,null:忽略, 其他:返回转换后的值,
     */
    public static Object convStringToValue(String value, SMTConvType type, SMTConvEmpty skipEmpty, boolean throwError) throws Exception
    {
        Object ret = convStrToValue(value == null ? "" : value, type, skipEmpty);
        if(throwError && ret instanceof Exception)
            throw (Exception)ret;
        
        return ret;
    }
    
    /**
     * 将字符串转换成数组
     * 
     * @param value - 字符串表现的值
     * @param type - 数据类型
     * @param split - 切分字符串
     * @param skipEmpty - 空值是否返回null
     * @param throwError - 出错是否抛异常
     * @return - Exception:错误,null:忽略, 其他:返回转换后的值,
     */
    public static Object convStringToArray(String value, SMTConvType type, SMTConvEmpty skipEmpty, String split, boolean throwError) throws Exception
    {
        Object ret = convStrToArray(value == null ? "" : value, type, skipEmpty, split);
        if(throwError && ret instanceof Exception)
            throw (Exception)ret;
        
        return ret;
    }
    
    /**
     * 计算时间
     * 
     * @param date - 原始时间
     * @param args - SMTCalcTime计算类型,要计算的值。。。
     * @return - 计算后的时间
     */
    public static Date calculateTime(Date date, Object...args)
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        for(int i = 0; i < args.length; i += 2)
        {
            SMTCalcTime type = (SMTCalcTime) args[i + 0];
            int value = SMTStatic.toInt( args[i + 1]);
            
            switch(type)
            {
            case ADD_SECOND:
                cal.add(Calendar.SECOND, value);
                break;
            
            case ADD_MINUTE:
                cal.add(Calendar.MINUTE, value);
                break;
                
            case ADD_HOUR:
                cal.add(Calendar.HOUR_OF_DAY, value);
                break;
 
            case ADD_DATE:
                cal.add(Calendar.DATE, value);
                break;
 
            case ADD_MONTH:
                cal.add(Calendar.MONTH, value);
                break;
 
            case ADD_YEAR:
                cal.add(Calendar.YEAR, value);
                break;
 
            case SET_SECOND:
                cal.set(Calendar.SECOND, value);
                break;
            
            case SET_MINUTE:
                cal.set(Calendar.MINUTE, value);
                break;
                
            case SET_HOUR:
                cal.set(Calendar.HOUR_OF_DAY, value);
                break;
 
            case SET_DATE:
                cal.set(Calendar.DATE, value);
                break;
 
            case SET_MONTH:
                cal.set(Calendar.MONTH, value);
                break;
 
            case SET_YEAR:
                cal.set(Calendar.YEAR, value);
                break;
                
            case SET_MILLISECOND:
                cal.set(Calendar.MILLISECOND, value);
                break;
            
            case ZERO_TIME:
                cal.set(Calendar.HOUR_OF_DAY, 0);
                cal.set(Calendar.MINUTE, 0);
                cal.set(Calendar.SECOND, 0);
                cal.set(Calendar.MILLISECOND, 0);
                break;
            }
        }
        return cal.getTime();
    }
 
    /**
     * 将时间间隔字符串转换成对应的秒值
     * 时间格式: [数字][单位].....
     * 单位格式: d:天,h:小时,m:分钟,s:秒
     * 
     * @param timeSpan
     * @return
     * @throws Exception
     */
    public static long convTimeSpanToSecond(String timeSpan) throws Exception
    {
        Matcher m = _patTimeSpanFormat.matcher(timeSpan);
        int pos = 0;
        long retSecond = 0;
        while(m.find())
        {
            if(pos != m.start())
                throw new Exception("time span format is error");
            
            pos += m.group().length();
            long value = Integer.parseInt(m.group(1));
            
            switch(m.group(2).charAt(0))
            {
            case 'd':
                retSecond += value * 60 * 60 * 24;
                break;
                
            case 'h':
                retSecond += value * 60 * 60;
                break;
                
            case 'm':
                retSecond += value * 60;
                break;
                
            case 's':
                retSecond += value;
                break;
            }
        }
        return retSecond;
    }
    
    public static void loadJarPath(String filePath) 
    {
        loadJarPath(filePath, null);
    }
    /**
     * 读取jar包的路径
     * 
     * @param filePath - 要读取的路径名
     */
    public static void loadJarPath(String filePath, URLClassLoader classLoader) 
    {
        // 系统类库路径  
        File libPath = new File(filePath);  
          
        // 获取所有的.jar和.zip文件  
        File[] jarFiles = libPath.listFiles(new FilenameFilter() {  
            public boolean accept(File dir, String name) {  
                return name.endsWith(".jar") || name.endsWith(".zip");  
            }  
        });  
        loadJarFiles(jarFiles, classLoader);
    }
 
    /**
     * 将jar包文件列表读入系统
     * @param jarFiles - 要读入的文件列表
     */
    public static void loadJarFiles(File[] jarFiles, URLClassLoader classLoader) 
    {      
        try
        {
            if(classLoader == null)
                classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader(); 
            
            if (jarFiles != null) {  
                // 从URLClassLoader类中获取类所在文件夹的方法  
                // 对于jar文件,可以理解为一个存放class文件的文件夹  
                Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);  
                boolean accessible = method.isAccessible();     // 获取方法的访问权限  
                try {  
                    if (accessible == false) {  
                        method.setAccessible(true);     // 设置方法的访问权限  
                    }  
                    // 获取系统类加载器  
                    for (File file : jarFiles) {  
                        URL url = file.toURI().toURL();  
                        try {  
                            method.invoke(classLoader, url);    
                            //LOG.debug("读取jar文件[name={}]", file.getName());  
                        } catch (Exception e) {  
                            //LOG.error("读取jar文件[name={}]失败", file.getName());  
                        }  
                    }  
                } finally {  
                    method.setAccessible(accessible);  
                }  
            }
        }
        catch(Exception ex)
        {
            throw new RuntimeException(ex);
        }
    }
 
    public static String toString(Object value)
    {
        if(value == null)
            return "";
        if(value instanceof Date)
            return _dateFmt.get().format(value);
        else if((value instanceof Float) || (value instanceof Double) || (value instanceof BigDecimal))
        {
            String ret = String.format("%f", value);
            if(ret.indexOf('.') > 0)
            {
                for(int i = ret.length() - 1; i >= 0; i --)
                {
                    char ch = ret.charAt(i);
                    if(ch == '.')
                    {
                        return ret.substring(0, i);
                    }
                    else if(ch != '0')
                        return ret.substring(0, i + 1);
                }
            }
            
            return ret;
        }
        else if(value instanceof Integer || value instanceof Long || value instanceof Short || value instanceof BigInteger)
        {
            String ret = String.format("%d", value);
            return ret;
        }
        else if(value instanceof Throwable)
        {
               ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(byteOS);
            ((Throwable)value).printStackTrace(ps);
            String errMsg = new String(byteOS.toByteArray());
            return errMsg;
        }
        else
            return value.toString();
    }
    
    public static boolean checkFileName(String fileName, boolean incSubPath, boolean throwError) throws Exception
    {
        boolean check = fileName.indexOf("..") < 0;
        if(!incSubPath)
            check &= (fileName.indexOf("/") < 0 && fileName.indexOf("\\") < 0);
        if(!check && throwError)
            throw new Exception("file name include '..' : " + fileName);
        
        return check;
    }
 
    public static boolean moveFile(File fileSrc, File fileTag, boolean throwError)
    {
        // 如果文件名相同,则直接返回
        if(fileSrc.toString().equals(fileTag.toString()))
            return true;
        
        // 删除目标文件
        if(fileTag.exists())
            fileTag.delete();
        if(fileTag.exists())
        {
            if(throwError)
                throw new RuntimeException("delete move tag file error");
            return false;
        }
        
        // 尝试移动目标文件
        fileSrc.renameTo(fileTag);
        
        // 如果移动成功,则返回成功
        if(fileTag.exists())
            return true;
        
        // 将文件复制到目标目录
        File tempFile = new File(fileTag.getAbsolutePath() + ".temp");
        byte[] data = new byte[1024 * 100];
        int size;
        InputStream is = null;
        OutputStream os = null;
        try
        {
            // 复制文件
            is = new FileInputStream(fileSrc);
            os = new FileOutputStream(tempFile);
            while((size = is.read(data)) > 0)
            {
                os.write(data, 0, size);
            }
            
            // 关闭文件
            os.close();
            os = null;
            
            is.close();
            is = null;
            
            // 将临时文件改名
            tempFile.renameTo(fileTag);
            if(!fileTag.exists())
            {
                if(throwError)
                    throw new RuntimeException("temp file can't not rename to tag file");
                return false;
            }
            return true;
        }
        catch(Exception ex)
        {
            if(throwError)
                throw new RuntimeException("copy file error", ex);
            return false;
        }
        finally
        {
            try
            {
                if(is != null)
                    is.close();
                if(os != null)
                    os.close();
            }
            catch(Exception ex)
            {
                throw new RuntimeException("close file error", ex);
            }
        }
    }
 
    public static Map<String, Object> createMap(Object...args)
    {
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        for(int i = 0; i < args.length; i += 2)
        {
            if(args[i + 1] != null)
                map.put(args[i].toString(), args[i + 1]);
        }
        
        return map;
    }
    
    public static String throwToString(Throwable ex)
    {
        ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(byteOS);
        ex.printStackTrace(ps);
        String errMsg = new String(byteOS.toByteArray());
        return errMsg;
    }
    
    public static String getStdoutEncode()
    {
        String encoding = System.getProperty("sun.stdout.encoding");
        if(!SMTStatic.isNullOrEmpty(encoding))
            return encoding;
        
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win"))
            return "GB2312";
        else
            return "UTF-8";
    }
 
    public static String getJavaExe()
    {
        String os = System.getProperty("os.name").toLowerCase();
 
        if (os.contains("win"))
            return "java.exe";
        else
            return "java";
    }
    
    
    public static String getClientAddr(HttpServletRequest request)
    {
        String clientAddr = null;
        
        clientAddr = request.getHeader("x-real-ip");
        if(!SMTStatic.isNullOrEmpty(clientAddr) && !"unknown".equalsIgnoreCase(clientAddr))
            return clientAddr;
        
        clientAddr = request.getHeader("x-forwarded-for");
        if(!SMTStatic.isNullOrEmpty(clientAddr))
            clientAddr = clientAddr.split(",")[0];
        if(!SMTStatic.isNullOrEmpty(clientAddr) && !"unknown".equalsIgnoreCase(clientAddr))
            return clientAddr;
        
        clientAddr = request.getHeader("Proxy-client-IP");
        if(!SMTStatic.isNullOrEmpty(clientAddr) && !"unknown".equalsIgnoreCase(clientAddr))
            return clientAddr;
 
        clientAddr = request.getHeader("WL-Proxy-client-IP");
        if(!SMTStatic.isNullOrEmpty(clientAddr) && !"unknown".equalsIgnoreCase(clientAddr))
            return clientAddr;
 
        clientAddr = request.getRemoteAddr();
        return clientAddr;
    }
    
    public static String[] convProcessArg(List<String> args)
    {
        return convProcessArg(args.toArray(new String[args.size()]));
    }
    public static String[] convProcessArg(String[] args)
    {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win"))
        {
            for(int i = 0; i < args.length; i ++)
            {
                args[i] = args[i].replace("\"", "\\\"");
            }
        }
        
        return args;
    }
 
    public static String generatePassword(int length) {
        SecureRandom random = new SecureRandom();
        StringBuilder password = new StringBuilder();
 
        // 至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符
        password.append(UPPER.charAt(random.nextInt(UPPER.length())));
        password.append(LOWER.charAt(random.nextInt(LOWER.length())));
        password.append(DIGITS.charAt(random.nextInt(DIGITS.length())));
        password.append(SPECIAL.charAt(random.nextInt(SPECIAL.length())));
 
        // 生成剩余的字符
        for (int i = 4; i < length; i++) {
            int index = random.nextInt(ALL_CHARACTERS.length());
            password.append(ALL_CHARACTERS.charAt(index));
        }
 
        // 将密码随机打乱顺序
        for (int i = 0; i < length; i++) {
            int randomIndex = random.nextInt(length);
            char temp = password.charAt(i);
            password.setCharAt(i, password.charAt(randomIndex));
            password.setCharAt(randomIndex, temp);
        }
 
        return password.toString();
    }
    
    public static Document convStrToXmlDoc(String xmlStr) throws Exception
    {
        try
        {
            String xml = String.format(
                    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n%s", 
                    xmlStr);
            ByteArrayInputStream sqlXmlStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
            SAXReader reader=new SAXReader();
            Document doc=reader.read(sqlXmlStream);
            
            return doc;
        }
        catch(Exception ex)
        {
            throw new Exception("parse xml error : \n" + xmlStr, ex);
        }
    }
    
    public static void setInnerXml(Element xmlRoot, String xmlStr) throws Exception
    {
        xmlRoot.clearContent();
        Document doc = SMTStatic.convStrToXmlDoc("<ROOT>" + xmlStr + "</ROOT>");
        Element xmlSubRoot = (Element)doc.selectSingleNode("ROOT");
        xmlSubRoot.setParent(null);
        xmlRoot.add(doc.getRootElement());
    }
    
    public static Element getOrCreateXmlNode(Element xmlRoot, String tag) throws Exception
    {
        Element xmlNode = (Element) xmlRoot.selectSingleNode(tag);
        if(xmlNode == null)
            xmlNode = xmlRoot.addElement(tag);
        
        return xmlNode;
    }
    
 
    public static String getXmlAttr(Element xmlNode, String key) throws Exception
    {
        Attribute attr = xmlNode.attribute(key);
        if(attr == null)
            throw new Exception("can't find xml attr : " + key);
        
        return attr.getValue();
    }
    
    public static String getXmlAttr(Element xmlNode, String key, String defValue)
    {
        Attribute attr = xmlNode.attribute(key);
        if(attr == null)
            return defValue;
        
        return attr.getValue();
    }
    
    public static String formatJson(Json json)
    {
        StringBuilder sb = new StringBuilder();
        convJsonToString(0, json, "", sb);
        return sb.toString();
    }
    
    private static void convJsonToString(int level, Json json, String tailStr, StringBuilder sbRet)
    {
        String space = "    ";
        String perfix = "";
        for(int i = 0; i < level; i ++)
        {
            perfix += space;
        }
        if(json == null)
        {
            sbRet.append(perfix);
            sbRet.append("null" + tailStr + "\n");
        }
        else if(json.isObject())
        {
            //sbRet.append(perfix);
            if(sbRet.length() > 0)
            {
                char lastChar = sbRet.charAt(sbRet.length() - 1);
                if(lastChar == '\n')
                    sbRet.append(perfix);
            }
            sbRet.append("{\n");
            int curCount = 0;
            int totalCount = json.asJsonMap().size();
            for(Entry<String, Json> entry : json.asJsonMap().entrySet())
            {
                 String curTailStr = (curCount < (totalCount - 1)) ? "," : "";
                 sbRet.append(perfix + space);
                sbRet.append("\"" + SMTStatic.toCStr(entry.getKey().toString()) + "\":");
                Json value = entry.getValue();
                if(value.isObject() || value.isArray())
                {
                     convJsonToString(level + 1, value, curTailStr, sbRet);
 
                }
                else
                {
                    convJsonToString(0, value, curTailStr, sbRet);
 
                }
                
                if(curTailStr.length() == 0)
                    curTailStr = ",";
                   curCount ++;
            }
            sbRet.append(perfix);
            sbRet.append("}" + tailStr + "\n");
        }
        else if(json.isArray())
        {
            List<Json> naJson = json.asJsonList();
            if(sbRet.length() > 0)
            {
                char lastChar = sbRet.charAt(sbRet.length() - 1);
                if(lastChar == '\n')
                    sbRet.append(perfix);
            }
            sbRet.append("[\n");
            for(int i = 0; i < naJson.size(); i ++)
            {
                String curTailStr = (i < (naJson.size() - 1)) ? "," : "";
                Json value = naJson.get(i);
                if(value.isObject() || value.isArray())
                {
                    convJsonToString(level + 1, value, curTailStr, sbRet);
                }
                else
                {
                    convJsonToString(level + 1, value, curTailStr, sbRet);
                }
               
            }
            sbRet.append(perfix);
            sbRet.append("]" + tailStr + "\n");
        }
        else if(json.isString())
        {
            sbRet.append(perfix);
            sbRet.append(json.toString() + tailStr + "\n");
        }
        else
        {
            sbRet.append(perfix);
            sbRet.append(json.toString() + tailStr + "\n");
        }
    }
 
    public static Json convLLMAnswerToJson(String answer, boolean toArray)
    {
        String perfixJson = "```json\n";
        int pos = answer.indexOf(perfixJson);
        if(pos >= 0)
        {
            answer = answer.substring(pos + perfixJson.length());
            pos = answer.lastIndexOf("\n```");
            if(pos >= 0)
                answer = answer.substring(0, pos);
        }
        
        if(toArray)
        {
            if(answer.charAt(0) != '[')
            {
                answer = "[" + answer + "]";
            }
        }
        
        try
        {
            return Json.read(answer);
        }
        catch(Exception ex)
        {
            return Json.object("error", answer);
        }
    }
    
    public static String convLLMAnswerToJavascript(String answer)
    {
        String perfixJson = "```javascript\n";
        int pos = answer.indexOf(perfixJson);
        if(pos >= 0)
        {
            answer = answer.substring(pos + perfixJson.length());
            pos = answer.lastIndexOf("\n```");
            if(pos >= 0)
                answer = answer.substring(0, pos);
        }
        
        return answer;
    }
    
    private static Pattern _patTrimStrLineS = Pattern.compile("^[\\r\\n\\t ]+");
    private static Pattern _patTrimStrLineE = Pattern.compile("[\\r\\n\\t ]+$");
    
    public static String trimStrLines(String value)
    {
        Matcher m;
        m = _patTrimStrLineS.matcher(value);
        if(m.find())
            value = m.replaceAll("");
        m = _patTrimStrLineE.matcher(value);
        if(m.find())
            value = m.replaceAll("");
        
        return value;
    }
    
    public static String indentStrLines(String value, String perfix)
    {
        return value.replace("\r\n", "\n").replace("\n", "\n" + perfix);
    }
    
    public interface SMTReplaceTextNotify {
        String replace(String match);
    }
    
    public static String replaceRegexText(String text, Pattern pattern, SMTReplaceTextNotify callback)
    {
        Matcher matcher = pattern.matcher(text);
        StringBuffer result = new StringBuffer();
        while (matcher.find()) {
            String match = matcher.group();
            String replacement = callback.replace(match);
            matcher.appendReplacement(result, replacement);
        }
        matcher.appendTail(result);
        return result.toString();
  }
}