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