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 package org.jomc.tools;
32
33 import java.io.BufferedReader;
34 import java.io.ByteArrayInputStream;
35 import java.io.ByteArrayOutputStream;
36 import java.io.FileNotFoundException;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.InputStreamReader;
40 import java.io.OutputStreamWriter;
41 import java.io.Reader;
42 import java.io.StringReader;
43 import java.lang.ref.Reference;
44 import java.lang.ref.SoftReference;
45 import java.lang.reflect.InvocationTargetException;
46 import java.net.URL;
47 import java.text.DateFormat;
48 import java.text.Format;
49 import java.text.MessageFormat;
50 import java.text.SimpleDateFormat;
51 import java.util.ArrayList;
52 import java.util.Calendar;
53 import java.util.Collections;
54 import java.util.Enumeration;
55 import java.util.HashMap;
56 import java.util.List;
57 import java.util.Locale;
58 import java.util.Map;
59 import java.util.ResourceBundle;
60 import java.util.Set;
61 import java.util.concurrent.ConcurrentHashMap;
62 import java.util.concurrent.CopyOnWriteArrayList;
63 import java.util.concurrent.CopyOnWriteArraySet;
64 import java.util.logging.Level;
65 import javax.activation.MimeType;
66 import javax.activation.MimeTypeParseException;
67 import org.apache.commons.io.IOUtils;
68 import org.apache.commons.lang.StringEscapeUtils;
69 import org.apache.commons.lang.StringUtils;
70 import org.apache.velocity.Template;
71 import org.apache.velocity.VelocityContext;
72 import org.apache.velocity.app.VelocityEngine;
73 import org.apache.velocity.exception.ParseErrorException;
74 import org.apache.velocity.exception.ResourceNotFoundException;
75 import org.apache.velocity.exception.VelocityException;
76 import org.apache.velocity.runtime.RuntimeConstants;
77 import org.apache.velocity.runtime.RuntimeServices;
78 import org.apache.velocity.runtime.log.LogChute;
79 import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
80 import org.apache.velocity.runtime.resource.loader.URLResourceLoader;
81 import org.jomc.model.Argument;
82 import org.jomc.model.ArgumentType;
83 import org.jomc.model.Dependency;
84 import org.jomc.model.Implementation;
85 import org.jomc.model.InheritanceModel;
86 import org.jomc.model.Message;
87 import org.jomc.model.ModelObject;
88 import org.jomc.model.Modules;
89 import org.jomc.model.Multiplicity;
90 import org.jomc.model.Properties;
91 import org.jomc.model.Property;
92 import org.jomc.model.Specification;
93 import org.jomc.model.SpecificationReference;
94 import org.jomc.model.Specifications;
95 import org.jomc.model.Text;
96 import org.jomc.model.Texts;
97 import org.jomc.model.modlet.ModelHelper;
98 import org.jomc.modlet.Model;
99
100
101
102
103
104
105
106 public class JomcTool
107 {
108
109
110 public abstract static class Listener
111 {
112
113
114 public Listener()
115 {
116 super();
117 }
118
119
120
121
122
123
124
125
126
127
128 public void onLog( final Level level, final String message, final Throwable throwable )
129 {
130 if ( level == null )
131 {
132 throw new NullPointerException( "level" );
133 }
134 }
135
136 }
137
138
139 private static final byte[] NO_BYTES =
140 {
141 };
142
143
144 private static final String TEMPLATE_PREFIX =
145 JomcTool.class.getPackage().getName().replace( '.', '/' ) + "/templates/";
146
147
148 private static final String DEFAULT_TEMPLATE_PROFILE = "jomc-java";
149
150
151 private static volatile String defaultTemplateProfile;
152
153
154
155
156
157 private static final Level DEFAULT_LOG_LEVEL = Level.WARNING;
158
159
160 private static volatile Level defaultLogLevel;
161
162
163 private Model model;
164
165
166 private VelocityEngine velocityEngine;
167
168
169
170
171
172 private boolean defaultVelocityEngine;
173
174
175 private String templateEncoding;
176
177
178
179
180
181 private URL templateLocation;
182
183
184 private String inputEncoding;
185
186
187 private String outputEncoding;
188
189
190
191
192
193 private Map<String, Object> templateParameters;
194
195
196 private String templateProfile;
197
198
199 private String indentation;
200
201
202 private String lineSeparator;
203
204
205 private List<Listener> listeners;
206
207
208 private Level logLevel;
209
210
211
212
213
214 private Locale locale;
215
216
217 private volatile Reference<Map<String, String>> indentationCache;
218
219
220 private volatile Reference<Map<String, String>> templateLocationsCache;
221
222
223 private volatile Reference<Map<String, java.util.Properties>> templateProfilePropertiesCache;
224
225
226 private volatile Reference<Set<String>> javaKeywordsCache;
227
228
229 public JomcTool()
230 {
231 super();
232 }
233
234
235
236
237
238
239
240
241
242 public JomcTool( final JomcTool tool ) throws IOException
243 {
244 this();
245
246 if ( tool == null )
247 {
248 throw new NullPointerException( "tool" );
249 }
250
251 this.indentation = tool.indentation;
252 this.inputEncoding = tool.inputEncoding;
253 this.lineSeparator = tool.lineSeparator;
254 this.listeners = tool.listeners != null ? new CopyOnWriteArrayList<Listener>( tool.listeners ) : null;
255 this.logLevel = tool.logLevel;
256 this.model = tool.model != null ? tool.model.clone() : null;
257 this.outputEncoding = tool.outputEncoding;
258 this.templateEncoding = tool.templateEncoding;
259 this.templateProfile = tool.templateProfile;
260 this.velocityEngine = tool.velocityEngine;
261 this.defaultVelocityEngine = tool.defaultVelocityEngine;
262 this.locale = tool.locale;
263 this.templateParameters =
264 tool.templateParameters != null
265 ? Collections.synchronizedMap( new HashMap<String, Object>( tool.templateParameters ) )
266 : null;
267
268 this.templateLocation =
269 tool.templateLocation != null ? new URL( tool.templateLocation.toExternalForm() ) : null;
270
271 }
272
273
274
275
276
277
278
279
280
281
282
283 public List<Listener> getListeners()
284 {
285 if ( this.listeners == null )
286 {
287 this.listeners = new CopyOnWriteArrayList<Listener>();
288 }
289
290 return this.listeners;
291 }
292
293
294
295
296
297
298
299
300
301
302
303
304 public static Level getDefaultLogLevel()
305 {
306 if ( defaultLogLevel == null )
307 {
308 defaultLogLevel = Level.parse( System.getProperty( "org.jomc.tools.JomcTool.defaultLogLevel",
309 DEFAULT_LOG_LEVEL.getName() ) );
310
311 }
312
313 return defaultLogLevel;
314 }
315
316
317
318
319
320
321
322
323 public static void setDefaultLogLevel( final Level value )
324 {
325 defaultLogLevel = value;
326 }
327
328
329
330
331
332
333
334
335
336
337 public final Level getLogLevel()
338 {
339 if ( this.logLevel == null )
340 {
341 this.logLevel = getDefaultLogLevel();
342
343 if ( this.isLoggable( Level.CONFIG ) )
344 {
345 this.log( Level.CONFIG, getMessage( "defaultLogLevelInfo", this.logLevel.getLocalizedName() ), null );
346 }
347 }
348
349 return this.logLevel;
350 }
351
352
353
354
355
356
357
358
359
360 public final void setLogLevel( final Level value )
361 {
362 this.logLevel = value;
363 }
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379 public boolean isLoggable( final Level level )
380 {
381 if ( level == null )
382 {
383 throw new NullPointerException( "level" );
384 }
385
386 return level.intValue() >= this.getLogLevel().intValue();
387 }
388
389
390
391
392
393
394
395
396
397
398 public String getJavaPackageName( final Specification specification )
399 {
400 if ( specification == null )
401 {
402 throw new NullPointerException( "specification" );
403 }
404
405 return specification.getClazz() != null ? this.getJavaPackageName( specification.getClazz() ) : null;
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421 public String getJavaTypeName( final Specification specification, final boolean qualified )
422 {
423 if ( specification == null )
424 {
425 throw new NullPointerException( "specification" );
426 }
427
428 if ( specification.getClazz() != null )
429 {
430 final StringBuilder typeName = new StringBuilder( specification.getClazz().length() );
431 final String javaPackageName = this.getJavaPackageName( specification );
432
433 if ( qualified && javaPackageName.length() > 0 )
434 {
435 typeName.append( javaPackageName ).append( '.' );
436 }
437
438 typeName.append( javaPackageName.length() > 0
439 ? specification.getClazz().substring( javaPackageName.length() + 1 )
440 : specification.getClazz() );
441
442 return typeName.toString();
443 }
444
445 return null;
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459 public String getJavaClasspathLocation( final Specification specification )
460 {
461 if ( specification == null )
462 {
463 throw new NullPointerException( "specification" );
464 }
465
466 return specification.getClazz() != null
467 ? ( this.getJavaTypeName( specification, true ) ).replace( '.', '/' )
468 : null;
469
470 }
471
472
473
474
475
476
477
478
479
480
481
482
483 public String getJavaPackageName( final SpecificationReference reference )
484 {
485 if ( reference == null )
486 {
487 throw new NullPointerException( "reference" );
488 }
489
490 final Specification s = this.getModules().getSpecification( reference.getIdentifier() );
491 assert s != null : "Specification '" + reference.getIdentifier() + "' not found.";
492 return s.getClazz() != null ? this.getJavaPackageName( s ) : null;
493 }
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508 public String getJavaTypeName( final SpecificationReference reference, final boolean qualified )
509 {
510 if ( reference == null )
511 {
512 throw new NullPointerException( "reference" );
513 }
514
515 final Specification s = this.getModules().getSpecification( reference.getIdentifier() );
516 assert s != null : "Specification '" + reference.getIdentifier() + "' not found.";
517 return s.getClazz() != null ? this.getJavaTypeName( s, qualified ) : null;
518 }
519
520
521
522
523
524
525
526
527
528
529 public String getJavaPackageName( final Implementation implementation )
530 {
531 if ( implementation == null )
532 {
533 throw new NullPointerException( "implementation" );
534 }
535
536 return implementation.getClazz() != null ? this.getJavaPackageName( implementation.getClazz() ) : null;
537 }
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552 public String getJavaTypeName( final Implementation implementation, final boolean qualified )
553 {
554 if ( implementation == null )
555 {
556 throw new NullPointerException( "implementation" );
557 }
558
559 if ( implementation.getClazz() != null )
560 {
561 final StringBuilder typeName = new StringBuilder( implementation.getClazz().length() );
562 final String javaPackageName = this.getJavaPackageName( implementation );
563
564 if ( qualified && javaPackageName.length() > 0 )
565 {
566 typeName.append( javaPackageName ).append( '.' );
567 }
568
569 typeName.append( javaPackageName.length() > 0
570 ? implementation.getClazz().substring( javaPackageName.length() + 1 )
571 : implementation.getClazz() );
572
573 return typeName.toString();
574 }
575
576 return null;
577 }
578
579
580
581
582
583
584
585
586
587
588 public String getJavaClasspathLocation( final Implementation implementation )
589 {
590 if ( implementation == null )
591 {
592 throw new NullPointerException( "implementation" );
593 }
594
595 return implementation.getClazz() != null
596 ? ( this.getJavaTypeName( implementation, true ) ).replace( '.', '/' )
597 : null;
598
599 }
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615 @Deprecated
616 public List<String> getJavaInterfaceNames( final Implementation implementation, final boolean qualified )
617 {
618 if ( implementation == null )
619 {
620 throw new NullPointerException( "implementation" );
621 }
622
623 return this.getImplementedJavaTypeNames( implementation, qualified );
624 }
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641 public List<String> getImplementedJavaTypeNames( final Implementation implementation, final boolean qualified )
642 {
643 if ( implementation == null )
644 {
645 throw new NullPointerException( "implementation" );
646 }
647
648 final Specifications specs = this.getModules().getSpecifications( implementation.getIdentifier() );
649 final List<String> col = new ArrayList<String>( specs == null ? 0 : specs.getSpecification().size() );
650
651 if ( specs != null )
652 {
653 for ( int i = 0, s0 = specs.getSpecification().size(); i < s0; i++ )
654 {
655 final Specification s = specs.getSpecification().get( i );
656
657 if ( s.getClazz() != null )
658 {
659 final String typeName = this.getJavaTypeName( s, qualified );
660 if ( !col.contains( typeName ) )
661 {
662 col.add( typeName );
663 }
664 }
665 }
666 }
667
668 return Collections.unmodifiableList( col );
669 }
670
671
672
673
674
675
676
677
678
679
680 public String getJavaTypeName( final Argument argument )
681 {
682 if ( argument == null )
683 {
684 throw new NullPointerException( "argument" );
685 }
686
687 String javaTypeName = "java.lang.String";
688
689 if ( argument.getType() == ArgumentType.DATE || argument.getType() == ArgumentType.TIME )
690 {
691 javaTypeName = "java.util.Date";
692 }
693 else if ( argument.getType() == ArgumentType.NUMBER )
694 {
695 javaTypeName = "java.lang.Number";
696 }
697
698 return javaTypeName;
699 }
700
701
702
703
704
705
706
707
708
709
710
711
712 public String getJavaMethodParameterName( final Argument argument )
713 {
714 if ( argument == null )
715 {
716 throw new NullPointerException( "argument" );
717 }
718
719 return this.getJavaMethodParameterName( argument.getName() );
720 }
721
722
723
724
725
726
727
728
729
730
731
732
733 public String getJavaTypeName( final Property property, final boolean boxify )
734 {
735 if ( property == null )
736 {
737 throw new NullPointerException( "property" );
738 }
739
740 if ( property.getType() != null )
741 {
742 final String typeName = property.getType();
743
744 if ( boxify )
745 {
746 if ( Boolean.TYPE.getName().equals( typeName ) )
747 {
748 return Boolean.class.getName();
749 }
750 if ( Byte.TYPE.getName().equals( typeName ) )
751 {
752 return Byte.class.getName();
753 }
754 if ( Character.TYPE.getName().equals( typeName ) )
755 {
756 return Character.class.getName();
757 }
758 if ( Double.TYPE.getName().equals( typeName ) )
759 {
760 return Double.class.getName();
761 }
762 if ( Float.TYPE.getName().equals( typeName ) )
763 {
764 return Float.class.getName();
765 }
766 if ( Integer.TYPE.getName().equals( typeName ) )
767 {
768 return Integer.class.getName();
769 }
770 if ( Long.TYPE.getName().equals( typeName ) )
771 {
772 return Long.class.getName();
773 }
774 if ( Short.TYPE.getName().equals( typeName ) )
775 {
776 return Short.class.getName();
777 }
778 }
779
780 return typeName;
781 }
782
783 return property.getAny() != null ? Object.class.getName() : String.class.getName();
784 }
785
786
787
788
789
790
791
792
793
794
795
796
797 public boolean isJavaPrimitiveType( final Property property )
798 {
799 if ( property == null )
800 {
801 throw new NullPointerException( "property" );
802 }
803
804 return !this.getJavaTypeName( property, false ).equals( this.getJavaTypeName( property, true ) );
805 }
806
807
808
809
810
811
812
813
814
815
816
817
818 public String getJavaGetterMethodName( final Property property )
819 {
820 if ( property == null )
821 {
822 throw new NullPointerException( "property" );
823 }
824
825 String prefix = "get";
826
827 final String javaTypeName = this.getJavaTypeName( property, true );
828 if ( Boolean.class.getName().equals( javaTypeName ) )
829 {
830 prefix = "is";
831 }
832
833 return prefix + this.getJavaIdentifier( property.getName(), true );
834 }
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849 public String getJavaSetterMethodName( final Property property )
850 {
851 if ( property == null )
852 {
853 throw new NullPointerException( "property" );
854 }
855
856 return "set" + this.getJavaIdentifier( property.getName(), true );
857 }
858
859
860
861
862
863
864
865
866
867
868
869
870 public String getJavaMethodParameterName( final Property property )
871 {
872 if ( property == null )
873 {
874 throw new NullPointerException( "property" );
875 }
876
877 return this.getJavaMethodParameterName( property.getName() );
878 }
879
880
881
882
883
884
885
886
887
888
889
890
891 public String getJavaTypeName( final Dependency dependency )
892 {
893 if ( dependency == null )
894 {
895 throw new NullPointerException( "dependency" );
896 }
897
898 final Specification s = this.getModules().getSpecification( dependency.getIdentifier() );
899
900 if ( s != null && s.getClazz() != null )
901 {
902 final StringBuilder typeName = new StringBuilder( s.getClazz().length() );
903 typeName.append( this.getJavaTypeName( s, true ) );
904 if ( s.getMultiplicity() == Multiplicity.MANY && dependency.getImplementationName() == null )
905 {
906 typeName.append( "[]" );
907 }
908
909 return typeName.toString();
910 }
911
912 return null;
913 }
914
915
916
917
918
919
920
921
922
923
924
925
926 public String getJavaGetterMethodName( final Dependency dependency )
927 {
928 if ( dependency == null )
929 {
930 throw new NullPointerException( "dependency" );
931 }
932
933 return "get" + this.getJavaIdentifier( dependency.getName(), true );
934 }
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949 public String getJavaSetterMethodName( final Dependency dependency )
950 {
951 if ( dependency == null )
952 {
953 throw new NullPointerException( "dependency" );
954 }
955
956 return "set" + this.getJavaIdentifier( dependency.getName(), true );
957 }
958
959
960
961
962
963
964
965
966
967
968
969
970 public String getJavaMethodParameterName( final Dependency dependency )
971 {
972 if ( dependency == null )
973 {
974 throw new NullPointerException( "dependency" );
975 }
976
977 return this.getJavaMethodParameterName( dependency.getName() );
978 }
979
980
981
982
983
984
985
986
987
988
989
990
991 public String getJavaGetterMethodName( final Message message )
992 {
993 if ( message == null )
994 {
995 throw new NullPointerException( "message" );
996 }
997
998 return "get" + this.getJavaIdentifier( message.getName(), true );
999 }
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014 public String getJavaSetterMethodName( final Message message )
1015 {
1016 if ( message == null )
1017 {
1018 throw new NullPointerException( "message" );
1019 }
1020
1021 return "set" + this.getJavaIdentifier( message.getName(), true );
1022 }
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035 public String getJavaMethodParameterName( final Message message )
1036 {
1037 if ( message == null )
1038 {
1039 throw new NullPointerException( "message" );
1040 }
1041
1042 return this.getJavaMethodParameterName( message.getName() );
1043 }
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055 public String getJavaModifierName( final Implementation implementation, final Dependency dependency )
1056 {
1057 if ( implementation == null )
1058 {
1059 throw new NullPointerException( "implementation" );
1060 }
1061 if ( dependency == null )
1062 {
1063 throw new NullPointerException( "dependency" );
1064 }
1065
1066 return "private";
1067 }
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079 public String getJavaModifierName( final Implementation implementation, final Message message )
1080 {
1081 if ( implementation == null )
1082 {
1083 throw new NullPointerException( "implementation" );
1084 }
1085 if ( message == null )
1086 {
1087 throw new NullPointerException( "message" );
1088 }
1089
1090 return "private";
1091 }
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103 public String getJavaModifierName( final Implementation implementation, final Property property )
1104 {
1105 if ( implementation == null )
1106 {
1107 throw new NullPointerException( "implementation" );
1108 }
1109 if ( property == null )
1110 {
1111 throw new NullPointerException( "property" );
1112 }
1113
1114 String modifier = "private";
1115 final Properties specified = this.getModules().getSpecifiedProperties( implementation.getIdentifier() );
1116
1117 if ( specified != null && specified.getProperty( property.getName() ) != null )
1118 {
1119 modifier = "public";
1120 }
1121
1122 return modifier;
1123 }
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137 public String getJavadocComment( final Text text, final int indentationLevel, final String linePrefix )
1138 {
1139 if ( text == null )
1140 {
1141 throw new NullPointerException( "text" );
1142 }
1143 if ( linePrefix == null )
1144 {
1145 throw new NullPointerException( "linePrefix" );
1146 }
1147 if ( indentationLevel < 0 )
1148 {
1149 throw new IllegalArgumentException( Integer.toString( indentationLevel ) );
1150 }
1151
1152 BufferedReader reader = null;
1153 boolean suppressExceptionOnClose = true;
1154
1155 try
1156 {
1157 String javadoc = "";
1158
1159 if ( text.getValue() != null )
1160 {
1161 final String indent = this.getIndentation( indentationLevel );
1162 reader = new BufferedReader( new StringReader( text.getValue() ) );
1163 final StringBuilder builder = new StringBuilder( text.getValue().length() );
1164
1165 String line;
1166 while ( ( line = reader.readLine() ) != null )
1167 {
1168 builder.append( this.getLineSeparator() ).append( indent ).append( linePrefix ).
1169 append( line.replaceAll( "\\/\\*\\*", "/*" ).replaceAll( "\\*/", "/" ) );
1170
1171 }
1172
1173 if ( builder.length() > 0 )
1174 {
1175 javadoc =
1176 builder.substring( this.getLineSeparator().length() + indent.length() + linePrefix.length() );
1177
1178 if ( !new MimeType( text.getType() ).match( "text/html" ) )
1179 {
1180 javadoc = StringEscapeUtils.escapeHtml( javadoc );
1181 }
1182 }
1183 }
1184
1185 suppressExceptionOnClose = false;
1186 return javadoc;
1187 }
1188 catch ( final MimeTypeParseException e )
1189 {
1190 throw new AssertionError( e );
1191 }
1192 catch ( final IOException e )
1193 {
1194 throw new AssertionError( e );
1195 }
1196 finally
1197 {
1198 try
1199 {
1200 if ( reader != null )
1201 {
1202 reader.close();
1203 }
1204 }
1205 catch ( final IOException e )
1206 {
1207 if ( suppressExceptionOnClose )
1208 {
1209 this.log( Level.SEVERE, getMessage( e ), e );
1210 }
1211 else
1212 {
1213 throw new AssertionError( e );
1214 }
1215 }
1216 }
1217 }
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236 public String getJavadocComment( final Texts texts, final int indentationLevel, final String linePrefix )
1237 {
1238 if ( texts == null )
1239 {
1240 throw new NullPointerException( "texts" );
1241 }
1242 if ( linePrefix == null )
1243 {
1244 throw new NullPointerException( "linePrefix" );
1245 }
1246 if ( indentationLevel < 0 )
1247 {
1248 throw new IllegalArgumentException( Integer.toString( indentationLevel ) );
1249 }
1250
1251 return this.getJavadocComment( texts.getText( this.getLocale().getLanguage() ), indentationLevel, linePrefix );
1252 }
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263 public String getJavaString( final String str )
1264 {
1265 return StringEscapeUtils.escapeJava( str );
1266 }
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279 public String getJavaIdentifier( final String str, final boolean capitalize )
1280 {
1281 String identifier = null;
1282
1283 if ( str != null )
1284 {
1285 final int len = str.length();
1286 final StringBuilder builder = new StringBuilder( len );
1287 boolean uc = capitalize;
1288
1289 for ( int i = 0; i < len; i++ )
1290 {
1291 final char c = str.charAt( i );
1292 final String charString = Character.toString( c );
1293
1294 if ( builder.length() > 0 )
1295 {
1296 if ( Character.isJavaIdentifierPart( c ) )
1297 {
1298 builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
1299 uc = false;
1300 }
1301 else
1302 {
1303 uc = true;
1304 }
1305 }
1306 else
1307 {
1308 if ( Character.isJavaIdentifierStart( c ) )
1309 {
1310 builder.append( uc ? charString.toUpperCase( this.getLocale() )
1311 : charString.toLowerCase( this.getLocale() ) );
1312
1313 uc = false;
1314 }
1315 else
1316 {
1317 uc = capitalize;
1318 }
1319 }
1320 }
1321
1322 identifier = builder.toString();
1323
1324 if ( identifier.length() <= 0 && this.isLoggable( Level.WARNING ) )
1325 {
1326 this.log( Level.WARNING, getMessage( "invalidJavaIdentifier", str ), null );
1327 }
1328 }
1329
1330 return identifier;
1331 }
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342 private String getJavaMethodParameterName( final String str )
1343 {
1344 String methodParameterName = null;
1345
1346 if ( str != null )
1347 {
1348 final int len = str.length();
1349 final StringBuilder builder = new StringBuilder( len );
1350 boolean uc = false;
1351
1352 for ( int i = 0; i < len; i++ )
1353 {
1354 final char c = str.charAt( i );
1355 final String charString = Character.toString( c );
1356
1357 if ( builder.length() > 0 )
1358 {
1359 if ( Character.isJavaIdentifierPart( c ) )
1360 {
1361 builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
1362 uc = false;
1363 }
1364 else
1365 {
1366 uc = true;
1367 }
1368 }
1369 else if ( Character.isJavaIdentifierStart( c ) )
1370 {
1371 builder.append( charString.toLowerCase( this.getLocale() ) );
1372 }
1373 }
1374
1375 methodParameterName = builder.toString();
1376
1377 if ( methodParameterName.length() <= 0 && this.isLoggable( Level.WARNING ) )
1378 {
1379 this.log( Level.WARNING, getMessage( "invalidJavaMethodParameterName", str ), null );
1380 }
1381
1382 if ( this.getJavaKeywords().contains( methodParameterName ) )
1383 {
1384 methodParameterName = "_" + methodParameterName;
1385 }
1386 }
1387
1388 return methodParameterName;
1389 }
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401 public boolean isJavaDefaultPackage( final Specification specification )
1402 {
1403 if ( specification == null )
1404 {
1405 throw new NullPointerException( "specification" );
1406 }
1407
1408 return specification.getClazz() != null && this.getJavaPackageName( specification ).length() == 0;
1409 }
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421 public boolean isJavaDefaultPackage( final Implementation implementation )
1422 {
1423 if ( implementation == null )
1424 {
1425 throw new NullPointerException( "implementation" );
1426 }
1427
1428 return implementation.getClazz() != null && this.getJavaPackageName( implementation ).length() == 0;
1429 }
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442 public String getHtmlString( final String str )
1443 {
1444 return StringEscapeUtils.escapeHtml( str );
1445 }
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458 public String getXmlString( final String str )
1459 {
1460 return StringEscapeUtils.escapeXml( str );
1461 }
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474 public String getJavaScriptString( final String str )
1475 {
1476 return StringEscapeUtils.escapeJavaScript( str );
1477 }
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490 public String getSqlString( final String str )
1491 {
1492 return StringEscapeUtils.escapeSql( str );
1493 }
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506 public String getCsvString( final String str )
1507 {
1508 return StringEscapeUtils.escapeCsv( str );
1509 }
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522 public String getBooleanString( final Boolean b )
1523 {
1524 final MessageFormat messageFormat = new MessageFormat( ResourceBundle.getBundle(
1525 JomcTool.class.getName().replace( '.', '/' ), this.getLocale() ).
1526 getString( b ? "booleanStringTrue" : "booleanStringFalse" ), this.getLocale() );
1527
1528 return messageFormat.format( null );
1529 }
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540 public String getDisplayLanguage( final String language )
1541 {
1542 if ( language == null )
1543 {
1544 throw new NullPointerException( "language" );
1545 }
1546
1547 final Locale l = new Locale( language );
1548 return l.getDisplayLanguage( l );
1549 }
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562 public String getShortDate( final Calendar calendar )
1563 {
1564 if ( calendar == null )
1565 {
1566 throw new NullPointerException( "calendar" );
1567 }
1568
1569 return DateFormat.getDateInstance( DateFormat.SHORT, this.getLocale() ).format( calendar.getTime() );
1570 }
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585 public String getMediumDate( final Calendar calendar )
1586 {
1587 if ( calendar == null )
1588 {
1589 throw new NullPointerException( "calendar" );
1590 }
1591
1592 return DateFormat.getDateInstance( DateFormat.MEDIUM, this.getLocale() ).format( calendar.getTime() );
1593 }
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606 public String getLongDate( final Calendar calendar )
1607 {
1608 if ( calendar == null )
1609 {
1610 throw new NullPointerException( "calendar" );
1611 }
1612
1613 return DateFormat.getDateInstance( DateFormat.LONG, this.getLocale() ).format( calendar.getTime() );
1614 }
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629 public String getIsoDate( final Calendar calendar )
1630 {
1631 if ( calendar == null )
1632 {
1633 throw new NullPointerException( "calendar" );
1634 }
1635
1636 return new SimpleDateFormat( "yyyy-DDD", this.getLocale() ).format( calendar.getTime() );
1637 }
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650 public String getShortTime( final Calendar calendar )
1651 {
1652 if ( calendar == null )
1653 {
1654 throw new NullPointerException( "calendar" );
1655 }
1656
1657 return DateFormat.getTimeInstance( DateFormat.SHORT, this.getLocale() ).format( calendar.getTime() );
1658 }
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673 public String getMediumTime( final Calendar calendar )
1674 {
1675 if ( calendar == null )
1676 {
1677 throw new NullPointerException( "calendar" );
1678 }
1679
1680 return DateFormat.getTimeInstance( DateFormat.MEDIUM, this.getLocale() ).format( calendar.getTime() );
1681 }
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694 public String getLongTime( final Calendar calendar )
1695 {
1696 if ( calendar == null )
1697 {
1698 throw new NullPointerException( "calendar" );
1699 }
1700
1701 return DateFormat.getTimeInstance( DateFormat.LONG, this.getLocale() ).format( calendar.getTime() );
1702 }
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717 public String getIsoTime( final Calendar calendar )
1718 {
1719 if ( calendar == null )
1720 {
1721 throw new NullPointerException( "calendar" );
1722 }
1723
1724 return new SimpleDateFormat( "HH:mm", this.getLocale() ).format( calendar.getTime() );
1725 }
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738 public String getShortDateTime( final Calendar calendar )
1739 {
1740 if ( calendar == null )
1741 {
1742 throw new NullPointerException( "calendar" );
1743 }
1744
1745 return DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, this.getLocale() ).
1746 format( calendar.getTime() );
1747
1748 }
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763 public String getMediumDateTime( final Calendar calendar )
1764 {
1765 if ( calendar == null )
1766 {
1767 throw new NullPointerException( "calendar" );
1768 }
1769
1770 return DateFormat.getDateTimeInstance( DateFormat.MEDIUM, DateFormat.MEDIUM, this.getLocale() ).
1771 format( calendar.getTime() );
1772
1773 }
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786 public String getLongDateTime( final Calendar calendar )
1787 {
1788 if ( calendar == null )
1789 {
1790 throw new NullPointerException( "calendar" );
1791 }
1792
1793 return DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG, this.getLocale() ).
1794 format( calendar.getTime() );
1795
1796 }
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811 public String getIsoDateTime( final Calendar calendar )
1812 {
1813 if ( calendar == null )
1814 {
1815 throw new NullPointerException( "calendar" );
1816 }
1817
1818
1819 return new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ", this.getLocale() ).format( calendar.getTime() );
1820 }
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832 public String getYears( final Calendar start, final Calendar end )
1833 {
1834 if ( start == null )
1835 {
1836 throw new NullPointerException( "start" );
1837 }
1838 if ( end == null )
1839 {
1840 throw new NullPointerException( "end" );
1841 }
1842
1843 final Format yearFormat = new SimpleDateFormat( "yyyy", this.getLocale() );
1844 final int s = start.get( Calendar.YEAR );
1845 final int e = end.get( Calendar.YEAR );
1846 final StringBuilder years = new StringBuilder();
1847
1848 if ( s != e )
1849 {
1850 if ( s < e )
1851 {
1852 years.append( yearFormat.format( start.getTime() ) ).append( " - " ).
1853 append( yearFormat.format( end.getTime() ) );
1854
1855 }
1856 else
1857 {
1858 years.append( yearFormat.format( end.getTime() ) ).append( " - " ).
1859 append( yearFormat.format( start.getTime() ) );
1860
1861 }
1862 }
1863 else
1864 {
1865 years.append( yearFormat.format( start.getTime() ) );
1866 }
1867
1868 return years.toString();
1869 }
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879 public final Model getModel()
1880 {
1881 if ( this.model == null )
1882 {
1883 this.model = new Model();
1884 this.model.setIdentifier( ModelObject.MODEL_PUBLIC_ID );
1885 }
1886
1887 return this.model;
1888 }
1889
1890
1891
1892
1893
1894
1895
1896
1897 public final void setModel( final Model value )
1898 {
1899 this.model = value;
1900 }
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913 @Deprecated
1914 public Modules getModules()
1915 {
1916 Modules modules = ModelHelper.getModules( this.getModel() );
1917
1918 if ( modules == null )
1919 {
1920 modules = new Modules();
1921 ModelHelper.setModules( this.getModel(), modules );
1922 }
1923
1924 return modules;
1925 }
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936 public final VelocityEngine getVelocityEngine() throws IOException
1937 {
1938 if ( this.velocityEngine == null )
1939 {
1940
1941 class JomcLogChute implements LogChute
1942 {
1943
1944 JomcLogChute()
1945 {
1946 super();
1947 }
1948
1949 public void init( final RuntimeServices runtimeServices ) throws Exception
1950 {
1951 }
1952
1953 public void log( final int level, final String message )
1954 {
1955 this.log( level, message, null );
1956 }
1957
1958 public void log( final int level, final String message, final Throwable throwable )
1959 {
1960 JomcTool.this.log( Level.FINEST, message, throwable );
1961 }
1962
1963 public boolean isLevelEnabled( final int level )
1964 {
1965 return isLoggable( Level.FINEST );
1966 }
1967
1968 }
1969
1970 final VelocityEngine engine = new VelocityEngine();
1971 engine.setProperty( RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE.toString() );
1972 engine.setProperty( RuntimeConstants.VM_ARGUMENTS_STRICT, Boolean.TRUE.toString() );
1973 engine.setProperty( RuntimeConstants.STRICT_MATH, Boolean.TRUE.toString() );
1974 engine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new JomcLogChute() );
1975
1976 engine.setProperty( RuntimeConstants.RESOURCE_LOADER, "class" );
1977 engine.setProperty( "class.resource.loader.class", ClasspathResourceLoader.class.getName() );
1978 engine.setProperty( "class.resource.loader.cache", Boolean.TRUE.toString() );
1979
1980 if ( this.getTemplateLocation() != null )
1981 {
1982 engine.setProperty( RuntimeConstants.RESOURCE_LOADER, "class,url" );
1983 engine.setProperty( "url.resource.loader.class", URLResourceLoader.class.getName() );
1984 engine.setProperty( "url.resource.loader.cache", Boolean.TRUE.toString() );
1985 engine.setProperty( "url.resource.loader.root", this.getTemplateLocation().toExternalForm() );
1986 engine.setProperty( "url.resource.loader.timeout", Integer.toString( 60000 ) );
1987 }
1988
1989 this.velocityEngine = engine;
1990 this.defaultVelocityEngine = true;
1991 }
1992
1993 return this.velocityEngine;
1994 }
1995
1996
1997
1998
1999
2000
2001
2002
2003 public final void setVelocityEngine( final VelocityEngine value )
2004 {
2005 this.velocityEngine = value;
2006 this.defaultVelocityEngine = false;
2007 }
2008
2009
2010
2011
2012
2013
2014
2015
2016 public VelocityContext getVelocityContext()
2017 {
2018 final Calendar now = Calendar.getInstance();
2019 final VelocityContext ctx =
2020 new VelocityContext( new HashMap<String, Object>( this.getTemplateParameters() ) );
2021
2022 this.mergeTemplateProfileProperties( this.getTemplateProfile(), this.getLocale().getLanguage(), ctx );
2023 this.mergeTemplateProfileProperties( this.getTemplateProfile(), null, ctx );
2024 this.mergeTemplateProfileProperties( getDefaultTemplateProfile(), this.getLocale().getLanguage(), ctx );
2025 this.mergeTemplateProfileProperties( getDefaultTemplateProfile(), null, ctx );
2026
2027 this.getModules();
2028 final Model clonedModel = this.getModel().clone();
2029 final Modules clonedModules = ModelHelper.getModules( clonedModel );
2030 assert clonedModules != null : "Unexpected missing modules for model '" + clonedModel.getIdentifier() + "'.";
2031
2032 ctx.put( "model", clonedModel );
2033 ctx.put( "modules", clonedModules );
2034 ctx.put( "imodel", new InheritanceModel( this.getModules() ) );
2035 ctx.put( "tool", this );
2036 ctx.put( "toolName", this.getClass().getName() );
2037 ctx.put( "toolVersion", getMessage( "projectVersion" ) );
2038 ctx.put( "toolUrl", getMessage( "projectUrl" ) );
2039 ctx.put( "calendar", now.getTime() );
2040
2041
2042 ctx.put( "now",
2043 new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ", this.getLocale() ).format( now.getTime() ) );
2044
2045 ctx.put( "year", new SimpleDateFormat( "yyyy", this.getLocale() ).format( now.getTime() ) );
2046 ctx.put( "month", new SimpleDateFormat( "MM", this.getLocale() ).format( now.getTime() ) );
2047 ctx.put( "day", new SimpleDateFormat( "dd", this.getLocale() ).format( now.getTime() ) );
2048 ctx.put( "hour", new SimpleDateFormat( "HH", this.getLocale() ).format( now.getTime() ) );
2049 ctx.put( "minute", new SimpleDateFormat( "mm", this.getLocale() ).format( now.getTime() ) );
2050 ctx.put( "second", new SimpleDateFormat( "ss", this.getLocale() ).format( now.getTime() ) );
2051 ctx.put( "timezone", new SimpleDateFormat( "Z", this.getLocale() ).format( now.getTime() ) );
2052 ctx.put( "shortDate", this.getShortDate( now ) );
2053 ctx.put( "mediumDate", this.getMediumDate( now ) );
2054 ctx.put( "longDate", this.getLongDate( now ) );
2055 ctx.put( "isoDate", this.getIsoDate( now ) );
2056 ctx.put( "shortTime", this.getShortTime( now ) );
2057 ctx.put( "mediumTime", this.getMediumTime( now ) );
2058 ctx.put( "longTime", this.getLongTime( now ) );
2059 ctx.put( "isoTime", this.getIsoTime( now ) );
2060 ctx.put( "shortDateTime", this.getShortDateTime( now ) );
2061 ctx.put( "mediumDateTime", this.getMediumDateTime( now ) );
2062 ctx.put( "longDateTime", this.getLongDateTime( now ) );
2063 ctx.put( "isoDateTime", this.getIsoDateTime( now ) );
2064
2065 return ctx;
2066 }
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080 public final Map<String, Object> getTemplateParameters()
2081 {
2082 if ( this.templateParameters == null )
2083 {
2084 this.templateParameters = Collections.synchronizedMap( new HashMap<String, Object>() );
2085 }
2086
2087 return this.templateParameters;
2088 }
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099 public final URL getTemplateLocation()
2100 {
2101 return this.templateLocation;
2102 }
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113 public final void setTemplateLocation( final URL value )
2114 {
2115 this.templateLocation = value;
2116 this.templateProfilePropertiesCache = null;
2117
2118 if ( this.defaultVelocityEngine )
2119 {
2120 this.setVelocityEngine( null );
2121 }
2122 }
2123
2124
2125
2126
2127
2128
2129
2130
2131 public final String getTemplateEncoding()
2132 {
2133 if ( this.templateEncoding == null )
2134 {
2135 this.templateEncoding = getMessage( "buildSourceEncoding" );
2136
2137 if ( this.isLoggable( Level.CONFIG ) )
2138 {
2139 this.log( Level.CONFIG, getMessage( "defaultTemplateEncoding", this.templateEncoding ), null );
2140 }
2141 }
2142
2143 return this.templateEncoding;
2144 }
2145
2146
2147
2148
2149
2150
2151
2152
2153 public final void setTemplateEncoding( final String value )
2154 {
2155 this.templateEncoding = value;
2156 }
2157
2158
2159
2160
2161
2162
2163
2164
2165 public final String getInputEncoding()
2166 {
2167 if ( this.inputEncoding == null )
2168 {
2169 this.inputEncoding = new InputStreamReader( new ByteArrayInputStream( NO_BYTES ) ).getEncoding();
2170
2171 if ( this.isLoggable( Level.CONFIG ) )
2172 {
2173 this.log( Level.CONFIG, getMessage( "defaultInputEncoding", this.inputEncoding ), null );
2174 }
2175 }
2176
2177 return this.inputEncoding;
2178 }
2179
2180
2181
2182
2183
2184
2185
2186
2187 public final void setInputEncoding( final String value )
2188 {
2189 this.inputEncoding = value;
2190 }
2191
2192
2193
2194
2195
2196
2197
2198
2199 public final String getOutputEncoding()
2200 {
2201 if ( this.outputEncoding == null )
2202 {
2203 this.outputEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
2204
2205 if ( this.isLoggable( Level.CONFIG ) )
2206 {
2207 this.log( Level.CONFIG, getMessage( "defaultOutputEncoding", this.outputEncoding ), null );
2208 }
2209 }
2210
2211 return this.outputEncoding;
2212 }
2213
2214
2215
2216
2217
2218
2219
2220
2221 public final void setOutputEncoding( final String value )
2222 {
2223 this.outputEncoding = value;
2224 }
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239 @Deprecated
2240 public static String getDefaultTemplateProfile()
2241 {
2242 if ( defaultTemplateProfile == null )
2243 {
2244 defaultTemplateProfile = System.getProperty( "org.jomc.tools.JomcTool.defaultTemplateProfile",
2245 DEFAULT_TEMPLATE_PROFILE );
2246
2247 }
2248
2249 return defaultTemplateProfile;
2250 }
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261 @Deprecated
2262 public static void setDefaultTemplateProfile( final String value )
2263 {
2264 defaultTemplateProfile = value;
2265 }
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275 public final String getTemplateProfile()
2276 {
2277 if ( this.templateProfile == null )
2278 {
2279 this.templateProfile = getDefaultTemplateProfile();
2280
2281 if ( this.isLoggable( Level.CONFIG ) )
2282 {
2283 this.log( Level.CONFIG, getMessage( "defaultTemplateProfile", this.templateProfile ), null );
2284 }
2285 }
2286
2287 return this.templateProfile;
2288 }
2289
2290
2291
2292
2293
2294
2295
2296
2297 public final void setTemplateProfile( final String value )
2298 {
2299 this.templateProfile = value;
2300 }
2301
2302
2303
2304
2305
2306
2307
2308
2309 public final String getIndentation()
2310 {
2311 if ( this.indentation == null )
2312 {
2313 this.indentation = " ";
2314
2315 if ( this.isLoggable( Level.CONFIG ) )
2316 {
2317 this.log( Level.CONFIG, getMessage( "defaultIndentation",
2318 StringEscapeUtils.escapeJava( this.indentation ) ), null );
2319
2320 }
2321 }
2322
2323 return this.indentation;
2324 }
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337 public final String getIndentation( final int level )
2338 {
2339 if ( level < 0 )
2340 {
2341 throw new IllegalArgumentException( Integer.toString( level ) );
2342 }
2343
2344 Map<String, String> map = this.indentationCache == null ? null : this.indentationCache.get();
2345
2346 if ( map == null )
2347 {
2348 map = new ConcurrentHashMap<String, String>( 8 );
2349 this.indentationCache = new SoftReference<Map<String, String>>( map );
2350 }
2351
2352 final String key = this.getIndentation() + "|" + level;
2353 String idt = map.get( key );
2354
2355 if ( idt == null )
2356 {
2357 final StringBuilder b = new StringBuilder( this.getIndentation().length() * level );
2358
2359 for ( int i = level; i > 0; i-- )
2360 {
2361 b.append( this.getIndentation() );
2362 }
2363
2364 idt = b.toString();
2365 map.put( key, idt );
2366 }
2367
2368 return idt;
2369 }
2370
2371
2372
2373
2374
2375
2376
2377
2378 public final void setIndentation( final String value )
2379 {
2380 this.indentation = value;
2381 }
2382
2383
2384
2385
2386
2387
2388
2389
2390 public final String getLineSeparator()
2391 {
2392 if ( this.lineSeparator == null )
2393 {
2394 this.lineSeparator = System.getProperty( "line.separator", "\n" );
2395
2396 if ( this.isLoggable( Level.CONFIG ) )
2397 {
2398 this.log( Level.CONFIG, getMessage( "defaultLineSeparator",
2399 StringEscapeUtils.escapeJava( this.lineSeparator ) ), null );
2400
2401 }
2402 }
2403
2404 return this.lineSeparator;
2405 }
2406
2407
2408
2409
2410
2411
2412
2413
2414 public final void setLineSeparator( final String value )
2415 {
2416 this.lineSeparator = value;
2417 }
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428 public final Locale getLocale()
2429 {
2430 if ( this.locale == null )
2431 {
2432 this.locale = Locale.ENGLISH;
2433
2434 if ( this.isLoggable( Level.CONFIG ) )
2435 {
2436 this.log( Level.CONFIG, getMessage( "defaultLocale", this.locale ), null );
2437 }
2438 }
2439
2440 return this.locale;
2441 }
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452 public final void setLocale( final Locale value )
2453 {
2454 this.locale = value;
2455 }
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479 public Template getVelocityTemplate( final String templateName ) throws IOException
2480 {
2481 if ( templateName == null )
2482 {
2483 throw new NullPointerException( "templateName" );
2484 }
2485
2486 String location = null;
2487 Template template = null;
2488 final String key = this.getLocale() + "|" + this.getTemplateProfile() + "|" + getDefaultTemplateProfile()
2489 + "|" + templateName;
2490
2491 Map<String, String> map = this.templateLocationsCache == null ? null : this.templateLocationsCache.get();
2492
2493 if ( map == null )
2494 {
2495 map = Collections.synchronizedMap( new HashMap<String, String>( 32 ) );
2496 this.templateLocationsCache = new SoftReference<Map<String, String>>( map );
2497 }
2498
2499 location = map.get( key );
2500
2501 if ( location == null && !map.containsKey( key ) )
2502 {
2503 if ( !StringUtils.EMPTY.equals( this.getLocale().getLanguage() ) )
2504 {
2505 location = TEMPLATE_PREFIX + this.getTemplateProfile() + "/" + this.getLocale().getLanguage() + "/"
2506 + templateName;
2507
2508 template = this.findVelocityTemplate( location );
2509 }
2510
2511 if ( template == null )
2512 {
2513 location = TEMPLATE_PREFIX + this.getTemplateProfile() + "/" + templateName;
2514 template = this.findVelocityTemplate( location );
2515 }
2516
2517 if ( template == null && !StringUtils.EMPTY.equals( this.getLocale().getLanguage() ) )
2518 {
2519 location = TEMPLATE_PREFIX + getDefaultTemplateProfile() + "/" + this.getLocale().getLanguage() + "/"
2520 + templateName;
2521
2522 template = this.findVelocityTemplate( location );
2523 }
2524
2525 if ( template == null )
2526 {
2527 location = TEMPLATE_PREFIX + getDefaultTemplateProfile() + "/" + templateName;
2528 template = this.findVelocityTemplate( location );
2529 }
2530
2531 map.put( key, location );
2532 }
2533 else if ( location != null )
2534 {
2535 template = this.findVelocityTemplate( location );
2536 }
2537
2538 if ( template == null )
2539 {
2540 throw new IOException( getMessage( "noSuchTemplate", templateName ) );
2541 }
2542
2543 if ( this.isLoggable( Level.FINER ) )
2544 {
2545 this.log( Level.FINER, getMessage( "templateInfo", templateName, location ), null );
2546 }
2547
2548 return template;
2549 }
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563 public void log( final Level level, final String message, final Throwable throwable )
2564 {
2565 if ( level == null )
2566 {
2567 throw new NullPointerException( "level" );
2568 }
2569
2570 if ( this.isLoggable( level ) )
2571 {
2572 for ( int i = this.getListeners().size() - 1; i >= 0; i-- )
2573 {
2574 this.getListeners().get( i ).onLog( level, message, throwable );
2575 }
2576 }
2577 }
2578
2579 private String getJavaPackageName( final String identifier )
2580 {
2581 if ( identifier == null )
2582 {
2583 throw new NullPointerException( "identifier" );
2584 }
2585
2586 final int idx = identifier.lastIndexOf( '.' );
2587 return idx != -1 ? identifier.substring( 0, idx ) : "";
2588 }
2589
2590 private Template findVelocityTemplate( final String location ) throws IOException
2591 {
2592 try
2593 {
2594 return this.getVelocityEngine().getTemplate( location, this.getTemplateEncoding() );
2595 }
2596 catch ( final ResourceNotFoundException e )
2597 {
2598 if ( this.isLoggable( Level.FINER ) )
2599 {
2600 this.log( Level.FINER, getMessage( "templateNotFound", location ), null );
2601 }
2602
2603 return null;
2604 }
2605 catch ( final ParseErrorException e )
2606 {
2607 String m = getMessage( e );
2608 m = m == null ? "" : " " + m;
2609
2610
2611 throw (IOException) new IOException( getMessage( "invalidTemplate", location, m ) ).initCause( e );
2612 }
2613 catch ( final VelocityException e )
2614 {
2615 String m = getMessage( e );
2616 m = m == null ? "" : " " + m;
2617
2618
2619 throw (IOException) new IOException( getMessage( "velocityException", location, m ) ).initCause( e );
2620 }
2621 }
2622
2623 private java.util.Properties getTemplateProfileProperties( final String profileName, final String language )
2624 {
2625 Map<String, java.util.Properties> map = this.templateProfilePropertiesCache == null
2626 ? null : this.templateProfilePropertiesCache.get();
2627
2628 if ( map == null )
2629 {
2630 map = new ConcurrentHashMap<String, java.util.Properties>();
2631 this.templateProfilePropertiesCache = new SoftReference<Map<String, java.util.Properties>>( map );
2632 }
2633
2634 final String key = profileName + "|" + language;
2635 java.util.Properties profileProperties = map.get( key );
2636
2637 if ( profileProperties == null )
2638 {
2639 InputStream in = null;
2640 URL url = null;
2641 profileProperties = new java.util.Properties();
2642 map.put( key, profileProperties );
2643
2644 final String resourceName = TEMPLATE_PREFIX + profileName + ( language == null ? "" : "/" + language )
2645 + "/context.properties";
2646
2647 try
2648 {
2649 url = this.getClass().getResource( "/" + resourceName );
2650
2651 if ( url != null )
2652 {
2653 in = url.openStream();
2654
2655 if ( this.isLoggable( Level.CONFIG ) )
2656 {
2657 this.log( Level.CONFIG, getMessage( "contextPropertiesFound", url.toExternalForm() ), null );
2658 }
2659
2660 profileProperties.load( in );
2661 }
2662 else if ( this.getTemplateLocation() != null )
2663 {
2664 if ( this.isLoggable( Level.CONFIG ) )
2665 {
2666 this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", resourceName ), null );
2667 }
2668
2669 url = new URL( this.getTemplateLocation(), resourceName );
2670 in = url.openStream();
2671
2672 if ( this.isLoggable( Level.CONFIG ) )
2673 {
2674 this.log( Level.CONFIG, getMessage( "contextPropertiesFound", url.toExternalForm() ), null );
2675 }
2676
2677 profileProperties.load( in );
2678 }
2679 else if ( this.isLoggable( Level.CONFIG ) )
2680 {
2681 this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", resourceName ), null );
2682 }
2683 }
2684 catch ( final FileNotFoundException e )
2685 {
2686 if ( this.isLoggable( Level.CONFIG ) )
2687 {
2688 this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", url.toExternalForm() ), null );
2689 }
2690 }
2691 catch ( final IOException e )
2692 {
2693 map.remove( key );
2694 this.log( Level.SEVERE, getMessage( e ), e );
2695 }
2696 finally
2697 {
2698 try
2699 {
2700 if ( in != null )
2701 {
2702 in.close();
2703 }
2704 }
2705 catch ( final IOException e )
2706 {
2707 this.log( Level.SEVERE, getMessage( e ), e );
2708 }
2709 }
2710 }
2711
2712 return profileProperties;
2713 }
2714
2715 private void mergeTemplateProfileProperties( final String profileName, final String language,
2716 final VelocityContext velocityContext )
2717 {
2718 final java.util.Properties templateProfileProperties =
2719 this.getTemplateProfileProperties( profileName, language );
2720
2721 for ( final Enumeration<?> e = templateProfileProperties.propertyNames(); e.hasMoreElements(); )
2722 {
2723 final String name = e.nextElement().toString();
2724 final String value = templateProfileProperties.getProperty( name );
2725 final String[] values = value.split( "\\|" );
2726
2727 if ( !velocityContext.containsKey( name ) )
2728 {
2729 try
2730 {
2731 if ( values.length > 1 )
2732 {
2733 final Class<?> valueClass = Class.forName( values[0] );
2734 velocityContext.put( name, valueClass.getConstructor( String.class ).newInstance( values[1] ) );
2735 }
2736 else if ( value.contains( "|" ) )
2737 {
2738 velocityContext.put( name, Class.forName( values[0] ).newInstance() );
2739 }
2740 else
2741 {
2742 velocityContext.put( name, value );
2743 }
2744 }
2745 catch ( final InstantiationException ex )
2746 {
2747 this.log( Level.SEVERE, getMessage( ex ), ex );
2748 }
2749 catch ( final IllegalAccessException ex )
2750 {
2751 this.log( Level.SEVERE, getMessage( ex ), ex );
2752 }
2753 catch ( final InvocationTargetException ex )
2754 {
2755 this.log( Level.SEVERE, getMessage( ex ), ex );
2756 }
2757 catch ( final NoSuchMethodException ex )
2758 {
2759 this.log( Level.SEVERE, getMessage( ex ), ex );
2760 }
2761 catch ( final ClassNotFoundException ex )
2762 {
2763 this.log( Level.SEVERE, getMessage( ex ), ex );
2764 }
2765 }
2766 }
2767 }
2768
2769 private Set<String> getJavaKeywords()
2770 {
2771 Reader in = null;
2772 Set<String> set = this.javaKeywordsCache == null ? null : this.javaKeywordsCache.get();
2773
2774 try
2775 {
2776 if ( set == null )
2777 {
2778 in = new InputStreamReader( this.getClass().getResourceAsStream(
2779 "/" + this.getClass().getPackage().getName().replace( ".", "/" ) + "/JavaKeywords.txt" ), "UTF-8" );
2780
2781 set = new CopyOnWriteArraySet<String>( IOUtils.readLines( in ) );
2782
2783 this.javaKeywordsCache = new SoftReference<Set<String>>( set );
2784 }
2785 }
2786 catch ( final IOException e )
2787 {
2788 throw new IllegalStateException( getMessage( e ), e );
2789 }
2790 finally
2791 {
2792 try
2793 {
2794 if ( in != null )
2795 {
2796 in.close();
2797 }
2798 }
2799 catch ( final IOException e )
2800 {
2801 throw new IllegalStateException( getMessage( e ), e );
2802 }
2803 }
2804
2805 return set;
2806 }
2807
2808 private static String getMessage( final String key, final Object... arguments )
2809 {
2810 return MessageFormat.format( ResourceBundle.getBundle(
2811 JomcTool.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
2812
2813 }
2814
2815 private static String getMessage( final Throwable t )
2816 {
2817 return t != null ? t.getMessage() != null ? t.getMessage() : getMessage( t.getCause() ) : null;
2818 }
2819
2820 }