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