1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package net.sf.jour.signature;
22
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.OutputStream;
26 import java.util.Iterator;
27 import java.util.List;
28
29 import javassist.CtBehavior;
30 import javassist.CtClass;
31 import javassist.CtConstructor;
32 import javassist.CtField;
33 import javassist.CtMethod;
34 import javassist.Modifier;
35 import javassist.NotFoundException;
36
37 import javax.xml.parsers.DocumentBuilder;
38 import javax.xml.parsers.DocumentBuilderFactory;
39 import javax.xml.parsers.FactoryConfigurationError;
40 import javax.xml.parsers.ParserConfigurationException;
41 import javax.xml.transform.OutputKeys;
42 import javax.xml.transform.Transformer;
43 import javax.xml.transform.TransformerException;
44 import javax.xml.transform.TransformerFactory;
45 import javax.xml.transform.dom.DOMSource;
46 import javax.xml.transform.stream.StreamResult;
47
48 import net.sf.jour.util.FileUtil;
49
50 import org.w3c.dom.Attr;
51 import org.w3c.dom.Document;
52 import org.w3c.dom.Element;
53 import org.w3c.dom.Node;
54
55
56
57
58
59 public class ExportXML {
60
61 public static final String rootNodeName = "signature";
62
63 private Document document;
64
65 private APIFilter filter;
66
67 public static void export(String reportFile, List classes, APIFilter filter) {
68
69 DocumentBuilder builder;
70 try {
71 builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
72 } catch (ParserConfigurationException e) {
73 throw new RuntimeException(e);
74 } catch (FactoryConfigurationError e) {
75 throw new RuntimeException(e);
76 }
77
78 ExportXML instance = new ExportXML();
79 instance.filter = filter;
80
81 instance.document = builder.newDocument();
82
83 Element root = instance.document.createElement(rootNodeName);
84 instance.document.appendChild(root);
85
86 for (Iterator iterator = classes.iterator(); iterator.hasNext();) {
87 CtClass klass = (CtClass) iterator.next();
88 if (filter.isAPIClass(klass)) {
89 root.appendChild(instance.classNode(klass));
90 }
91 }
92 instance.serializeXML(reportFile);
93 }
94
95 private void serializeXML(String reportFile) {
96 OutputStream out = null;
97 try {
98 Transformer transformer = TransformerFactory.newInstance().newTransformer();
99
100 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
101 transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
102
103 DOMSource source = new DOMSource(document);
104
105 out = new FileOutputStream(reportFile);
106
107 StreamResult result = new StreamResult(out);
108 transformer.transform(source, result);
109
110 } catch (TransformerException e) {
111 throw new RuntimeException(e);
112 } catch (FileNotFoundException e) {
113 throw new RuntimeException(e);
114 } finally {
115 FileUtil.closeQuietly(out);
116 }
117 }
118
119 private void addAttribute(Node node, final String attrName, final String attrValue) {
120 Attr attr = document.createAttribute(attrName);
121 attr.setValue(attrValue);
122 node.getAttributes().setNamedItem(attr);
123 }
124
125 private void addModifiers(Node node, int mod) {
126 mod = APIFilter.filterModifiers(mod);
127 if (mod != 0) {
128 addAttribute(node, "modifiers", Modifier.toString(mod));
129 }
130 }
131
132 private Node classNode(CtClass klass) {
133 String nodeName = klass.isInterface()?"interface":"class";
134 Element element = document.createElement(nodeName);
135 addAttribute(element, "name", klass.getName());
136
137 addModifiers(element, klass.getModifiers());
138
139 try {
140 buildHierarchy(element, klass);
141 buildConstructors(element, klass);
142 buildMethods(element, klass);
143 buildFields(element, klass);
144 } catch (NotFoundException e) {
145 throw new RuntimeException(klass.getName(), e);
146 }
147
148 return element;
149 }
150
151 private void buildHierarchy(Element element, CtClass klass) throws NotFoundException {
152 CtClass superClass = klass.getSuperclass();
153 if ((superClass != null) && (!superClass.getName().equals(Object.class.getName()))) {
154 addAttribute(element, "extends", superClass.getName());
155 }
156
157 CtClass[] interfaces = klass.getInterfaces();
158 if (interfaces.length != 0) {
159
160 Element interfacesNode = document.createElement("implements");
161 element.appendChild(interfacesNode);
162
163 for (int i = 0; i < interfaces.length; i++) {
164 Element intElement = document.createElement("interface");
165 addAttribute(intElement, "name", interfaces[i].getName());
166 interfacesNode.appendChild(intElement);
167 }
168 }
169 }
170
171 private void buildExceptions(Element element, CtBehavior method) throws NotFoundException {
172 CtClass[] exceptions = method.getExceptionTypes();
173 for (int k = 0; k < exceptions.length; k++) {
174 Element exceptElement = document.createElement("exception");
175 addAttribute(exceptElement, "name", exceptions[k].getName());
176 element.appendChild(exceptElement);
177 }
178 }
179
180 private void buildParameterTypes(Element element, CtBehavior method) throws NotFoundException {
181 CtClass[] params = method.getParameterTypes();
182 for (int k = 0; k < params.length; k++) {
183 Element paramsElement = document.createElement("parameter");
184 addAttribute(paramsElement, "type", params[k].getName());
185 element.appendChild(paramsElement);
186 }
187 }
188
189 private void buildConstructors(Element element, CtClass klass) throws NotFoundException {
190 CtConstructor[] constructors = klass.getDeclaredConstructors();
191 int exportedCount = 0;
192 for (int i = 0; i < constructors.length; i++) {
193 if (!filter.isAPIMember(constructors[i])) {
194 continue;
195 }
196 buildConstructor(element, constructors[i]);
197 exportedCount ++;
198 }
199
200 APIFilter lrfilter = filter;
201 while (exportedCount == 0) {
202 try {
203 lrfilter = lrfilter.getLessRestrictiveFilter();
204 } catch (IllegalArgumentException e) {
205 break;
206 }
207 for (int i = 0; i < constructors.length; i++) {
208 if (!lrfilter.isAPIMember(constructors[i])) {
209 continue;
210 }
211 buildConstructor(element, constructors[i]);
212 exportedCount ++;
213 }
214 }
215 }
216
217 private void buildConstructor(Element element, CtConstructor constructor) throws NotFoundException {
218 Element constructorElement = document.createElement("constructor");
219 addModifiers(constructorElement, constructor.getModifiers());
220 buildExceptions(constructorElement, constructor);
221 buildParameterTypes(constructorElement, constructor);
222 element.appendChild(constructorElement);
223 }
224
225 private void buildMethods(Element element, CtClass klass) throws NotFoundException {
226 CtMethod[] methods = klass.getDeclaredMethods();
227 for (int i = 0; i < methods.length; i++) {
228
229 if (!filter.isAPIMember(methods[i])) {
230 continue;
231 }
232
233 Element methElement = document.createElement("method");
234 addAttribute(methElement, "name", methods[i].getName());
235 addAttribute(methElement, "return", methods[i].getReturnType().getName());
236 addModifiers(methElement, methods[i].getModifiers());
237 buildExceptions(methElement, methods[i]);
238 buildParameterTypes(methElement, methods[i]);
239
240 element.appendChild(methElement);
241 }
242 }
243
244 private void buildFields(Element element, CtClass klass) throws NotFoundException {
245 CtField[] fields = klass.getDeclaredFields();
246 for (int i = 0; i < fields.length; i++) {
247
248 if (!filter.isAPIMember(fields[i])) {
249 continue;
250 }
251
252 Element fieldElement = document.createElement("field");
253 addAttribute(fieldElement, "name", fields[i].getName());
254 addAttribute(fieldElement, "type", fields[i].getType().getName());
255 addModifiers(fieldElement, fields[i].getModifiers());
256
257 int mod = fields[i].getModifiers();
258
259 if ((Modifier.isFinal(mod)) && (Modifier.isStatic(mod)) && APIFilter.isExportableConstantType(fields[i].getType())) {
260 Object constValue = fields[i].getConstantValue();
261 if (constValue != null) {
262 addAttribute(fieldElement, "constant-value", constValue.toString());
263 }
264 }
265
266 element.appendChild(fieldElement);
267 }
268 }
269
270
271 }