Sonar Fixes, Formatting
[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 }