-
Notifications
You must be signed in to change notification settings - Fork 9
/
built-in.app
3418 lines (3090 loc) · 95.1 KB
/
built-in.app
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
module .servletapp/src-webdsl-template/built-in
// overridable attributes for generator built-in templates and library input templates
attributes navigate{ class = "navigate" }
attributes downloadlink{ class = "downloadlink" }
attributes outputimage{ class = "outputimage" }
attributes submit{ class = "button" }
attributes submitlink{ }
attributes form{ }
attributes navigatebutton{ }
attributes captcha{ }
attributes image{ }
attributes inputInt{ class = "inputInt" }
attributes inputBool{ class = "inputBool" }
attributes inputString{ class = "inputString" }
attributes inputEmail{ class = "inputEmail" }
attributes inputSecret{ class = "inputSecret" }
attributes inputURL{ class = "inputURL" }
attributes inputText{ class = "inputTextarea inputText" }
attributes inputWikiText{ class = "inputTextarea inputWikiText" }
attributes inputFloat{ class = "inputFloat" }
attributes inputLong{ class = "inputLong" }
attributes inputDate{ class = "inputDate" }
attributes inputSetCheckbox{ class = "checkbox-set" }
attributes inputSetCheckboxElements{ class = "checkbox-set-element" }
attributes inputSelect{ class = "select" }
attributes inputSelectMultiple{ class = "select" }
attributes inputFile{ class = "inputFile" }
attributes inputMultiFile{ class = "inputFile" }
attributes inputSDF{ class = "inputSDF" }
attributes radio{ class = "radio" }
// page request statistics
native class utils.Statistics as RequestStatistics{
static logStatistics()
}
function logStatistics(){
RequestStatistics.logStatistics();
}
invoke logStatistics() every 5 minutes
// hibbernate transaction management
native class utils.IncludePaths as IncludePaths{
static jQueryJS(): String
static jQueryUIJS(): String
static jQueryUICSS(): String
static momentJS() : String
static timepickerJS(): String
static timepickerCSS(): String
}
native class utils.ValidationException as NativeValidationException{
getName(): String
getErrorMessage(): String
isRelevantObject( Object ): Bool
}
native class utils.HibernateTransactionHelper as HibernateTransactionHelper{
static commitAndStartNewTransaction(): [NativeValidationException]
static rollbackAndStartNewTransaction()
}
function commitAndStartNewTransaction(): [NativeValidationException]{
return HibernateTransactionHelper.commitAndStartNewTransaction();
}
function rollbackAndStartNewTransaction(){
HibernateTransactionHelper.rollbackAndStartNewTransaction();
}
// session management
invoke internalCleanupSessionManagerEntities() every 10 minutes
function internalUpdateSessionManagerTimeout() : Bool{
var n: DateTime := now().addMinutes( -30 ); // update lastUse after 30 minutes to avoid unnecessary db writes, also sets minimum timeout to 30 minutes
var man := getSessionManager();
if( man.lastUse == null
|| man.lastUse.before( n )
){
man.lastUse := now();
return true;
}
return false;
}
function internalCleanupSessionManagerEntities(){
var sessiontimeout := 6; //months
var n: DateTime := now().addMonths( -1 * sessiontimeout );
var ses := from SessionManager as sc where sc.lastUse is null or sc.lastUse < ~n limit 25; //use limit to avoid loading all obsolete entities in one transaction
for( s: SessionManager in ses ){
s.delete();
}
}
// search
//optimization of search index, twice a day
invoke optimizeSearchIndex() every 12 hours
//Update the spell check and autocompletion indices twice a day
invoke updateSuggestionIndex() every 12 hours
//renew facet index readers every 15 minutes
invoke renewFacetIndexReaders() every 15 minutes
function renewFacetIndexReaders(){
IndexManager.renewFacetIndexReaders();
}
function optimizeSearchIndex(){
IndexManager.optimizeIndex();
}
function updateSuggestionIndex(){
IndexManager.indexSuggestions();
}
native class webdsl.generated.search.IndexManager as IndexManager{
static indexSuggestions()
static indexSuggestions( [String] )
static optimizeIndex()
static renewFacetIndexReaders()
static clearAutoCompleteIndex( String )
static clearSpellCheckIndex( String )
static reindex( Entity )
static reindex( List<Entity> )
static removeFromIndex( Entity )
static reindex()
}
native class org.webdsl.search.SearchHelper as SearchHelper{
static firstIndexLink( Int, Int, Int ): Int
static lastIndexLink( Int, Int, Int ): Int
}
native class org.webdsl.search.DynamicSearchField as DynamicSearchField{
constructor( String, String )
}
native class org.webdsl.search.WebDSLFacet as Facet{
constructor()
static fromString( String ): Facet
asString(): String
isSelected(): Bool
getCount(): Int
getValue(): String
getFieldName(): String
getValueAsDate(): Date
getValueAsFloat(): Float
getValueAsInt(): Int
must(): Facet
mustNot(): Facet
should(): Facet
isMust(): Bool
isMustNot(): Bool
isShould(): Bool
}
function escapeQuery( q: String ): String{
return Searcher.escapeQuery( q );
}
native class org.webdsl.search.AbstractEntitySearcher as Searcher{
static escapeQuery( String ): String
static fromString( String ): Searcher
asString(): String
enableFaceting( String, Int ): Searcher
enableFaceting( String, String ): Searcher
getFacets( String ): [Facet]
addFacetSelection( Facet ): Searcher
addFacetSelection( [Facet] ): Searcher
getFacetSelection(): [Facet]
getFacetSelection( String ): [Facet]
removeFacetSelection( Facet ): Searcher
clearFacetSelection(): Searcher
clearFacetSelection( String ): Searcher
highlight( String, String ): String
highlight( String, String, String, String, Int, Int, String ): String
highlight( String, String, String, String ): String
highlightLargeText( String, String ): String
highlightLargeText( String, String, String, String, Int, Int, String ): String
highlightLargeText( String, String, String, String ): String
highlightHTML( String, String ): String
highlightHTML( String, String, String, String, Int, Int, String ): String
highlightHTML( String, String, String, String ): String
highlightLargeHTML( String, String ): String
highlightLargeHTML( String, String, String, String, Int, Int, String ): String
highlightLargeHTML( String, String, String, String ): String
getQuery(): String
luceneQuery(): String
searchTime(): String
searchTimeMillis(): Int
searchTimeSeconds(): Float
allowLuceneSyntax( Bool ): Searcher
addFieldFilter( String, Object ): Searcher
addFieldFilter( String, String ): Searcher
getFilteredFields(): [String]
getFieldFilterValue( String ): String
removeFieldFilter( String ): Searcher
clearFieldFilters(): Searcher
startMustClause(): Searcher
startMustNotClause(): Searcher
startShouldClause(): Searcher
results(): [Entity]
must(): Searcher
should(): Searcher
not(): Searcher
endClause(): Searcher
setNamespace( String ): Searcher
setNamespace( Object ): Searcher
getNamespace(): String
removeNamespace(): Searcher
boost( String, Float ): Searcher
strictMatching( Bool ): Searcher
field( String ): Searcher
fields( [String] ): Searcher
defaultFields(): Searcher
getFields(): [String]
setOffset( Int ): Searcher
getOffset(): Int
setLimit( Int ): Searcher
getLimit(): Int
scores(): [Float]
explanations(): [String]
count(): Int
moreLikeThis( String ): Searcher
sortDesc( String ): Searcher
sortAsc( String ): Searcher
clearSorting(): Searcher
reset(): Searcher
query( Object ): Searcher
query( String ): Searcher
phraseQuery( String, Int ): Searcher
phraseQuery( Object, Int ): Searcher
regexQuery( String ): Searcher
rangeQuery( Int, Int, Bool, Bool ): Searcher
rangeQuery( Float, Float, Bool, Bool ): Searcher
rangeQuery( Date, Date, Bool, Bool ): Searcher
rangeQuery( String, String, Bool, Bool ): Searcher
rangeQuery( Int, Int ): Searcher
rangeQuery( Float, Float ): Searcher
rangeQuery( Date, Date ): Searcher
rangeQuery( String, String ): Searcher
matchAllQuery(): Searcher
}
native class org.webdsl.search.SearchStatistics as SearchStatistics{
static clear(): Void
static getSearchQueryExecutionCount(): Long
static getSearchQueryTotalTime(): Long
static getSearchQueryExecutionMaxTime(): Long
static getSearchQueryExecutionAvgTime(): Long
static getSearchQueryExecutionMaxTimeQueryString(): String
static getObjectLoadingTotalTime(): Long
static getObjectLoadingExecutionMaxTime(): Long
static getObjectLoadingExecutionAvgTime(): Long
static getObjectsLoadedCount(): Long
static isStatisticsEnabled(): Bool
static setStatisticsEnabled( Bool ): Bool
static getSearchVersion(): String
static getIndexedClassNames(): [String]
static indexedEntitiesCount(): [String]
}
//The default analyzer, equal to the one used by default in hibernate search
default_builtin_analyzer analyzer hsearchstandardanalyzer{
tokenizer = StandardTokenizer
token filter = StandardFilter
token filter = LowerCaseFilter
token filter = StopFilter
}
//Template showing the info available through Hibernate Search statistics
template showSearchStats(){
var NStoMS: Long := 1000000L;
table{
row{ column{ <b> "Search statistics" </b> } }
row{ column{ "Statistics enabled?" } column { output( SearchStatistics.isStatisticsEnabled() ) if( !SearchStatistics.isStatisticsEnabled() ){ "(Enabled through searchstats=true in application.ini)" } } }
row{ column{ "Hibernate Search version" } column { output( SearchStatistics.getSearchVersion() ) } }
row{ column{ <b> "Query execution times" </b> } }
row{ column{ "Search query execution count" } column { output( SearchStatistics.getSearchQueryExecutionCount() ) } }
row{ column{ "Total search time" } column { output( SearchStatistics.getSearchQueryTotalTime() / NStoMS ) "ms (" output( SearchStatistics.getSearchQueryTotalTime() ) "ns)" } }
row{ column{ "Average search query exec time" } column { output( SearchStatistics.getSearchQueryExecutionAvgTime() / NStoMS ) "ms (" output( SearchStatistics.getSearchQueryExecutionAvgTime() ) "ns)" } }
row{ column{ "Slowest search query exec time" } column { output( SearchStatistics.getSearchQueryExecutionMaxTime() / NStoMS ) "ms (" output( SearchStatistics.getSearchQueryExecutionMaxTime() ) "ns)" } }
row{ column{ "Slowest search query" } column { output( SearchStatistics.getSearchQueryExecutionMaxTimeQueryString() ) } }
row{ column{ <b> "Object load times" </b> } }
row{ column{ "Objects loaded count" } column { output( SearchStatistics.getObjectsLoadedCount() ) } }
row{ column{ "Total object loading time" } column { output(SearchStatistics.getObjectLoadingTotalTime()/ NStoMS ) "ms (" output( SearchStatistics.getObjectLoadingTotalTime() ) "ns)" } }
row{ column{ "Average object loading time" } column { output(SearchStatistics.getObjectLoadingExecutionAvgTime() / NStoMS ) "ms (" output( SearchStatistics.getObjectLoadingExecutionAvgTime() ) "ns)" } }
row{ column{ "Slowest object loading time" } column { output(SearchStatistics.getObjectLoadingExecutionMaxTime() / NStoMS ) "ms (" output( SearchStatistics.getObjectLoadingExecutionMaxTime() ) "ns)" } }
}
table{
row{ column{ <b> "Indexed entities (entity - nOfEntities)" </b> } }
row{ column{ output( SearchStatistics.indexedEntitiesCount() ) } }
}
}
//Tries to highlight the elements inside, not touching the html tags inside (highlighter invoked to ignore html tags)
//If nothing is highlighted, it just renders elements
//Hits are surrounded by tags <span class = "highlightcontent">HIT</span>
template highlight( s: Searcher, fld: String ){
var rendered := rendertemplate( elements );
var renderedHL := if( s != null ) s.highlightLargeHTML( fld, rendered, "<span class=\"highlightcontent\">", "</span>", 1, 10000000, "" )
else "";
if( renderedHL != null && renderedHL.length() > 0 ){
rawoutput( renderedHL )[ all attributes ]
}
else{
rawoutput( rendered )[ all attributes ] //don't render twice
}
}
//Outputs a summary surrogate for the given text 'txt' based on constraints in searcher 's' for search field 'fld'
//A summary suggorate will consist of at most 3 fragments of max 80 characters seperated by '... '
//Hits are surrounded by tags <span class = "highlightcontent">HIT</span>
template highlightedSummary( s: Searcher, fld: String, txt: String ){
var decorated := highlightHTML ~fld: txt from s with tags ("HLOPENTAG", "HLCLOSETAG");
var prerendered := rendertemplate( output("... " + decorated + " ...") )
var tagsfixed := prerendered.replace( "HLOPENTAG", "<span class=\"highlightcontent\">" )
.replace( "HLCLOSETAG", "</span>" );
rawoutput( tagsfixed )[ all attributes ]
}
//Outputs a summary surrogate for the given text 'txt' based on constraints in searcher 's' for search field 'fld'
//A summary suggorate will consist of at most 3 fragments of max 80 characters seperated by '... '
//Hits are surrounded by tags <span class = "highlightcontent">HIT</span>
template highlightedSummary( s: Searcher, fld: String, txt: WikiText ){
var decorated := highlightHTML ~fld: txt from s with tags ("HLOPENTAG", "HLCLOSETAG");
var prerendered := rendertemplate( output( ( ("... " + decorated + " ...") as WikiText) ) )
//also remove links from summaries
var tagsfixed := prerendered.replace( "<a ", "<span " )
.replace( "</a ", "</span " )
.replace( "HLOPENTAG", "<span class=\"highlightcontent\">" )
.replace( "HLCLOSETAG", "</span>" )
rawoutput( tagsfixed )[ all attributes ]
}
// section methods for built-in types
type String{ //includes other String-based types such as Secret, Patch, Email, URL, etc.
length(): Int
toLowerCase(): String
toUpperCase(): String
replace( String, String ): String
startsWith( String ): Bool
startsWith( String, Int ): Bool
endsWith( String ): Bool
trim(): String
utils.StringType.parseUUID as parseUUID(): UUID
org.webdsl.tools.Utils.containsDigit as containsDigit(): Bool
org.webdsl.tools.Utils.containsLowerCase as containsLowerCase(): Bool
org.webdsl.tools.Utils.containsUpperCase as containsUpperCase(): Bool
org.webdsl.tools.Utils.isCleanUrl as isCleanUrl(): Bool
org.apache.commons.lang3.StringUtils.contains as contains( String ): Bool // this 'contains' function handles null, null as either arg will produce false
utils.StringType.parseInt as parseInt(): Int
utils.StringType.split as split(): [String]
utils.StringType.splitWithSeparator as split( String ): [String] //TODO Regex as argument
utils.StringType.parseLong as parseLong(): Long
utils.StringType.parseFloat as parseFloat(): Float
utils.DateType.parseDate as parseDate( String ): Date
utils.DateType.parseDate as parseDateTime( String ): DateTime
utils.DateType.parseDate as parseTime( String ): Time
org.apache.commons.lang3.StringEscapeUtils.escapeEcmaScript as escapeJavaScript(): String
substring( Int ): String
substring( Int, Int ): String
utils.StringType.similarity as similarity(String) : Float
}
type Secret{
org.webdsl.tools.Utils.secretDigest as digest(): Secret
org.webdsl.tools.Utils.secretCheck as check(Secret): Bool
}
type Patch{
name.fraser.neil.plaintext.patch_factory.patchApply as applyPatch( String ): String
name.fraser.neil.plaintext.patch_factory.unpatchApply as revertPatch( String ): String
name.fraser.neil.plaintext.patch_factory.diffHTML as diffHTML( Bool ): String
}
type String{
name.fraser.neil.plaintext.patch_factory.patchMake as makePatch( String ): Patch
name.fraser.neil.plaintext.patch_factory.diff as diff( String ): [String]
}
type Long{
intValue(): Int
}
type DateTime{ // includes Date and Time types
utils.DateType.format as format( String ): String
before( DateTime ): Bool
after( DateTime ): Bool
getTime(): Long
setTime( Long )
utils.DateType.addYears as addYears( Int ): DateTime
utils.DateType.addMonths as addMonths( Int ): DateTime
utils.DateType.addDays as addDays( Int ): DateTime
utils.DateType.addHours as addHours( Int ): DateTime
utils.DateType.addMinutes as addMinutes( Int ): DateTime
utils.DateType.addSeconds as addSeconds( Int ): DateTime
utils.DateType.getYear as getYear(): Int
utils.DateType.getMonth as getMonth(): Int
utils.DateType.getDay as getDay(): Int
utils.DateType.getDayOfYear as getDayOfYear(): Int
utils.DateType.getHour as getHour(): Int
utils.DateType.getMinute as getMinute(): Int
utils.DateType.getSecond as getSecond(): Int
}
function age( d: Date ): Int{
var today: Date := today();
var age := today.getYear() - d.getYear();
if( today.getDayOfYear() < d.getDayOfYear() ){
age := age - 1;
}
return age;
}
native class utils.DateType as DateType{ //@TODO static functions not yet supported in type import of DateTime above
static getDefaultDateFormat(): String
static getDefaultTimeFormat(): String
static getDefaultDateTimeFormat(): String
}
type WikiText{
org.webdsl.tools.WikiFormatter.wikiFormat as format(): String
org.webdsl.tools.WikiFormatter.wikiFormatNoTagFiltering as formatNoTagFiltering(): String
}
type Email{
utils.EmailType.isValid as isValid(): Bool
}
type URL{
utils.URLType.isValid as isValid(): Bool
utils.URLType.download as download(): File
}
type File{
getContentAsString(): String
getContentType(): String
setContentType( String )
getFileName(): String
delete() : File
}
type String{
utils.File.createFromString as asFile( String ): File
}
type Image{
getContentAsString(): String
getContentType(): String
setContentType( String )
getFileName(): String
delete() : File
}
// access to servlet context
native class AbstractDispatchServletHelper as DispatchServlet{
getIncomingSuccessMessages(): [String]
getOutgoingSuccessMessages(): [String]
clearSuccessMessages()
getRequest(): HttpServletRequest
static get(): DispatchServlet
getBaseUrl(): String
getUrlComponents(): [String]
}
function getDispatchServlet(): DispatchServlet{
return DispatchServlet.get();
}
native class javax.servlet.http.HttpServletRequest as HttpServletRequest{
getRemoteAddr(): String
}
function remoteAddress(): String{
var address := getDispatchServlet().getRequest().getRemoteAddr();
if( address == "127.0.0.1" ){ // e.g. Nginx proxying to http port of Tomcat
address := getPage().getXForwardedFor(); // only look at header if getRemoteAddr is useless
}
return address;
}
function baseUrl(): String{
return getDispatchServlet().getBaseUrl();
}
function urlComponents(): [String]{
return getDispatchServlet().getUrlComponents();
}
// access to page context
native class AbstractPageServlet as PageServlet{
inSubmittedForm(): Bool
formRequiresMultipartEnc: Bool
getFileUploads( String ): [File]
getLabelString(): String
inLabelContext(): Bool
addValidationException( String, String )
getValidationErrorsByName( String ): [String]
static getRequestedPage(): PageServlet
enterLabelContext( String )
leaveLabelContext()
setTemplateContext( TemplateContext )
getTemplateContext(): TemplateContext
setMimetype( String )
isRedirected(): Bool
getRedirectUrl(): String
setRedirectUrl( String )
enableDownloadInline()
addReRenderPlaceholders( String )
addBodyAttribute( String, String )
submitWrapOpenHelper( String )
submitWrapCloseHelper()
actionHasAjaxPageUpdates: Bool
getXForwardedProto(): String
getXForwardedFor(): String
reloadSessionManagerFromExistingSessionId( UUID )
}
function getPage(): PageServlet{
return PageServlet.getRequestedPage();
}
function replace( ph: String ){
getPage().addReRenderPlaceholders( ph );
getPage().actionHasAjaxPageUpdates := true;
}
native class utils.TemplateContext as TemplateContext{
clone(): TemplateContext
getTemplateContextString(): String
}
function mimetype( s: String ){
getPage().setMimetype( s );
}
template mimetype( s: String ){
init{
getPage().setMimetype( s );
}
}
function downloadInline(){
getPage().enableDownloadInline();
}
template downloadInline(){
init{
downloadInline();
}
}
function addBodyAttribute( key: String, value: String ){
getPage().addBodyAttribute( key, value );
}
template addBodyAttribute( key: String, value: String ){
init{
addBodyAttribute( key, value );
}
}
//access to template context
native class TemplateServlet as TemplateServlet{
getUniqueId(): String
getUniqueIdNoCache(): String
static getCurrentTemplate(): TemplateServlet
}
function getTemplate(): TemplateServlet{
return TemplateServlet.getCurrentTemplate();
}
// utitity for templates that handle validation
function handleValidationErrors( errors: [String] ): [String]{
var result: [String] := null;
if( errors != null && errors.length > 0 ){
if( getPage().inLabelContext() ){
for( s: String in errors ){
getPage().addValidationException( getPage().getLabelString(), s );
}
}
else{
result := errors;
}
cancel();
}
return result;
}
// section XML
native class org.w3c.dom.Document as XMLDocument : XMLNode{
org.webdsl.xml.XMLUtil.getElementsByTagName as getElementsByTagName(String) : List<XMLNode>
org.webdsl.xml.XMLUtil.getElementsByXPath as getElementsByXPath(String) : List<XMLNode>
org.webdsl.xml.XMLUtil.getNodesByXPath as getNodesByXPath(String) : List<XMLNode>
org.webdsl.xml.XMLUtil.asString as asString() : String
}
native class org.w3c.dom.Node as XMLNode{
org.webdsl.xml.XMLUtil.getElementsByTagName as getElementsByTagName(String) : List<XMLNode>
org.webdsl.xml.XMLUtil.getElementsByXPath as getElementsByXPath(String) : List<XMLNode>
javaxt.xml.DOM.getNodeValue as getVal() : String
org.webdsl.xml.XMLUtil.getText as getVal(String) : String
javaxt.xml.DOM.getAttributeValue as getAttrVal(String) : String
org.webdsl.xml.XMLUtil.getChildren as getChildren() : List<XMLNode>
org.webdsl.xml.XMLUtil.getAttributes as getAttributes() : List<XMLNode>
getNodeName() : String
org.webdsl.xml.XMLUtil.setValue as setValue(String)
}
type String{
javaxt.xml.DOM.createDocument as asXMLDocument() : XMLDocument
}
// section JSON for services
native class org.json.JSONObject as JSONObject{
constructor()
constructor( String )
NULL: Object
get( String ): Object
getBoolean( String ): Bool
getDouble( String ): Double
getInt( String ): Int
getLong( String ): Long
getJSONArray( String ): JSONArray
getJSONObject( String ): JSONObject
getString( String ): String
has( String ): Bool
names(): JSONArray
put( String, Object )
toString(): String
toString( Int ): String
}
native class org.json.JSONArray as JSONArray{
constructor()
constructor( String )
get( Int ): Object
getBoolean( Int ): Bool
getDouble( Int ): Double
getInt( Int ): Int
getJSONArray( Int ): JSONArray
getJSONObject( Int ): JSONObject
getString( Int ): String
length(): Int
join( String ): String
put( Object )
remove( Int )
toString(): String
toString( Int ): String
}
native class java.lang.Double as Double{
constructor( Double )
constructor( String )
floatValue(): Float
}
// section WebDriver for testing
function sleep( i: Int ){
UtilsTestClass.sleep(i);
}
function createTempFile( s: String ): String{
return UtilsTestClass.createTempFile(s);
}
function getFirefoxDriver(): FirefoxDriver{
return UtilsTestClass.getFirefoxDriver();
}
function getHtmlUnitDriver(): HtmlUnitDriver{
return UtilsTestClass.getHtmlUnitDriver();
}
function getDriver(): WebDriver{
return getFirefoxDriver();
}
native class utils.Test as UtilsTestClass{
static sleep( Int )
static getHtmlUnitDriver(): HtmlUnitDriver
static getFirefoxDriver(): FirefoxDriver
static closeDrivers()
static createTempFile( String ): String
}
native class org.openqa.selenium.WebDriver as WebDriver{
get( String )
getTitle(): String
getPageSource(): String
findElement( SelectBy ): WebElement
findElements( SelectBy ): [WebElement]
close()
utils.Test.runJavaScript as runJavaScript( String ): String
utils.Test.getAlert as getAlert(): WebAlert
utils.Test.getSubmit as getSubmit(): WebElement
utils.Test.getSubmits as getSubmits(): [WebElement]
}
native class org.openqa.selenium.Alert as WebAlert{
getText(): String
dismiss()
accept()
}
native class org.openqa.selenium.By as SelectBy{
static className( String ): SelectBy
static id( String ): SelectBy
static linkText( String ): SelectBy
static name( String ): SelectBy
static partialLinkText( String ): SelectBy
static tagName( String ): SelectBy
static cssSelector( String ): SelectBy
static xpath( String ): SelectBy
}
native class org.openqa.selenium.WebElement as WebElement{
getText(): String
utils.Test.getValue as getValue(): String //WebElement.getValue() is deprecated
getElementName(): String
getAttribute( String ): String
isEnabled(): Bool
sendKeys( String )
submit()
clear()
getAttribute( String ): String
isEnabled(): Bool
isSelected(): Bool
findElements( SelectBy ): [WebElement]
//void sendKeys(java.lang.CharSequence... keysToSend)
utils.Test.click as toggle()
utils.Test.click as setSelected()
utils.Test.clickAndWait as click()
}
native class org.openqa.selenium.htmlunit.HtmlUnitDriver as HtmlUnitDriver: WebDriver{
constructor()
}
native class org.openqa.selenium.firefox.FirefoxDriver as FirefoxDriver: WebDriver{
constructor()
utils.Test.takeScreenshot as takeScreenshot()
}
native class org.openqa.selenium.support.ui.Select as Select{
deselectAll() // Clear all selected entries.
deselectByIndex( Int ) // Deselect the option at the given index.
deselectByValue( String ) // Deselect all options that have a value matching the argument.
deselectByVisibleText( String ) // Deselect all options that display text matching the argument.
escapeQuotes( String ): String
getAllSelectedOptions(): [WebElement]
getFirstSelectedOption(): WebElement
getOptions(): [WebElement]
isMultiple(): Bool
selectByIndex( Int ) // Select the option at the given index.
selectByValue( String ) // Select all options that have a value matching the argument.
selectByVisibleText( String ) // Select all options that display text matching the argument.
constructor( WebElement )
}
//email
entity QueuedEmail{
body: String (length=1000000) //Note: default length for string is currently 255
to: String (length=1000000)
cc: String (length=1000000)
bcc: String (length=1000000)
replyTo: String (length=1000000)
from: String (length=1000000)
subject: String (length=1000000)
unsubscribeAddress: String (length=1000000)
// scheduled: DateTime (default=now())
lastTry: DateTime
}
invoke internalHandleEmailQueue() every 15 seconds
function internalHandleEmailQueue(){
var n: DateTime := now().addHours( -3 ); // retry after 3 hours to avoid spamming too much
var dontRetryMoment: DateTime := now().addDays( -3 ); //dont retry emails older than 3 days
var queuedEmails := from QueuedEmail as q where (q.lastTry is null or q.lastTry < ~n) and q.created > ~dontRetryMoment order by q.created asc limit 5;
for( queuedEmail: QueuedEmail in queuedEmails ){
if( sendemail( sendQueuedEmail( queuedEmail ) ) ){
queuedEmail.delete();
}
else{
queuedEmail.lastTry := now();
}
//normally you would use email(sendQueuedEmail(queuedEmail)) to send email, however,
//that is desugared to renderemail(queuedEmail).save() to make it asynchronous.
//In this function the email is actually send, using the synchronous sendemail function.
}
}
native class utils.ThreadLocalEmailContext as ThreadLocalEmailContext{
static inEmailContext(): Bool
}
function inEmailContext(): Bool {
return ThreadLocalEmailContext.inEmailContext();
}
define email sendQueuedEmail( q: QueuedEmail ){
to( q.to )
from( q.from )
subject( q.subject )
cc( q.cc )
bcc( q.bcc )
replyTo( q.replyTo )
unsubscribeAddress( q.unsubscribeAddress )
//don't escape the html from internal email rendering
rawoutput( q.body )
}
// logging
entity RequestLogEntry{
name: String
requestedURL: Text
start: DateTime
end: DateTime
clientIP: String
clientPort: Int
method: String
referer: Text
userAgent: Text
}
//built-in templates
// convenient for desugaring in the compiler that replaces template elements with a single templatecall, see RenderTemplateFunctionCall desugaring
template internalElementsWrapper(){ elements }
// e.g. head{ <meta charset="utf-8"/> }
template head(){ includeHead( rendertemplate( elements ) ) }
htmlwrapper{
h1 h1
h2 h2
h3 h3
h4 h4
h5 h5
h6 h6
div div
span span
table table
row tr
column td
par p
pre pre
spacer hr
list ul[ class = "block" ]
listitem li[ class = "block" ]
block div[ class = "block" ]
container span[ class = "container" ]
groupitem tr
strong strong
emph em
code code
}
template br(){ <br all attributes> }
template break(){ <br all attributes> }
template block( s: String ){
<div class = "block" class = s all attributes>
elements
</div>
}
template fieldset( s: String ){
<fieldset all attributes>
<legend>
output( s )
</legend>
elements
</fieldset>
}
template group( s: String ){
<fieldset all attributes>
<legend>
output( s )
</legend>
<table>
elements
</table>
</fieldset>
}
template group(){
<fieldset class = "fieldset_no_legend_" all attributes>
<table>
elements
</table>
</fieldset>
}
/*
menubar{
menu
{
menuheader{ ... }
menuitems{
menuitem{ ... }
menuitem{ ... }
}
}
}
*/
template menubar(){
var elementid := "menu" + id
includeCSS( "dropdownmenu.css" )
<div class = "menuwrapper"
id = elementid
all attributes>
<ul id = "p7menubar"
class = "menubar">
elements
</ul>
</div>
}
template menuspacer(){
<li all attributes>
elements
</li>
}
template menu(){
<li class = "menu" all attributes>
elements
</li>
}
template menuheader(){
<span class = "menuheader" all attributes>
elements
</span>
}
template menuitems(){
<ul class = "menuitems">
elements
</ul>
}
template menuitem(){
<li class = "menuitem" all attributes>
elements
</li>
}
//reflection of entities
native class org.webdsl.lang.ReflectionEntity as ReflectionEntity{
getName(): String
getProperties(): [ReflectionProperty]
getPropertyByName( String ): ReflectionProperty
hasViewPage(): Bool
static byName( String ): ReflectionEntity
static all(): [ReflectionEntity]
}
native class org.webdsl.lang.ReflectionProperty as ReflectionProperty{
getName(): String
hasNotNullAnnotation(): Bool
getFormatAnnotation(): String
}
//validation wrapper for submit and submitlink
template wrapsubmit( tname: String ) requires s( String ){
render{ getPage().submitWrapOpenHelper( tname ); }
if( getValidationErrorsByName( tname ).length > 0 ){
errorTemplateAction( getValidationErrorsByName( tname ) ){
s( tname )
}
}
else{
s( tname )
}
render{ getPage().submitWrapCloseHelper(); }
}
//reused when elements are empty