1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.xbean.spring.generator;
18
19 import java.io.File;
20 import java.io.FileWriter;
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.util.Iterator;
24 import java.util.List;
25
26
27
28
29
30
31 public class XsdGenerator implements GeneratorPlugin {
32 private final File destFile;
33 private LogFacade log;
34
35 public XsdGenerator(File destFile) {
36 this.destFile = destFile;
37 }
38
39 public void generate(NamespaceMapping namespaceMapping) throws IOException {
40
41 File file = destFile;
42 log.log("Generating XSD file: " + file + " for namespace: " + namespaceMapping.getNamespace());
43 PrintWriter out = new PrintWriter(new FileWriter(file));
44 try {
45 generateSchema(out, namespaceMapping);
46 } finally {
47 out.close();
48 }
49 }
50
51 public void generateSchema(PrintWriter out, NamespaceMapping namespaceMapping) {
52 out.println("<?xml version='1.0'?>");
53 out.println("<!-- NOTE: this file is autogenerated by Apache XBean -->");
54 out.println();
55 out.println("<xs:schema elementFormDefault='qualified'");
56 out.println(" targetNamespace='" + namespaceMapping.getNamespace() + "'");
57 out.println(" xmlns:xs='http://www.w3.org/2001/XMLSchema'");
58 out.println(" xmlns:tns='" + namespaceMapping.getNamespace() + "'>");
59
60 for (Iterator iter = namespaceMapping.getElements().iterator(); iter.hasNext();) {
61 ElementMapping element = (ElementMapping) iter.next();
62 generateElementMapping(out, namespaceMapping, element);
63 }
64
65 out.println();
66 out.println("</xs:schema>");
67 }
68
69 private void generateElementMapping(PrintWriter out, NamespaceMapping namespaceMapping, ElementMapping element) {
70 out.println();
71 out.println(" <!-- element for type: " + element.getClassName() + " -->");
72
73 String localName = element.getElementName();
74
75 out.println(" <xs:element name='" + localName + "'>");
76
77 if (!isEmptyString(element.getDescription())) {
78 out.println(" <xs:annotation>");
79 out.println(" <xs:documentation><![CDATA[");
80 out.println(" " + element.getDescription());
81 out.println(" ]]></xs:documentation>");
82 out.println(" </xs:annotation>");
83 }
84
85 out.println(" <xs:complexType>");
86
87 int complexCount = 0;
88 for (Iterator iterator = element.getAttributes().iterator(); iterator.hasNext();) {
89 AttributeMapping attributeMapping = (AttributeMapping) iterator.next();
90 if (!namespaceMapping.isSimpleType(attributeMapping.getType())) {
91 complexCount++;
92 }
93 }
94 if (complexCount > 0) {
95 out.println(" <xs:sequence>");
96 for (Iterator iterator = element.getAttributes().iterator(); iterator.hasNext();) {
97 AttributeMapping attributeMapping = (AttributeMapping) iterator.next();
98 if (!namespaceMapping.isSimpleType(attributeMapping.getType())) {
99 generateElementMappingComplexProperty(out, namespaceMapping, attributeMapping);
100 }
101 }
102 out.println(" <xs:any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>");
103 out.println(" </xs:sequence>");
104 }
105
106 for (Iterator iterator = element.getAttributes().iterator(); iterator.hasNext();) {
107 AttributeMapping attributeMapping = (AttributeMapping) iterator.next();
108 if (namespaceMapping.isSimpleType(attributeMapping.getType())) {
109 generateElementMappingSimpleProperty(out, attributeMapping);
110 } else if (!attributeMapping.getType().isCollection()) {
111 generateElementMappingComplexPropertyAsRef(out, attributeMapping);
112 }
113 }
114 generateIDAttributeMapping(out, namespaceMapping, element);
115
116 out.println(" <xs:anyAttribute namespace='##other' processContents='lax'/>");
117 out.println(" </xs:complexType>");
118 out.println(" </xs:element>");
119 out.println();
120 }
121
122 private boolean isEmptyString(String str) {
123 if (str == null) {
124 return true;
125 }
126 for (int i = 0; i < str.length(); i++) {
127 if (!Character.isWhitespace(str.charAt(i))) {
128 return false;
129 }
130 }
131 return true;
132 }
133
134 private void generateIDAttributeMapping(PrintWriter out, NamespaceMapping namespaceMapping, ElementMapping element) {
135 for (Iterator iterator = element.getAttributes().iterator(); iterator.hasNext();) {
136 AttributeMapping attributeMapping = (AttributeMapping) iterator.next();
137 if ("id".equals(attributeMapping.getAttributeName())) {
138 return;
139 }
140 }
141 out.println(" <xs:attribute name='id' type='xs:ID'/>");
142 }
143
144 private void generateElementMappingSimpleProperty(PrintWriter out, AttributeMapping attributeMapping) {
145
146 String type = attributeMapping.getPropertyEditor() != null ?
147 Utils.getXsdType(Type.newSimpleType(String.class.getName())) : Utils.getXsdType(attributeMapping.getType());
148 if (!isEmptyString(attributeMapping.getDescription())) {
149 out.println(" <xs:attribute name='" + attributeMapping.getAttributeName() + "' type='" + type + "'>");
150 out.println(" <xs:annotation>");
151 out.println(" <xs:documentation><![CDATA[");
152 out.println(" " + attributeMapping.getDescription());
153 out.println(" ]]></xs:documentation>");
154 out.println(" </xs:annotation>");
155 out.println(" </xs:attribute>");
156 } else {
157 out.println(" <xs:attribute name='" + attributeMapping.getAttributeName() + "' type='" + type + "'/>");
158 }
159 }
160
161 private void generateElementMappingComplexPropertyAsRef(PrintWriter out, AttributeMapping attributeMapping) {
162 if (!isEmptyString(attributeMapping.getDescription())) {
163 out.println(" <xs:attribute name='" + attributeMapping.getAttributeName() + "' type='xs:string'>");
164 out.println(" <xs:annotation>");
165 out.println(" <xs:documentation><![CDATA[");
166 out.println(" " + attributeMapping.getDescription());
167 out.println(" ]]></xs:documentation>");
168 out.println(" </xs:annotation>");
169 out.println(" </xs:attribute>");
170 } else {
171 out.println(" <xs:attribute name='" + attributeMapping.getAttributeName() + "' type='xs:string'/>");
172 }
173 }
174
175 private void generateElementMappingComplexProperty(PrintWriter out, NamespaceMapping namespaceMapping, AttributeMapping attributeMapping) {
176 Type type = attributeMapping.getType();
177 List types;
178 if (type.isCollection()) {
179 types = Utils.findImplementationsOf(namespaceMapping, type.getNestedType());
180 } else {
181 types = Utils.findImplementationsOf(namespaceMapping, type);
182 }
183 String maxOccurs = type.isCollection() || "java.util.Map".equals(type.getName()) ? "unbounded" : "1";
184
185 out.println(" <xs:element name='" + attributeMapping.getAttributeName() + "' minOccurs='0' maxOccurs='1'>");
186 if (!isEmptyString(attributeMapping.getDescription())) {
187 out.println(" <xs:annotation>");
188 out.println(" <xs:documentation><![CDATA[");
189 out.println(" " + attributeMapping.getDescription());
190 out.println(" ]]></xs:documentation>");
191 out.println(" </xs:annotation>");
192 }
193 out.println(" <xs:complexType>");
194 if (types.isEmpty()) {
195
196 out.println(" <xs:sequence minOccurs='0' maxOccurs='" + maxOccurs + "'><xs:any minOccurs='0' maxOccurs='unbounded'/></xs:sequence>");
197 } else {
198 out.println(" <xs:choice minOccurs='0' maxOccurs='" + maxOccurs + "'>");
199 for (Iterator iterator = types.iterator(); iterator.hasNext();) {
200 ElementMapping element = (ElementMapping) iterator.next();
201 out.println(" <xs:element ref='tns:" + element.getElementName() + "'/>");
202 }
203 out.println(" <xs:any namespace='##other'/>");
204 out.println(" </xs:choice>");
205 }
206 out.println(" </xs:complexType>");
207 out.println(" </xs:element>");
208 }
209
210 public LogFacade getLog() {
211 return log;
212 }
213
214 public void setLog(LogFacade log) {
215 this.log = log;
216 }
217
218 }