1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.demo.uif.components;
17
18 import org.apache.commons.io.FileUtils;
19 import org.apache.commons.io.LineIterator;
20 import org.kuali.rice.core.api.util.AbstractKeyValue;
21 import org.kuali.rice.core.api.util.ConcreteKeyValue;
22 import org.kuali.rice.core.api.util.KeyValue;
23 import org.kuali.rice.krad.datadictionary.parse.BeanTag;
24 import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
25 import org.kuali.rice.krad.datadictionary.parse.BeanTags;
26 import org.kuali.rice.krad.messages.MessageService;
27 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
28 import org.kuali.rice.krad.uif.component.Component;
29 import org.kuali.rice.krad.uif.container.Group;
30 import org.kuali.rice.krad.uif.container.TabGroup;
31 import org.kuali.rice.krad.uif.control.MultiValueControl;
32 import org.kuali.rice.krad.uif.element.Header;
33 import org.kuali.rice.krad.uif.element.Message;
34 import org.kuali.rice.krad.uif.field.InputField;
35 import org.kuali.rice.krad.uif.util.ComponentFactory;
36 import org.kuali.rice.krad.uif.view.FormView;
37 import org.kuali.rice.krad.uif.view.View;
38 import org.springframework.util.StringUtils;
39
40 import javax.swing.text.StyleContext;
41 import java.io.File;
42 import java.lang.reflect.Method;
43 import java.net.URL;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.Comparator;
48 import java.util.HashMap;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.regex.Matcher;
52 import java.util.regex.Pattern;
53
54
55
56
57
58
59 public class ComponentLibraryView extends FormView {
60 private static final long serialVersionUID = 3981186175467661843L;
61
62 private String rootJavadocAddress;
63 private String rootDocBookAddress;
64 private String docBookAnchor;
65 private String componentName;
66 private String javaFullClassPath;
67 private String xmlFilePath;
68 private String description;
69 private String usage;
70 private String largeExampleFieldId;
71
72 public static enum ExampleSize {
73 SMALL, LARGE, XLARGE, WINDOW;
74 }
75
76 private ExampleSize exampleSize;
77
78 private Group detailsGroup;
79
80 private ComponentExhibit exhibit;
81 private List<Group> demoGroups;
82
83
84
85
86
87
88
89 @Override
90 public void performInitialization(View view, Object model) {
91 super.performInitialization(view, model);
92
93 MessageService messageService = KRADServiceLocatorWeb.getMessageService();
94
95
96 this.getPage().setHeaderText(this.getComponentName());
97
98 TabGroup tabGroup = ComponentFactory.getTabGroup();
99 List<Component> tabItems = new ArrayList<Component>();
100
101
102 Group descriptionGroup = ComponentFactory.getVerticalBoxGroup();
103
104
105 Header descriptionHeader = (Header) ComponentFactory.getNewComponentInstance("Uif-SubSectionHeader");
106 descriptionHeader.setHeaderLevel("H3");
107 descriptionHeader.setHeaderText(messageService.getMessageText("KR-SAP", null, "componentLibrary.description"));
108 descriptionHeader.setRender(false);
109 descriptionGroup.setHeader(descriptionHeader);
110
111
112 List<Component> descriptionItems = new ArrayList<Component>();
113 Message descriptionMessage = ComponentFactory.getMessage();
114 descriptionMessage.setMessageText(description);
115 descriptionItems.add(descriptionMessage);
116 descriptionGroup.setItems(descriptionItems);
117
118 tabItems.add(descriptionGroup);
119
120
121 Group usageGroup = ComponentFactory.getVerticalBoxGroup();
122
123
124 Header usageHeader = (Header) ComponentFactory.getNewComponentInstance("Uif-SubSectionHeader");
125 usageHeader.setHeaderLevel("H3");
126 usageHeader.setHeaderText(messageService.getMessageText("KR-SAP", null, "componentLibrary.usage"));
127 usageHeader.setRender(false);
128 usageGroup.setHeader(usageHeader);
129
130
131 List<Component> usageItems = new ArrayList<Component>();
132 Message usageMessage = ComponentFactory.getMessage();
133 usageMessage.setMessageText(usage);
134 usageItems.add(usageMessage);
135 usageGroup.setItems(usageItems);
136
137 tabItems.add(usageGroup);
138
139
140 if (javaFullClassPath != null) {
141 processDocumentationTab(tabItems);
142 }
143
144
145 tabGroup.setItems(tabItems);
146
147 tabGroup.addStyleClass("demo-componentDetailsTabs");
148
149
150 List<Component> detailsItems = new ArrayList<Component>();
151 detailsItems.addAll(detailsGroup.getItems());
152 detailsItems.add(tabGroup);
153 detailsGroup.setItems(detailsItems);
154 view.assignComponentIds(detailsGroup);
155
156
157 List<String> sourceCode = new ArrayList<String>();
158
159
160 processXmlSource(sourceCode);
161
162
163 exhibit.setDemoSourceCode(sourceCode);
164 exhibit.setDemoGroups(this.getDemoGroups());
165
166 if (this.getExampleSize() != null &&
167 (this.getExampleSize().equals(ExampleSize.LARGE) || this.getExampleSize().equals(ExampleSize.XLARGE))) {
168 exhibit.getTabGroup().addStyleClass("demo-noTabs");
169 Group headerRightGroup = view.getPage().getHeader().getRightGroup();
170 for (Component item : headerRightGroup.getItems()) {
171 if (item instanceof InputField && ((InputField) item).getControl() instanceof MultiValueControl && item
172 .getId().equals(this.getLargeExampleFieldId())) {
173
174 List<KeyValue> values = new ArrayList<KeyValue>();
175 int i = 0;
176 for (Group demoGroup : demoGroups) {
177 values.add(new ConcreteKeyValue(String.valueOf(i), demoGroup.getHeader().getHeaderText()));
178 i++;
179 }
180
181
182 ((MultiValueControl) ((InputField) item).getControl()).setOptions(values);
183 item.setRender(true);
184 }
185 }
186 }
187
188 if(this.getExampleSize() != null && this.getExampleSize().equals(ExampleSize.XLARGE)){
189 this.addStyleClass("demo-xLargeLibraryView");
190 }
191
192
193 List<Component> pageItems = new ArrayList<Component>();
194 pageItems.addAll(this.getPage().getItems());
195 pageItems.add(exhibit);
196 pageItems.add(detailsGroup);
197 this.getPage().setItems(pageItems);
198 }
199
200
201
202
203
204
205
206 private void processDocumentationTab(List<Component> tabItems) {
207 MessageService messageService = KRADServiceLocatorWeb.getMessageService();
208
209 try {
210 Class<?> componentClass = Class.forName(javaFullClassPath);
211 Method methodsArray[] = componentClass.getMethods();
212
213
214 String classMessage = messageService.getMessageText("KR-SAP", null, javaFullClassPath);
215
216 if (classMessage == null) {
217 classMessage = "NO DOCUMENTATION AVAILABLE/FOUND... we are working on it!";
218 }
219
220
221 classMessage = classMessage.replaceAll("\\{[@#]link (.*?)\\}", "<i>$1</i>");
222 classMessage = classMessage.replaceAll("\\{[@#]code (.*?)\\}", "<i>$1</i>");
223
224
225 String schemaTable =
226 "<table class='demo-schemaIdDocTable'><tr><th>Schema Name</th>" + "<th>Uif Bean Id</th></tr>";
227 if (componentClass.isAnnotationPresent(BeanTag.class)) {
228 BeanTag beanTag = componentClass.getAnnotation(BeanTag.class);
229 schemaTable = schemaTable +
230 "<tr><td>" + beanTag.name() + "</td><td>" + beanTag.parent() + "</td></tr>";
231 schemaTable = schemaTable + "</table>";
232 } else if (componentClass.isAnnotationPresent(BeanTags.class)) {
233 BeanTags beanTags = componentClass.getAnnotation(BeanTags.class);
234 BeanTag[] beanTagArray = beanTags.value();
235 for (BeanTag beanTag : beanTagArray) {
236 schemaTable = schemaTable +
237 "<tr><td>" + beanTag.name() + "</td><td>" + beanTag.parent() + "</td></tr>";
238 }
239 schemaTable = schemaTable + "</table>";
240 } else {
241 schemaTable = "";
242 }
243
244 String javadocTitle = messageService.getMessageText("KR-SAP", null, "componentLibrary.javaDoc");
245 String kradGuideTitle = messageService.getMessageText("KR-SAP", null, "componentLibrary.kradGuide");
246 String devDocumentationTitle = messageService.getMessageText("KR-SAP", null,
247 "componentLibrary.devDocumentation");
248 String beanDefsTitle = messageService.getMessageText("KR-SAP", null, "componentLibrary.beanDefs");
249
250
251 String docLinkDiv = "<div class='demo-docLinks'> "
252 + "<label>Additional Resources:</label><a class='demo-documentationLink'"
253 + " href='"
254 + getRootJavadocAddress()
255 + javaFullClassPath.replace('.', '/')
256 + ".html' target='_blank'>"
257 + javadocTitle
258 + "</a>"
259 + "<a class='demo-documentationLink'"
260 + " href='"
261 + getRootDocBookAddress()
262 + getDocBookAnchor()
263 + "' target='_blank'>"
264 + kradGuideTitle
265 + "</a>"
266 + "</div>";
267
268
269 String documentationMessageContent =
270 "<H3>" + this.getComponentName() + " " + devDocumentationTitle + "</H3>" +
271 docLinkDiv + classMessage + "<H3>" + beanDefsTitle + "</H3>" + schemaTable;
272
273 List<String> propertyDescriptions = new ArrayList<String>();
274 Map<String, List<String>> inheritedProperties = new HashMap<String, List<String>>();
275
276 List<Method> methods = Arrays.asList(methodsArray);
277
278
279 Collections.sort(methods, new Comparator<Method>() {
280 @Override
281 public int compare(Method method1, Method method2) {
282 String name1 = getPropName(method1);
283 String name2 = getPropName(method2);
284 return name1.compareTo(
285 name2);
286 }
287 });
288
289
290 for (Method method : methods) {
291 BeanTagAttribute attribute = method.getAnnotation(BeanTagAttribute.class);
292 if (attribute != null) {
293
294 String name = getPropName(method);
295 String methodClass = method.getDeclaringClass().getName();
296 String returnType = method.getReturnType().getName();
297 returnType = returnType.replaceAll("<.*?>", "");
298 String returnTypeShort = returnType.substring(returnType.lastIndexOf(".") + 1);
299
300
301 String key = methodClass + "|" + name + "|" + returnTypeShort;
302 String propertyMessage = messageService.getMessageText("KR-SAP", null, key);
303
304 if (propertyMessage == null) {
305 propertyMessage = "NO DOCUMENTATION AVAILABLE... we are working on it!";
306 }
307
308
309 propertyMessage = propertyMessage.replaceAll("\\{[@#]link (.*?)\\}", "<i>$1</i>");
310 propertyMessage = propertyMessage.replaceAll("\\{[@#]code (.*?)\\}", "<i>$1</i>");
311
312
313 if (returnType.startsWith("org.kuali")) {
314 returnTypeShort = "<a href='"
315 + getRootJavadocAddress()
316 + returnType.replace('.', '/')
317 + ".html' target='_blank'>"
318 + returnTypeShort
319 + "</a>";
320 }
321
322
323 propertyMessage = "<div class='demo-propertyItem'>"
324 + "<h4 class='demo-propertyName'>"
325 + name
326 + "</h4>"
327 + "<div class='demo-propertyType'>"
328 + returnTypeShort
329 + "</div>"
330 + "<div class='demo-propertyDesc'>"
331 + propertyMessage
332 + "</div></div>";
333
334 if (!methodClass.equals(javaFullClassPath)) {
335
336 List<String> classProperties = inheritedProperties.get(methodClass);
337 if (classProperties == null) {
338 classProperties = new ArrayList<String>();
339 }
340 classProperties.add(propertyMessage);
341 inheritedProperties.put(methodClass, classProperties);
342 } else {
343 propertyDescriptions.add(propertyMessage);
344 }
345 }
346 }
347
348 documentationMessageContent =
349 documentationMessageContent + "<H3>Properties</H3><div class='demo-propertiesContent'>";
350 for (String desc : propertyDescriptions) {
351 documentationMessageContent = documentationMessageContent + desc;
352 }
353 documentationMessageContent = documentationMessageContent + "</div>";
354
355 Group documentationGroup = ComponentFactory.getVerticalBoxGroup();
356
357
358 Header documentationHeader = (Header) ComponentFactory.getNewComponentInstance("Uif-SubSectionHeader");
359 documentationHeader.setHeaderLevel("H3");
360 documentationHeader.setHeaderText(messageService.getMessageText("KR-SAP", null,
361 "componentLibrary.documentation"));
362 documentationHeader.setRender(false);
363 documentationGroup.setHeader(documentationHeader);
364
365 List<Component> propertiesItems = new ArrayList<Component>();
366 Message propertiesMessage = ComponentFactory.getMessage();
367 propertiesMessage.setParseComponents(false);
368 propertiesMessage.setMessageText(documentationMessageContent);
369 propertiesItems.add(propertiesMessage);
370
371
372 if (!inheritedProperties.isEmpty()) {
373
374
375 for (String className : inheritedProperties.keySet()) {
376 String messageContent = "";
377 List<String> inheritedPropertyDescriptions = inheritedProperties.get(className);
378
379 for (String desc : inheritedPropertyDescriptions) {
380 messageContent = messageContent + desc;
381 }
382
383 Group iPropertiesGroup = ComponentFactory.getVerticalBoxGroup();
384
385
386 Header iPropHeader = (Header) ComponentFactory.getNewComponentInstance("Uif-SubSectionHeader");
387 iPropHeader.setHeaderLevel("H3");
388 iPropHeader.setHeaderText(messageService.getMessageText("KR-SAP", null,
389 "componentLibrary.inheritedFrom") + " " + className);
390
391 iPropertiesGroup.setHeader(iPropHeader);
392 iPropertiesGroup.getDisclosure().setRender(true);
393 iPropertiesGroup.getDisclosure().setDefaultOpen(false);
394
395 List<Component> iPropertiesItems = new ArrayList<Component>();
396 Message iPropertiesMessage = ComponentFactory.getMessage();
397 iPropertiesMessage.setParseComponents(false);
398 iPropertiesMessage.setMessageText(messageContent);
399 iPropertiesItems.add(iPropertiesMessage);
400 iPropertiesGroup.setItems(iPropertiesItems);
401
402 propertiesItems.add(iPropertiesGroup);
403 }
404 }
405
406 documentationGroup.setItems(propertiesItems);
407
408 tabItems.add(documentationGroup);
409 } catch (Exception e) {
410 throw new RuntimeException("Error loading class: " + javaFullClassPath, e);
411 }
412 }
413
414
415
416
417
418
419
420 private String getPropName(Method method) {
421 String name = method.getName();
422
423 if (name.startsWith("get")) {
424 name = name.replaceFirst("get", "");
425 } else {
426 name = name.replaceFirst("is", "");
427 }
428
429 name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
430
431 return name;
432 }
433
434
435
436
437
438
439 private void processXmlSource(List<String> sourceCode) {
440 Map<String, String> idSourceMap = new HashMap<String, String>();
441 if (xmlFilePath != null) {
442 try {
443
444 URL fileUrl = ComponentLibraryView.class.getClassLoader().getResource(xmlFilePath);
445 File file = new File(fileUrl.toURI());
446 Pattern examplePattern = Pattern.compile("ex:(.*?)(\\s|(-->))");
447
448 boolean readingSource = false;
449 String currentSource = "";
450 String currentId = "";
451
452 LineIterator lineIt = FileUtils.lineIterator(file);
453 while (lineIt.hasNext()) {
454 String line = lineIt.next();
455 if (line.contains("ex:") && !readingSource) {
456
457 readingSource = true;
458
459 Matcher matcher = examplePattern.matcher(line);
460 if (matcher.find()) {
461 currentId = matcher.group(1);
462 }
463
464 currentSource = idSourceMap.get(currentId) != null ? idSourceMap.get(currentId) : "";
465
466 if (!currentSource.isEmpty()) {
467 currentSource = currentSource + "\n";
468 }
469 } else if (line.contains("ex:") && readingSource) {
470
471 readingSource = false;
472 idSourceMap.put(currentId, currentSource);
473 } else if (readingSource) {
474
475 currentSource = currentSource + line + "\n";
476 }
477
478 }
479 } catch (Exception e) {
480 throw new RuntimeException(
481 "file not found or error while reading: " + xmlFilePath + " for source reading", e);
482 }
483 }
484
485 for (Group demoGroup : demoGroups) {
486
487 String groupId = demoGroup.getId();
488 String source = idSourceMap.get(groupId);
489 if (source != null) {
490
491 sourceCode.add(translateSource(source));
492 }
493 }
494 }
495
496
497
498
499
500
501
502
503 private String translateSource(String source) {
504
505 source = source.replace("<", "<");
506 source = source.replace(">", ">");
507 source = source.replaceAll("[ \\t]", " ");
508
509 Pattern linePattern = Pattern.compile("(( )*).*?(\\n)+");
510 Matcher matcher = linePattern.matcher(source);
511 int toRemove = -1;
512
513
514 while (matcher.find()) {
515 String spaces = matcher.group(1);
516
517 int count = StringUtils.countOccurrencesOf(spaces, " ");
518 if (toRemove == -1 || count < toRemove) {
519 toRemove = count;
520 }
521 }
522
523 matcher.reset();
524 String newSource = "";
525
526
527 while (matcher.find()) {
528 String line = matcher.group();
529 newSource = newSource + line.replaceFirst("( ){" + toRemove + "}", "");
530 }
531
532
533 newSource = newSource.replaceAll("\\n$", "");
534
535 newSource = newSource.replace("\n", "
");
536
537 return newSource;
538 }
539
540
541
542
543 public ComponentLibraryView() {
544 demoGroups = new ArrayList<Group>();
545 }
546
547
548
549
550
551
552 public String getComponentName() {
553 return componentName;
554 }
555
556
557
558
559
560
561 public void setComponentName(String componentName) {
562 this.componentName = componentName;
563 }
564
565
566
567
568
569
570
571 public String getJavaFullClassPath() {
572 return javaFullClassPath;
573 }
574
575
576
577
578
579
580 public void setJavaFullClassPath(String javaFullClassPath) {
581 this.javaFullClassPath = javaFullClassPath;
582 }
583
584
585
586
587
588
589 public String getXmlFilePath() {
590 return xmlFilePath;
591 }
592
593
594
595
596
597
598 public void setXmlFilePath(String xmlFilePath) {
599 this.xmlFilePath = xmlFilePath;
600 }
601
602
603
604
605
606
607 public String getDescription() {
608 return description;
609 }
610
611
612
613
614
615
616 public void setDescription(String description) {
617 this.description = description;
618 }
619
620
621
622
623
624
625 public String getUsage() {
626 return usage;
627 }
628
629
630
631
632
633
634 public void setUsage(String usage) {
635 this.usage = usage;
636 }
637
638
639
640
641
642
643 public Group getDetailsGroup() {
644 return detailsGroup;
645 }
646
647
648
649
650
651
652 public void setDetailsGroup(Group detailsGroup) {
653 this.detailsGroup = detailsGroup;
654 }
655
656
657
658
659
660
661 public ComponentExhibit getExhibit() {
662 return exhibit;
663 }
664
665
666
667
668
669
670 public void setExhibit(ComponentExhibit exhibit) {
671 this.exhibit = exhibit;
672 }
673
674
675
676
677
678
679
680 public List<Group> getDemoGroups() {
681 return demoGroups;
682 }
683
684
685
686
687
688
689 public void setDemoGroups(List<Group> demoGroups) {
690 this.demoGroups = demoGroups;
691 }
692
693
694
695
696
697
698 public String getRootJavadocAddress() {
699 return rootJavadocAddress;
700 }
701
702
703
704
705
706
707 public void setRootJavadocAddress(String rootJavadocAddress) {
708 this.rootJavadocAddress = rootJavadocAddress;
709 }
710
711
712
713
714
715
716 public String getRootDocBookAddress() {
717 return rootDocBookAddress;
718 }
719
720
721
722
723
724
725 public void setRootDocBookAddress(String rootDocBookAddress) {
726 this.rootDocBookAddress = rootDocBookAddress;
727 }
728
729
730
731
732
733
734 public String getDocBookAnchor() {
735 if (docBookAnchor == null) {
736 return "";
737 } else {
738 return "#" + docBookAnchor;
739 }
740 }
741
742
743
744
745
746
747 public void setDocBookAnchor(String docBookAnchor) {
748 this.docBookAnchor = docBookAnchor;
749 }
750
751 public ExampleSize getExampleSize() {
752 return exampleSize;
753 }
754
755 public void setExampleSize(ExampleSize exampleSize) {
756 this.exampleSize = exampleSize;
757 }
758
759 public String getLargeExampleFieldId() {
760 return largeExampleFieldId;
761 }
762
763 public void setLargeExampleFieldId(String largeExampleFieldId) {
764 this.largeExampleFieldId = largeExampleFieldId;
765 }
766 }