source: release-kits/lirk3/resources/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/AntStructure.java@ 14982

Last change on this file since 14982 was 14982, checked in by oranfry, 16 years ago

initial import of LiRK3

File size: 11.8 KB
Line 
1/*
2 * Copyright 2000-2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.apache.tools.ant.taskdefs;
19
20import java.io.File;
21import java.io.FileOutputStream;
22import java.io.FileWriter;
23import java.io.IOException;
24import java.io.OutputStreamWriter;
25import java.io.PrintWriter;
26import java.io.UnsupportedEncodingException;
27import java.util.Enumeration;
28import java.util.Hashtable;
29import java.util.Vector;
30import org.apache.tools.ant.BuildException;
31import org.apache.tools.ant.IntrospectionHelper;
32import org.apache.tools.ant.Task;
33import org.apache.tools.ant.TaskContainer;
34import org.apache.tools.ant.types.EnumeratedAttribute;
35import org.apache.tools.ant.types.Reference;
36
37/**
38 * Creates a partial DTD for Ant from the currently known tasks.
39 *
40 *
41 *
42 * @since Ant 1.1
43 *
44 * @ant.task category="xml"
45 */
46public class AntStructure extends Task {
47
48 private final String lSep = System.getProperty("line.separator");
49
50 private static final String BOOLEAN = "%boolean;";
51 private static final String TASKS = "%tasks;";
52 private static final String TYPES = "%types;";
53
54 private Hashtable visited = new Hashtable();
55
56 private File output;
57
58 /**
59 * The output file.
60 * @param output the output file
61 */
62 public void setOutput(File output) {
63 this.output = output;
64 }
65
66 /**
67 * Build the antstructure DTD.
68 *
69 * @exception BuildException if the DTD cannot be written.
70 */
71 public void execute() throws BuildException {
72
73 if (output == null) {
74 throw new BuildException("output attribute is required", getLocation());
75 }
76
77 PrintWriter out = null;
78 try {
79 try {
80 out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output), "UTF8"));
81 } catch (UnsupportedEncodingException ue) {
82 /*
83 * Plain impossible with UTF8, see
84 * http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html
85 *
86 * fallback to platform specific anyway.
87 */
88 out = new PrintWriter(new FileWriter(output));
89 }
90
91 printHead(out, getProject().getTaskDefinitions().keys(),
92 getProject().getDataTypeDefinitions().keys());
93
94 printTargetDecl(out);
95
96 Enumeration dataTypes = getProject().getDataTypeDefinitions().keys();
97 while (dataTypes.hasMoreElements()) {
98 String typeName = (String) dataTypes.nextElement();
99 printElementDecl(out, typeName,
100 (Class) getProject().getDataTypeDefinitions().get(typeName));
101 }
102
103 Enumeration tasks = getProject().getTaskDefinitions().keys();
104 while (tasks.hasMoreElements()) {
105 String taskName = (String) tasks.nextElement();
106 printElementDecl(out, taskName,
107 (Class) getProject().getTaskDefinitions().get(taskName));
108 }
109
110 } catch (IOException ioe) {
111 throw new BuildException("Error writing "
112 + output.getAbsolutePath(), ioe, getLocation());
113 } finally {
114 if (out != null) {
115 out.close();
116 }
117 visited.clear();
118 }
119 }
120
121 /**
122 * Prints the header of the generated output.
123 *
124 * <p>Basically this prints the XML declaration, defines some
125 * entities and the project element.</p>
126 */
127 private void printHead(PrintWriter out, Enumeration tasks,
128 Enumeration types) {
129 out.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
130 out.println("<!ENTITY % boolean \"(true|false|on|off|yes|no)\">");
131 out.print("<!ENTITY % tasks \"");
132 boolean first = true;
133 while (tasks.hasMoreElements()) {
134 String taskName = (String) tasks.nextElement();
135 if (!first) {
136 out.print(" | ");
137 } else {
138 first = false;
139 }
140 out.print(taskName);
141 }
142 out.println("\">");
143 out.print("<!ENTITY % types \"");
144 first = true;
145 while (types.hasMoreElements()) {
146 String typeName = (String) types.nextElement();
147 if (!first) {
148 out.print(" | ");
149 } else {
150 first = false;
151 }
152 out.print(typeName);
153 }
154 out.println("\">");
155
156 out.println("");
157
158 out.print("<!ELEMENT project (target | ");
159 out.print(TASKS);
160 out.print(" | ");
161 out.print(TYPES);
162 out.println(")*>");
163 out.println("<!ATTLIST project");
164 out.println(" name CDATA #IMPLIED");
165 out.println(" default CDATA #IMPLIED");
166 out.println(" basedir CDATA #IMPLIED>");
167 out.println("");
168 }
169
170 /**
171 * Prints the definition for the target element.
172 */
173 private void printTargetDecl(PrintWriter out) {
174 out.print("<!ELEMENT target (");
175 out.print(TASKS);
176 out.print(" | ");
177 out.print(TYPES);
178 out.println(")*>");
179 out.println("");
180
181 out.println("<!ATTLIST target");
182 out.println(" id ID #IMPLIED");
183 out.println(" name CDATA #REQUIRED");
184 out.println(" address CDATA #IMPLIED");
185 out.println(" if CDATA #IMPLIED");
186 out.println(" unless CDATA #IMPLIED");
187 out.println(" depends CDATA #IMPLIED");
188 out.println(" description CDATA #IMPLIED>");
189 out.println("");
190 }
191
192 /**
193 * Print the definition for a given element.
194 */
195 private void printElementDecl(PrintWriter out, String name, Class element)
196 throws BuildException {
197
198 if (visited.containsKey(name)) {
199 return;
200 }
201 visited.put(name, "");
202
203 IntrospectionHelper ih = null;
204 try {
205 ih = IntrospectionHelper.getHelper(element);
206 } catch (Throwable t) {
207 /*
208 * XXX - failed to load the class properly.
209 *
210 * should we print a warning here?
211 */
212 return;
213 }
214
215 StringBuffer sb = new StringBuffer("<!ELEMENT ");
216 sb.append(name).append(" ");
217
218 if (org.apache.tools.ant.types.Reference.class.equals(element)) {
219 sb.append("EMPTY>").append(lSep);
220 sb.append("<!ATTLIST ").append(name);
221 sb.append(lSep).append(" id ID #IMPLIED");
222 sb.append(lSep).append(" refid IDREF #IMPLIED");
223 sb.append(">").append(lSep);
224 out.println(sb);
225 return;
226 }
227
228 Vector v = new Vector();
229 if (ih.supportsCharacters()) {
230 v.addElement("#PCDATA");
231 }
232
233 if (TaskContainer.class.isAssignableFrom(element)) {
234 v.addElement(TASKS);
235 }
236
237 Enumeration e = ih.getNestedElements();
238 while (e.hasMoreElements()) {
239 v.addElement(e.nextElement());
240 }
241
242 if (v.isEmpty()) {
243 sb.append("EMPTY");
244 } else {
245 sb.append("(");
246 final int count = v.size();
247 for (int i = 0; i < count; i++) {
248 if (i != 0) {
249 sb.append(" | ");
250 }
251 sb.append(v.elementAt(i));
252 }
253 sb.append(")");
254 if (count > 1 || !v.elementAt(0).equals("#PCDATA")) {
255 sb.append("*");
256 }
257 }
258 sb.append(">");
259 out.println(sb);
260
261 sb = new StringBuffer("<!ATTLIST ");
262 sb.append(name);
263 sb.append(lSep).append(" id ID #IMPLIED");
264
265 e = ih.getAttributes();
266 while (e.hasMoreElements()) {
267 String attrName = (String) e.nextElement();
268 if ("id".equals(attrName)) {
269 continue;
270 }
271
272 sb.append(lSep).append(" ").append(attrName).append(" ");
273 Class type = ih.getAttributeType(attrName);
274 if (type.equals(java.lang.Boolean.class)
275 || type.equals(java.lang.Boolean.TYPE)) {
276 sb.append(BOOLEAN).append(" ");
277 } else if (Reference.class.isAssignableFrom(type)) {
278 sb.append("IDREF ");
279 } else if (EnumeratedAttribute.class.isAssignableFrom(type)) {
280 try {
281 EnumeratedAttribute ea =
282 (EnumeratedAttribute) type.newInstance();
283 String[] values = ea.getValues();
284 if (values == null
285 || values.length == 0
286 || !areNmtokens(values)) {
287 sb.append("CDATA ");
288 } else {
289 sb.append("(");
290 for (int i = 0; i < values.length; i++) {
291 if (i != 0) {
292 sb.append(" | ");
293 }
294 sb.append(values[i]);
295 }
296 sb.append(") ");
297 }
298 } catch (InstantiationException ie) {
299 sb.append("CDATA ");
300 } catch (IllegalAccessException ie) {
301 sb.append("CDATA ");
302 }
303 } else {
304 sb.append("CDATA ");
305 }
306 sb.append("#IMPLIED");
307 }
308 sb.append(">").append(lSep);
309 out.println(sb);
310
311 final int count = v.size();
312 for (int i = 0; i < count; i++) {
313 String nestedName = (String) v.elementAt(i);
314 if (!"#PCDATA".equals(nestedName)
315 && !TASKS.equals(nestedName)
316 && !TYPES.equals(nestedName)) {
317 printElementDecl(out, nestedName, ih.getElementType(nestedName));
318 }
319 }
320 }
321
322 /**
323 * Does this String match the XML-NMTOKEN production?
324 * @param s the string to test
325 * @return true if the string matches the XML-NMTOKEN
326 */
327 protected boolean isNmtoken(String s) {
328 final int length = s.length();
329 for (int i = 0; i < length; i++) {
330 char c = s.charAt(i);
331 // XXX - we are committing CombiningChar and Extender here
332 if (!Character.isLetterOrDigit(c)
333 && c != '.' && c != '-' && c != '_' && c != ':') {
334 return false;
335 }
336 }
337 return true;
338 }
339
340 /**
341 * Do the Strings all match the XML-NMTOKEN production?
342 *
343 * <p>Otherwise they are not suitable as an enumerated attribute,
344 * for example.</p>
345 * @param s the array of string to test
346 * @return true if all the strings in the array math XML-NMTOKEN
347 */
348 protected boolean areNmtokens(String[] s) {
349 for (int i = 0; i < s.length; i++) {
350 if (!isNmtoken(s[i])) {
351 return false;
352 }
353 }
354 return true;
355 }
356
357}
Note: See TracBrowser for help on using the repository browser.