1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.kuali.student.common.assembly.dictionary;
16
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Set;
21
22 import org.kuali.student.common.assembly.data.ConstraintMetadata;
23 import org.kuali.student.common.assembly.data.Data;
24 import org.kuali.student.common.assembly.data.LookupMetadata;
25 import org.kuali.student.common.assembly.data.LookupParamMetadata;
26 import org.kuali.student.common.assembly.data.Metadata;
27 import org.kuali.student.common.assembly.data.MetadataInterrogator;
28
29 public class MetadataFormatter {
30
31 private StringBuilder builder = new StringBuilder(5000);
32 private Metadata structureMetadata;
33 private String type;
34 private String rowSeperator = "\n";
35 private String colSeperator = "|";
36 private String structureName;
37 private int level;
38
39 private Set<Metadata> structuresAlreadyProcessed;
40 private MetadataFormatter parent;
41
42 public MetadataFormatter(String structureName, Metadata structureMetadata,
43 String type, MetadataFormatter parent,
44 Set<Metadata> structuresAlreadyProcessed, int level) {
45 this.structureName = structureName;
46 this.structureMetadata = structureMetadata;
47 this.type = type;
48 this.parent = parent;
49 this.structuresAlreadyProcessed = structuresAlreadyProcessed;
50 this.level = level;
51 }
52
53 public String getStructureName() {
54 return structureName;
55 }
56
57 public MetadataFormatter getParent() {
58 return parent;
59 }
60
61 public String getRowSeperator() {
62 return rowSeperator;
63 }
64
65 public void setRowSeperator(String rowSeperator) {
66 this.rowSeperator = rowSeperator;
67 }
68
69 public String getColSeparator() {
70 return colSeperator;
71 }
72
73 public void setColSeparator(String separator) {
74 this.colSeperator = separator;
75 }
76
77 private String pad(String str, int size) {
78 StringBuilder padStr = new StringBuilder(size);
79 padStr.append(str);
80 while (padStr.length() < size) {
81 padStr.append(' ');
82 }
83 return padStr.toString();
84 }
85
86 public String formatForWiki() {
87 if (!this.structuresAlreadyProcessed.add(structureMetadata)) {
88 return "";
89 }
90 if (level == 1) {
91 builder.append(rowSeperator);
92
93
94 builder.append(rowSeperator);
95 String header = "h1. " + this.calcSimpleName(structureName);
96 if (type != null) {
97 header = "h2. " + type;
98 }
99 builder.append(header);
100 builder.append("{anchor:" + structureName + "}");
101 builder.append(rowSeperator);
102 builder.append("The object key is " + structureName);
103 builder.append(rowSeperator);
104 builder.append("The type is " + type);
105 builder.append(rowSeperator);
106 builder.append(colSeperator);
107 builder.append(colSeperator);
108 builder.append("Field");
109 builder.append(colSeperator);
110 builder.append(colSeperator);
111 builder.append("Required?");
112 builder.append(colSeperator);
113 builder.append(colSeperator);
114 builder.append("DataType");
115 builder.append(colSeperator);
116 builder.append(colSeperator);
117 builder.append("Length");
118 builder.append(colSeperator);
119 builder.append(colSeperator);
120 builder.append("Dynamic");
121 builder.append(colSeperator);
122 builder.append(colSeperator);
123 builder.append("Default");
124 builder.append(colSeperator);
125 builder.append(colSeperator);
126 builder.append("Repeats?");
127 builder.append(colSeperator);
128 builder.append(colSeperator);
129 builder.append("Valid Characters");
130 builder.append(colSeperator);
131 builder.append(colSeperator);
132 builder.append("Lookup Widget");
133 builder.append(colSeperator);
134 builder.append(colSeperator);
135 builder.append("Lookup");
136 builder.append(colSeperator);
137 builder.append(colSeperator);
138 builder.append(rowSeperator);
139 }
140
141 List<String> keys = new ArrayList<String>();
142 keys.addAll(structureMetadata.getProperties().keySet());
143 Collections.sort(keys);
144 for (String key : keys) {
145 if (key.equalsIgnoreCase ("_runtimeData"))
146 {
147 continue;
148 }
149 Metadata fieldMeta = structureMetadata.getProperties().get(key);
150 builder.append(colSeperator);
151 builder.append(calcFieldInfo (key, fieldMeta));
152 builder.append(colSeperator);
153 builder.append(pad(calcRequired(fieldMeta), 10));
154 builder.append(colSeperator);
155 builder.append(pad(calcDataType(fieldMeta), 25));
156 builder.append(colSeperator);
157 builder.append(pad(calcLength(fieldMeta), 15));
158 builder.append(colSeperator);
159 builder.append(pad(calcDynamic(fieldMeta), 7));
160 builder.append(colSeperator);
161 builder.append(pad(calcDefaultValue(fieldMeta), 15));
162 builder.append(colSeperator);
163 builder.append(calcRepeating(fieldMeta));
164 builder.append(colSeperator);
165 builder.append(calcValidChars(fieldMeta));
166 builder.append(colSeperator);
167 builder.append(calcWidget(fieldMeta));
168 builder.append(colSeperator);
169 builder.append(calcLookup(fieldMeta));
170 builder.append(colSeperator);
171 builder.append(rowSeperator);
172 if (fieldMeta.getDataType().equals(Data.DataType.DATA)
173 || fieldMeta.getDataType().equals(Data.DataType.LIST)) {
174 if (fieldMeta.getProperties() == null) {
175 throw new IllegalArgumentException(
176 fieldMeta.getName()
177 + " is DATA but does not have a sub-structure defined");
178 }
179 MetadataFormatter formatter = new MetadataFormatter(key,
180 fieldMeta, null, this, structuresAlreadyProcessed,
181 level + 1);
182 builder.append(formatter.formatForWiki());
183 }
184 }
185
186 return builder.toString();
187 }
188
189 private String calcDataType(Metadata fieldMeta) {
190 if (fieldMeta.getDataType().equals(Data.DataType.LIST)) {
191 StringBuilder type = new StringBuilder();
192 type.append("LIST of ");
193 String comma = "";
194 for (String key : fieldMeta.getProperties().keySet()) {
195 type.append(comma);
196 type.append(fieldMeta.getProperties().get(key).getDataType()
197 .toString());
198 comma = ", ";
199 }
200 return type.toString();
201 }
202 return fieldMeta.getDataType().toString();
203 }
204
205 private String calcDefaultValue(Metadata fieldMeta) {
206 if (fieldMeta.getDefaultValue() != null) {
207 return fieldMeta.getDefaultValue().toString();
208 }
209 return " ";
210 }
211
212 private String calcDynamic(Metadata meta) {
213 if (meta.isDynamic()) {
214 return "dynamic";
215 }
216 return " ";
217 }
218
219 private String calcFieldInfo (String key, Metadata fieldMeta)
220 {
221 StringBuilder bldr = new StringBuilder (40);
222 bldr.append (pad(calcFullyQualifiedFieldName(key), 30));
223 if (fieldMeta.getLabelKey () != null)
224 {
225 bldr.append ("\\\\\n");
226 bldr.append ("Label: ");
227 bldr.append (fieldMeta.getLabelKey ());
228 }
229 return bldr.toString ();
230 }
231
232 public String calcFullyQualifiedFieldName(String fieldName) {
233 if (parent == null) {
234 return escapeWiki(fieldName);
235 }
236 return parent.calcFullyQualifiedFieldName(structureName) + "."
237 + escapeWiki(fieldName);
238 }
239
240 private String calcSimpleName(String name) {
241 if (name.lastIndexOf(".") != -1) {
242 name = name.substring(name.lastIndexOf(".") + 1);
243 }
244 return name;
245 }
246
247 private String calcNotSoSimpleName(String name) {
248 if (name.lastIndexOf(".") == -1) {
249 return name;
250 }
251 String simpleName = calcSimpleName(name);
252 String fieldName = calcSimpleName(name.substring(0, name.length()
253 - simpleName.length() - 1));
254 return fieldName + "." + simpleName;
255 }
256
257 private String calcRequired(Metadata fieldMeta) {
258 for (ConstraintMetadata cons : fieldMeta.getConstraints()) {
259 if (cons.getMaxOccurs() != null) {
260 if (cons.getMaxOccurs() == 0) {
261 return "NOT USED";
262 }
263 }
264
265 if (cons.getMinOccurs() != null) {
266 if (cons.getMinOccurs() >= 1) {
267 return "required";
268 }
269 }
270 }
271 return " ";
272
273 }
274
275 private static final String LINK_TO_DEFINITIONS = "KULSTG:Formatted View of Base Dictionary#Valid Character Definitions";
276
277 private String calcValidChars(Metadata fieldMeta) {
278 for (ConstraintMetadata cons : fieldMeta.getConstraints()) {
279 if (cons.getValidChars() == null) {
280 continue;
281 }
282 String validChars = escapeWiki(cons.getValidChars());
283 String descr = "[" + "See" + "|" + LINK_TO_DEFINITIONS + "]"
284 + "\\\\\n" + validChars;
285 return descr;
286 }
287 return " ";
288 }
289
290 private String escapeWiki(String str) {
291 StringBuilder bldr = new StringBuilder(str.length());
292 boolean precededByBackSlash = false;
293 for (int i = 0; i < str.length(); i++) {
294 char c = str.charAt(i);
295 switch (c) {
296 case '\\':
297 case '[':
298 case '*':
299 case ']':
300 case '|':
301 if (!precededByBackSlash) {
302 bldr.append('\\');
303 }
304 break;
305 default:
306 break;
307 }
308 bldr.append(c);
309 if (c == '\\') {
310 precededByBackSlash = true;
311 } else {
312 precededByBackSlash = false;
313 }
314 }
315 return bldr.toString();
316 }
317
318 private String calcWidget(Metadata fieldMeta) {
319 StringBuilder bldr = new StringBuilder();
320 String comma = "";
321 if (!fieldMeta.isCanEdit()) {
322 bldr.append(comma);
323 bldr.append("not editable");
324 comma = ", ";
325 }
326 if (!fieldMeta.isCanView()) {
327 bldr.append(comma);
328 bldr.append("not viewable");
329 comma = ", ";
330 }
331 if (!fieldMeta.isCanUnmask()) {
332 bldr.append(comma);
333 bldr.append("Not unmaskable");
334 comma = ", ";
335 }
336 if (fieldMeta.getInitialLookup() != null) {
337 bldr.append(comma);
338 bldr.append(fieldMeta.getInitialLookup().getWidget());
339 comma = ", ";
340 }
341 if (bldr.length() == 0) {
342 bldr.append(" ");
343 }
344 return bldr.toString();
345 }
346
347 private String calcLookup(Metadata fieldMeta) {
348 StringBuilder bldr = new StringBuilder ();
349 if (fieldMeta.getInitialLookup() != null) {
350 bldr.append (calcLookup (fieldMeta.getInitialLookup ()));
351 }
352
353 if (fieldMeta.getAdditionalLookups () != null) {
354 if (fieldMeta.getAdditionalLookups ().size () > 0) {
355 if (fieldMeta.getInitialLookup() == null) {
356 bldr.append ("No initial lookup but...");
357 }
358 bldr.append("\\\\");
359 bldr.append("\n");
360 bldr.append("\\\\");
361 bldr.append("\n");
362 bldr.append ("Additional Lookups:");
363 bldr.append("\\\\");
364 bldr.append("\n");
365 }
366 for (LookupMetadata lm : fieldMeta.getAdditionalLookups ()) {
367 bldr.append("\\\\");
368 bldr.append("\n");
369 bldr.append (calcLookup (lm));
370 bldr.append("\\\\");
371 bldr.append("\n");
372 }
373 }
374 if (bldr.length () == 0)
375 {
376 bldr.append (" ");
377 }
378 return bldr.toString ();
379 }
380
381 private String calcLookup(LookupMetadata lm) {
382 StringBuilder bldr = new StringBuilder();
383 bldr.append(lm.getId());
384
385
386
387
388 bldr.append (" - ");
389 bldr.append (lm.getName());
390 bldr.append (" " + lm.getWidget ());
391 String and = " with option ";
392 if (lm.getWidgetOptions () != null) {
393 for (LookupMetadata.WidgetOption wo: lm.getWidgetOptions ().keySet ())
394 {
395 bldr.append (" and ");
396 bldr.append (wo);
397 bldr.append ("=");
398 bldr.append (lm.getWidgetOptions ().get (wo));
399 }
400 }
401 and = "";
402 bldr.append("\\\\\n");
403 bldr.append("Implemented using search: ");
404 String searchPage = calcWikiSearchPage(lm.getSearchTypeId());
405 bldr.append("[" + lm.getSearchTypeId() + "|" + searchPage + "#"
406 + lm.getSearchTypeId() + "]");
407 List<LookupParamMetadata> configuredParameters = filterConfiguredParams(lm
408 .getParams());
409 if (configuredParameters.size() > 0) {
410 bldr.append("\\\\");
411 bldr.append("\n");
412 bldr.append(" where ");
413 and = "";
414 for (LookupParamMetadata param : configuredParameters) {
415 bldr.append(and);
416 and = " and ";
417 bldr.append(param.getName());
418 bldr.append (" (" + param.getDataType () + ") ");
419 bldr.append("=");
420 if (param.getDefaultValueString() != null) {
421 bldr.append(param.getDefaultValueString());
422 }
423 if (param.getDefaultValueList() != null) {
424 String comma = "";
425 for (String defValue : param.getDefaultValueList()) {
426 bldr.append(comma);
427 comma = ", ";
428 bldr.append(defValue);
429 }
430 }
431 }
432 }
433 List<LookupParamMetadata> userEnterableParameters = this.filterUserEnterableParams (lm
434 .getParams());
435 if (userEnterableParameters.size() > 0) {
436 bldr.append("\\\\");
437 bldr.append("\n");
438 bldr.append(" and the user can enter: ");
439 for (LookupParamMetadata param : userEnterableParameters) {
440 bldr.append ("\\\\\n");
441 bldr.append(param.getName());
442 bldr.append (" (" + param.getDataType () + ")");
443 if (param.getWidget () != null) {
444 bldr.append(" using widget ");
445 bldr.append (param.getWidget ());
446 }
447 if (param.getDefaultValueString() != null) {
448 bldr.append("defaulted to " + param.getDefaultValueString());
449 }
450 if (param.getDefaultValueList() != null) {
451 String comma = "defaulted to ";
452 for (String defValue : param.getDefaultValueList()) {
453 bldr.append(comma);
454 comma = ", ";
455 bldr.append(defValue);
456 }
457 }
458 if (param.getChildLookup () != null)
459 {
460 bldr.append("\\\\");
461 bldr.append("\n");
462 bldr.append ("using a child lookup: ");
463 bldr.append("\\\\");
464 bldr.append("\n");
465 bldr.append (calcLookup (param.getChildLookup ()));
466 }
467 }
468 }
469 return bldr.toString();
470 }
471
472 private static final String PAGE_PREFIX = "Formatted View of ";
473 private static final String PAGE_SUFFIX = " Searches";
474
475 private String calcWikiSearchPage(String searchType) {
476 return PAGE_PREFIX + calcWikigPageAbbrev(searchType) + PAGE_SUFFIX;
477 }
478
479 private String calcWikigPageAbbrev(String searchType) {
480 if (searchType == null) {
481 return null;
482 }
483 if (searchType.equals("enumeration.management.search")) {
484 return "EM";
485 }
486 if (searchType.startsWith("lu.")) {
487 return "LU";
488 }
489 if (searchType.startsWith("cluset.")) {
490 return "LU";
491 }
492 if (searchType.startsWith("lo.")) {
493 return "LO";
494 }
495 if (searchType.startsWith("lrc.")) {
496 return "LRC";
497 }
498 if (searchType.startsWith("comment.")) {
499 return "Comment";
500 }
501 if (searchType.startsWith("org.")) {
502 return "Organization";
503 }
504 if (searchType.startsWith("atp.")) {
505 return "ATP";
506 }
507 if (searchType.startsWith("person.")) {
508 return "Person";
509 }
510 if (searchType.startsWith("proposal.")) {
511 return "Proposal";
512 }
513 throw new IllegalArgumentException("Unknown type of search: "
514 + searchType);
515 }
516
517 private List<LookupParamMetadata> filterConfiguredParams(
518 List<LookupParamMetadata> params) {
519 List<LookupParamMetadata> list = new ArrayList<LookupParamMetadata>();
520 if (params == null) {
521 return list;
522 }
523 if (params.size() == 0) {
524 return list;
525 }
526 for (LookupParamMetadata param : params) {
527 if (param.getDefaultValueString() != null) {
528 list.add(param);
529 continue;
530 }
531 if (param.getDefaultValueList() != null) {
532 list.add(param);
533 continue;
534 }
535 }
536 return list;
537 }
538
539 private List<LookupParamMetadata> filterUserEnterableParams (
540 List<LookupParamMetadata> params) {
541 List<LookupParamMetadata> list = new ArrayList<LookupParamMetadata>();
542 if (params == null) {
543 return list;
544 }
545 if (params.size() == 0) {
546 return list;
547 }
548 for (LookupParamMetadata param : params) {
549 if (param.getWriteAccess () != null) {
550 if ( ! param.getWriteAccess ().equals (Metadata.WriteAccess.NEVER)) {
551 list.add(param);
552 continue;
553 }
554 }
555 }
556 return list;
557 }
558
559 private String calcRepeating(Metadata fieldMeta) {
560 if (!fieldMeta.getDataType().equals(Data.DataType.LIST)) {
561 return " ";
562 }
563
564 MetadataInterrogator mi = new MetadataInterrogator(fieldMeta);
565 if (mi.getSmallestMaxOccurs() == null) {
566 if (mi.getLargestMinOccurs() != null
567 && mi.getLargestMinOccurs() > 1) {
568 return "repeating: minimum " + mi.getLargestMinOccurs()
569 + " times";
570 }
571 return "repeating: unlimited";
572 }
573 if (mi.getSmallestMaxOccurs() == 0) {
574 return "NOT USED";
575 }
576 if (mi.getSmallestMaxOccurs() == 1) {
577 return " ";
578
579 }
580
581 if (mi.getLargestMinOccurs() != null) {
582 if (mi.getLargestMinOccurs() > 1) {
583 return "repeating: " + mi.getLargestMinOccurs() + " to "
584 + mi.getSmallestMaxOccurs() + " times";
585 }
586 }
587 return "repeating: maximum " + mi.getSmallestMaxOccurs() + " times";
588 }
589
590 private String calcLength(Metadata fieldMeta) {
591 MetadataInterrogator mi = new MetadataInterrogator(fieldMeta);
592 if (mi.getSmallestMaxLength() != null) {
593 if (mi.getLargestMinLength() != null
594 && mi.getLargestMinLength() != 0) {
595 if (mi.getSmallestMaxLength() == mi.getLargestMinLength()) {
596 return ("(must be " + mi.getSmallestMaxLength() + ")");
597 }
598 return "(" + mi.getLargestMinLength() + " to "
599 + mi.getSmallestMaxLength() + ")";
600 }
601 return "(up to " + mi.getSmallestMaxLength() + ")";
602 }
603 if (mi.getLargestMinLength() != null) {
604 return "(over " + mi.getLargestMinLength() + ")";
605 }
606 return " ";
607 }
608 }