Update project structure to org.onap.aaf
[aaf/inno.git] / rosetta / src / main / java / org / onap / aaf / rosetta / OutJson.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package org.onap.aaf.rosetta;\r
24 \r
25 import java.io.IOException;\r
26 import java.io.Writer;\r
27 import java.util.Stack;\r
28 \r
29 import org.onap.aaf.inno.env.util.IndentPrintWriter;\r
30 \r
31 public class OutJson extends Out {\r
32 \r
33         @Override\r
34         public<IN,S> void extract(IN in, Writer writer, Parse<IN, S> prs, boolean ... options) throws IOException, ParseException {\r
35                 Parsed<S> p = prs.newParsed();\r
36                 IndentPrintWriter ipw;\r
37                 if(options.length>0 && options[0]) { // is Pretty\r
38                         ipw = writer instanceof IndentPrintWriter?(IndentPrintWriter)writer:new IndentPrintWriter(writer);\r
39                         writer = ipw;\r
40                 } else {\r
41                         ipw = null;\r
42                 }\r
43                 \r
44                 // If it's a fragment, print first Object Name.  If root Object, skip first name\r
45                 Stack<LevelStack> jsonLevel = new Stack<LevelStack>();\r
46                 jsonLevel.push(new LevelStack(options.length>1 && options[1]));\r
47                 boolean print = true, hadData=false;\r
48                 char afterName=0, beforeName=0, maybe = 0, prev=0;\r
49                 \r
50                 int count = 0;\r
51                 while((p = prs.parse(in,p.reuse())).valid()) {\r
52                         ++count;\r
53                         switch(p.event) {\r
54                                 case 1: \r
55                                         continue;\r
56                                 case 2:\r
57                                         if(count==2) { // it's empty, write open/close on it's own\r
58                                                 writer.append('{');\r
59                                                 writer.append('}');\r
60                                         }\r
61                                         writer.flush();\r
62                                         return;\r
63                                 case '{':\r
64                                         afterName = '{';\r
65                                         if(jsonLevel.peek().printObjectName) {\r
66                                                 print = true;\r
67                                         } else { // don't print names on first\r
68                                                 print=false; \r
69                                         }\r
70                                         maybe=jsonLevel.peek().listItem();\r
71                                         jsonLevel.push(new LevelStack(true));\r
72                                         break;\r
73                                 case '}':\r
74                                         if(p.hasData()) { // if we have data, we print that, so may need to prepend a comma.\r
75                                                 maybe = jsonLevel.peek().listItem();\r
76                                         } else { // No data means just print, \r
77                                                 p.name = ""; // XML tags come through with names, but no data\r
78                                         } \r
79                                         print = true;\r
80                                         jsonLevel.pop();\r
81                                         afterName = p.event;\r
82                                         break;\r
83                                 case '[':\r
84                                         afterName = p.event;\r
85                                         if((prev==',' && !hadData) || prev==']')maybe=',';\r
86                                         else maybe = jsonLevel.peek().listItem();\r
87 \r
88                                         jsonLevel.push(new LevelStack(false));\r
89                                         print=true;\r
90                                         break;\r
91                                 case ']':\r
92                                         afterName = p.event;\r
93                                         if(p.hasData()) {\r
94                                                 if(prev==',' && !hadData)maybe=',';\r
95                                                 else maybe = jsonLevel.peek().listItem();\r
96                                         } else {\r
97                                                 p.name = ""; // XML tags come through with names, but no data\r
98                                         } \r
99                                         jsonLevel.pop();\r
100 \r
101                                         print = true;\r
102                                         break;\r
103                                 case   3:\r
104                                 case ',':\r
105                                         if(!p.hasData()) {\r
106                                                 p.isString=false;\r
107                                                 print=false;\r
108                                         } else {\r
109                                                 maybe=jsonLevel.peek().listItem();\r
110                                                 print = true;\r
111                                         }\r
112                                         break;\r
113                                 default:\r
114                                         print = true;\r
115                         }\r
116                 \r
117                         if(maybe!=0) {\r
118                                 if(ipw==null)writer.append(maybe); \r
119                                 else ipw.println(maybe);\r
120                                 maybe = 0;\r
121                         }\r
122                         \r
123                         if(beforeName!=0) {\r
124                                 if(ipw==null)writer.append(beforeName);\r
125                                 else ipw.println(beforeName);\r
126                                 beforeName = 0;\r
127                         }\r
128                         if(print) {\r
129                                 if(p.hasName()) {\r
130                                         writer.append('"');\r
131                                         if(p.event==3)writer.append("__");\r
132                                         writer.append(p.name);\r
133                                         writer.append("\":");\r
134                                 } \r
135                                 if(p.hasData()) {\r
136                                         if(p.isString) {\r
137                                                 writer.append('"');\r
138                                                 escapedWrite(writer, p.sb);\r
139                                                 writer.append('"');\r
140                                         } else if(p.sb.length()>0) {\r
141                                                 writer.append(p.sb);\r
142                                         }\r
143                                 }\r
144                         }\r
145                         if(afterName!=0) {\r
146                                 if(ipw==null)writer.append(afterName);\r
147                                 else {\r
148                                         switch(afterName) {\r
149                                                 case '{':\r
150                                                         ipw.println(afterName);\r
151                                                         ipw.inc();\r
152                                                         break;\r
153                                                 case '}':\r
154                                                         ipw.dec();\r
155                                                         ipw.println();\r
156                                                         ipw.print(afterName);\r
157                                                         break;\r
158                                                 case ']':\r
159                                                         if(prev=='}' || prev==',')ipw.println();\r
160                                                         ipw.dec();\r
161                                                         ipw.print(afterName);\r
162                                                         break;\r
163 \r
164                                                 case ',':\r
165                                                         ipw.println(afterName);\r
166                                                         break;\r
167                                                 default:\r
168                                                         ipw.print(afterName);\r
169                                         }\r
170                                 }\r
171                                 afterName = 0;\r
172                         }\r
173                         \r
174                         if(ipw!=null) {\r
175                                 switch(p.event) {\r
176                                         case '[':\r
177                                                 ipw.inc();\r
178                                                 ipw.println();\r
179                                                 break;\r
180                                 }\r
181                         }\r
182                         prev = p.event;\r
183                         hadData = p.hasData();\r
184 \r
185                 }\r
186                 writer.flush();\r
187         }\r
188 \r
189         private void escapedWrite(Writer writer, StringBuilder sb) throws IOException {\r
190                 char c;\r
191                 for(int i=0;i<sb.length();++i) {\r
192                         switch(c=sb.charAt(i)) {\r
193                                 case '\\':\r
194                                         writer.append(c);\r
195                                         if(i<sb.length()) {\r
196                                                 c=sb.charAt(++i);\r
197                                                 writer.append(c);\r
198                                         }\r
199                                         break;\r
200                                 case '"':\r
201                                         writer.append('\\');\r
202                                         // Passthrough on purpose\r
203                                 default:\r
204                                         writer.append(c);\r
205                         }\r
206                 }\r
207 \r
208                 \r
209         }\r
210 \r
211         @Override\r
212         public String logName() {\r
213                 return "Rosetta JSON";\r
214         }\r
215 \r
216         private static class LevelStack {\r
217                 public boolean printObjectName=false;\r
218                 private boolean first_n_List=true;\r
219                 \r
220                 public LevelStack(boolean printObjectName) {\r
221                         this.printObjectName = printObjectName;\r
222                 }\r
223                 \r
224                 public char listItem() {\r
225                         if(first_n_List) {\r
226                                 first_n_List=false;\r
227                                 return 0;\r
228                         } else {\r
229                                 return ',';\r
230                         }\r
231                 }\r
232         }\r
233 }\r