1
+ package com .sap .oss .phosphor .fosstars .tool .format ;
2
+
3
+ import static java .util .Collections .emptyList ;
4
+
5
+ import com .fasterxml .jackson .core .JsonProcessingException ;
6
+ import com .fasterxml .jackson .databind .ObjectMapper ;
7
+ import com .sap .oss .phosphor .fosstars .advice .Advice ;
8
+ import com .sap .oss .phosphor .fosstars .advice .AdviceContent ;
9
+ import com .sap .oss .phosphor .fosstars .advice .Advisor ;
10
+ import com .sap .oss .phosphor .fosstars .model .Subject ;
11
+ import com .sap .oss .phosphor .fosstars .model .Value ;
12
+ import com .sap .oss .phosphor .fosstars .model .value .RatingValue ;
13
+ import com .sap .oss .phosphor .fosstars .model .value .ScoreValue ;
14
+ import com .sap .oss .phosphor .fosstars .tool .format .model .Advices ;
15
+ import com .sap .oss .phosphor .fosstars .tool .format .model .Feature ;
16
+ import com .sap .oss .phosphor .fosstars .tool .format .model .Rating ;
17
+ import com .sap .oss .phosphor .fosstars .tool .format .model .Score ;
18
+ import java .io .IOException ;
19
+ import java .io .UncheckedIOException ;
20
+ import java .text .DecimalFormat ;
21
+ import java .util .List ;
22
+ import java .util .stream .Collectors ;
23
+ import org .apache .commons .lang3 .StringUtils ;
24
+ import org .apache .logging .log4j .LogManager ;
25
+ import org .apache .logging .log4j .Logger ;
26
+
27
+ /**
28
+ * The class prints a pretty rating value in JSON.
29
+ */
30
+ public class JsonPrettyPrinter extends CommonFormatter {
31
+
32
+ /**
33
+ * Object Mapper for Json.
34
+ */
35
+ private static final ObjectMapper mapper = new ObjectMapper ();
36
+
37
+ /**
38
+ * A logger.
39
+ */
40
+ private static final Logger LOGGER
41
+ = LogManager .getLogger (JsonPrettyPrinter .class );
42
+
43
+ /**
44
+ * A formatter for doubles.
45
+ */
46
+ private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat ("#.#" );
47
+
48
+ static {
49
+ DECIMAL_FORMAT .setMinimumFractionDigits (1 );
50
+ DECIMAL_FORMAT .setMaximumFractionDigits (2 );
51
+ }
52
+
53
+ /**
54
+ * Initializes a pretty printer.
55
+ *
56
+ * @param advisor to be added to the printed output.
57
+ */
58
+ public JsonPrettyPrinter (Advisor advisor ) {
59
+ super (advisor );
60
+ }
61
+
62
+ @ Override
63
+ public String print (Subject subject ) {
64
+ if (!subject .ratingValue ().isPresent ()) {
65
+ return StringUtils .EMPTY ;
66
+ }
67
+ RatingValue ratingValue = subject .ratingValue ().get ();
68
+ Rating rating = from (ratingValue , subject );
69
+ rating .advices (adviceFor (subject ));
70
+ StringBuilder output = new StringBuilder ();
71
+ try {
72
+ output .append (mapper .writerWithDefaultPrettyPrinter ().writeValueAsString (rating ));
73
+ } catch (JsonProcessingException e ) {
74
+ throw new UncheckedIOException (
75
+ "Oops! Could not parse the rating value object to Json string!" , e );
76
+ }
77
+
78
+ return output .toString ();
79
+ }
80
+
81
+ /**
82
+ * Extract advices for a subject.
83
+ *
84
+ * @param subject The subject.
85
+ * @return Advices collected form a subject.
86
+ */
87
+ private List <Advices > adviceFor (Subject subject ) {
88
+ try {
89
+ return advisor .adviceFor (subject ).stream ().map (JsonPrettyPrinter ::from )
90
+ .collect (Collectors .toList ());
91
+ } catch (IOException e ) {
92
+ LOGGER .warn ("Oops! Could not collect advices!" , e );
93
+ return emptyList ();
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Map Advice to serializable class.
99
+ *
100
+ * @param advice The Advice.
101
+ * @return The serializable class.
102
+ */
103
+ private static Advices from (Advice advice ) {
104
+ AdviceContent content = advice .content ();
105
+ return new Advices (content .text (), content .feature ().name (), content .links ());
106
+ }
107
+
108
+ /**
109
+ * Format a rating value.
110
+ *
111
+ * @param ratingValue The rating value.
112
+ * @param subject The subject.
113
+ * @return A formatted rating value.
114
+ */
115
+ private static Rating from (RatingValue ratingValue , Subject subject ) {
116
+ ScoreValue scoreValue = ratingValue .scoreValue ();
117
+ Rating rating = new Rating ()
118
+ .purl (subject .purl ())
119
+ .label (ratingValue .label ().name ());
120
+ Score score = from (scoreValue );
121
+ rating .score (score );
122
+ return rating ;
123
+ }
124
+
125
+ /**
126
+ * Extract Score from Score Value.
127
+ *
128
+ * @param scoreValue The score value.
129
+ * @return the serializable Score.
130
+ */
131
+ private static Score from (ScoreValue scoreValue ) {
132
+ Score score = new Score ()
133
+ .name (scoreValue .score ().name ())
134
+ .value (tellMeActualValueOf (scoreValue ))
135
+ .confidence (printValue (scoreValue .confidence ()))
136
+ .weight (printValue (scoreValue .weight ()));
137
+ from (scoreValue , score );
138
+ return score ;
139
+ }
140
+
141
+ /**
142
+ * Map feature value to serializable class.
143
+ *
144
+ * @param featureValue The feature value.
145
+ * @return The serializable class from feature value.
146
+ */
147
+ private static Feature from (Value <?> featureValue ) {
148
+ return new Feature ()
149
+ .name (featureValue .feature ().name ())
150
+ .value (tellMeActualValueOf (featureValue ));
151
+ }
152
+
153
+ /**
154
+ * Extract Sub scores from the score value.
155
+ *
156
+ * @param scoreValue The score value to be printed.
157
+ * @param score Tells if the score is a top-level score in the rating.
158
+ */
159
+ private static void from (ScoreValue scoreValue , Score score ) {
160
+ for (Value <?> usedValue : scoreValue .usedValues ()) {
161
+ if (usedValue instanceof ScoreValue ) {
162
+ score .subScore (from ((ScoreValue ) usedValue ));
163
+ } else {
164
+ score .feature (from (usedValue ));
165
+ }
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Prints an actual value of a score value. The method takes care about unknown and not-applicable
171
+ * score values.
172
+ *
173
+ * @param scoreValue The score value.
174
+ * @return A string that represents the score value.
175
+ */
176
+ public static String tellMeActualValueOf (ScoreValue scoreValue ) {
177
+ if (scoreValue .isNotApplicable ()) {
178
+ return "N/A" ;
179
+ }
180
+
181
+ if (scoreValue .isUnknown ()) {
182
+ return "unknown" ;
183
+ }
184
+
185
+ return printValue (scoreValue .get ());
186
+ }
187
+
188
+ /**
189
+ * Prints an actual value. The method takes care about unknown and not-applicable values.
190
+ *
191
+ * @param value The value.
192
+ * @return A string that represents the score value.
193
+ */
194
+ public static String tellMeActualValueOf (Value <?> value ) {
195
+ if (value .isNotApplicable ()) {
196
+ return "N/A" ;
197
+ }
198
+
199
+ if (value .isUnknown ()) {
200
+ return "unknown" ;
201
+ }
202
+
203
+ return String .format ("%s" , value .get ());
204
+ }
205
+
206
+ /**
207
+ * Prints out a number with its max value.
208
+ *
209
+ * @param value The number.
210
+ * @return A formatted string with the number and max value.
211
+ */
212
+ public static String printValue (double value ) {
213
+ return String .format ("%-4s" ,
214
+ DECIMAL_FORMAT .format (value ));
215
+ }
216
+ }
0 commit comments