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