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