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