Collection syntax change because of Sonar
[aaf/authz.git] / misc / rosetta / src / main / java / org / onap / aaf / misc / rosetta / OutXML.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.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Stack;
31
32 import org.onap.aaf.misc.env.util.IndentPrintWriter;
33 import org.onap.aaf.misc.env.util.StringBuilderWriter;
34
35 public class OutXML extends Out{
36         private static final String XMLNS_XSI = "xmlns:xsi";
37         public static final String XML_INFO = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"; 
38         public static final String XML_SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance";
39         
40         private String root;
41         private List<Prop> props;
42
43         public OutXML(String root, String ... params) {
44                 this.root = root;
45                 props = new ArrayList<>();
46                 for(String p : params) {
47                         String[] tv=p.split("=");
48                         if(tv.length==2)
49                                 props.add(new Prop(tv[0],tv[1]));
50                 }
51         }
52         
53         public OutXML(JaxInfo jaxInfo) {
54                 this(jaxInfo.name,genNS(jaxInfo));
55         }
56         
57         public OutXML(InXML inXML) {
58                 this(inXML.jaxInfo.name,genNS(inXML.jaxInfo));
59         }
60         
61         private static String[] genNS(JaxInfo jaxInfo) {
62                 return new String[] {"xmlns=" + jaxInfo.ns};
63         }
64         
65         
66         @Override
67         public<IN,S> void extract(IN in, Writer writer, Parse<IN,S> prs, boolean ... options) throws IOException, ParseException {
68                 Parsed<S> p = prs.newParsed();
69                 Stack<Level> stack = new Stack<Level>();
70                 // If it's an IndentPrintWriter, it is pretty printing.
71                 boolean pretty = (options.length>0&&options[0]);
72         
73                 IndentPrintWriter ipw;
74                 if(pretty) {
75                         if(writer instanceof IndentPrintWriter) {
76                                 ipw = (IndentPrintWriter)writer;
77                         } else {
78                                 writer = ipw = new IndentPrintWriter(writer);
79                         }
80                 } else {
81                         ipw=null;
82                 }
83                 boolean closeTag = false;
84                 Level level = new Level(null);
85                 while((p = prs.parse(in,p.reuse())).valid()) {
86                         if(!p.hasName() && level.multi!=null) {
87                                 p.name=level.multi;
88                         }
89                         if(closeTag && p.event!=Parse.ATTRIB) {
90                                 writer.append('>');
91                                 if(pretty)writer.append('\n');
92                                 closeTag = false;
93                         }
94                         switch(p.event) {
95                                 case Parse.START_DOC:
96                                         if(!(options.length>1&&options[1])) // if not a fragment, print XML Info data
97                                                 if(pretty)ipw.println(XML_INFO);
98                                                 else writer.append(XML_INFO);
99                                         break;
100                                 case Parse.END_DOC:
101                                         break;
102                                 case Parse.START_OBJ:
103                                         stack.push(level);
104                                         level = new Level(level);
105                                         if(p.hasName()) {
106                                                 closeTag = tag(writer,level.sbw,pretty,pretty,p.name,null);
107                                         } else if(root!=null && stack.size()==1) { // first Object
108                                                 closeTag = tag(writer,level.sbw,pretty,pretty,root,null);
109                                                 // Write Root Props
110                                                 for(Prop prop : props) {
111                                                         attrib(writer,pretty,prop.tag, prop.value,level);
112                                                 }
113                                         }
114                                         if(pretty)ipw.inc();
115                                         break;
116                                 case Parse.END_OBJ:
117                                         if(p.hasData())  
118                                                 closeTag = tag(writer,writer,pretty,false,p.name, XmlEscape.convert(p.sb));
119                                         if(pretty)ipw.dec();
120                                         writer.append(level.sbw.getBuffer());
121                                         level = stack.pop();
122                                         break;
123                                 case Parse.START_ARRAY: 
124                                         level.multi = p.name;
125                                         break;
126                                 case Parse.END_ARRAY:
127                                         if(p.hasData()) 
128                                                 closeTag = tag(writer,writer,pretty,false, p.name, XmlEscape.convert(p.sb));
129                                         level.multi=null;
130                                         break;
131                                 case Parse.ATTRIB:
132                                         if(p.hasData()) 
133                                                 attrib(writer,pretty,p.name, XmlEscape.convert(p.sb), level);
134                                         break;
135                                 case Parse.NEXT:
136                                         if(p.hasData())
137                                                 closeTag = tag(writer,writer,pretty, false,p.name, XmlEscape.convert(p.sb));
138                                         break;
139                         }
140                 }
141                 writer.append(level.sbw.getBuffer());
142                 writer.flush();
143         }
144         
145         private class Level {
146                 public final StringBuilderWriter sbw;
147                 public String multi;
148                 private Level prev;
149                 private Map<String,String> nses;
150                 
151                 public Level(Level level) {
152                         sbw = new StringBuilderWriter();
153                         multi = null;
154                         prev = level;
155                 }
156
157                 public boolean hasPrinted(String ns, String value, boolean create) {
158                         boolean rv = false;
159                         if(nses==null) {
160                                 if(prev!=null)rv = prev.hasPrinted(ns, value, false);
161                         } else {
162                                 String v = nses.get(ns);
163                                 return value.equals(v); // note: accomodates not finding NS as well
164                         }
165                         
166                         if(create && !rv) {
167                                 if(nses == null) nses = new HashMap<>();
168                                 nses.put(ns, value);
169                         }
170                         return rv;
171                 }
172                 
173                 
174                 
175         }
176         
177         private boolean tag(Writer fore, Writer aft, boolean pretty, boolean returns, String tag, String data) throws IOException {
178                 fore.append('<');
179                 fore.append(tag);
180                 if(data!=null) {
181                         fore.append('>'); // if no data, it may need some attributes...
182                         fore.append(data);
183                         if(returns)fore.append('\n');
184                 }
185                 aft.append("</");
186                 aft.append(tag);
187                 aft.append(">");
188                 if(pretty)aft.append('\n');
189                 return data==null;
190         }
191         
192         private void attrib(Writer fore, boolean pretty, String tag, String value, Level level) throws IOException {
193                 String realTag = tag.startsWith("__")?tag.substring(2):tag; // remove __
194                 if(realTag.equals(Parsed.EXTENSION_TAG)) { // Convert Derived name into XML defined Inheritance
195                         fore.append(" xsi:type=\"");
196                         fore.append(value);
197                         fore.append('"');
198                         if(!level.hasPrinted(XMLNS_XSI, XML_SCHEMA_INSTANCE,true)) {
199                                 fore.append(' ');
200                                 fore.append(XMLNS_XSI);
201                                 fore.append("=\"");
202                                 fore.append(XML_SCHEMA_INSTANCE);
203                                 fore.append("\"");
204                         }
205                 } else {
206                         if(realTag.startsWith("xmlns:") ) {
207                                 if(level.hasPrinted(realTag, value, true)) {
208                                         return;
209                                 }
210                         }
211                         fore.append(' ');
212                         fore.append(realTag);  
213                         fore.append("=\"");
214                         fore.append(value);
215                         fore.append('"');
216                 }
217         }
218
219         @Override
220         public String logName() {
221                 return "Rosetta XML";
222         }
223
224
225 }