Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/axis/wsdl/toJava/JavaWriter.java


1   /*
2    * Copyright 2001-2004 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  package org.apache.axis.wsdl.toJava;
17  
18  import org.apache.axis.utils.Messages;
19  import org.apache.axis.wsdl.gen.Generator;
20  import org.w3c.dom.Element;
21  import org.w3c.dom.Node;
22  
23  import java.io.File;
24  import java.io.FileWriter;
25  import java.io.IOException;
26  import java.io.PrintWriter;
27  import java.util.StringTokenizer;
28  
29  /**
30   * Emitter knows about WSDL writers, one each for PortType, Binding, Service,
31   * Definition, Type.  But for some of these WSDL types, Wsdl2java generates
32   * multiple files.  Each of these files has a corresponding writer that extends
33   * JavaWriter.  So the Java WSDL writers (JavaPortTypeWriter, JavaBindingWriter,
34   * etc.) each calls a file writer (JavaStubWriter, JavaSkelWriter, etc.) for
35   * each file that that WSDL generates.
36   * <p/>
37   * <p>For example, when Emitter calls JavaWriterFactory for a Binding Writer, it
38   * returns a JavaBindingWriter.  JavaBindingWriter, in turn, contains a
39   * JavaStubWriter, JavaSkelWriter, and JavaImplWriter since a Binding may cause
40   * a stub, skeleton, and impl template to be generated.
41   * <p/>
42   * <p>Note that the writers that are given to Emitter by JavaWriterFactory DO NOT
43   * extend JavaWriter.  They simply implement Writer and delegate the actual
44   * task of writing to extensions of JavaWriter.
45   * <p/>
46   * <p>All of Wsdl2java's Writer implementations follow a common behaviour.
47   * JavaWriter is the abstract base class that dictates this common behaviour.
48   * This behaviour is primarily placed within the generate method.  The generate
49   * method calls, in succession (note:  the starred methods are the ones you are
50   * probably most interested in):
51   * <dl>
52   * <dt> * getFileName
53   * <dd> This is an abstract method that must be implemented by the subclass.
54   * It returns the fully-qualified file name.
55   * <dt> isFileGenerated(file)
56   * <dd> You should not need to override this method.  It checks to see whether
57   * this file is in the List returned by emitter.getGeneratedFileNames.
58   * <dt> registerFile(file)
59   * <dd> You should not need to override this method.  It registers this file by
60   * calling emitter.getGeneratedFileInfo().add(...).
61   * <dt> * verboseMessage(file)
62   * <dd> You may override this method if you want to provide more information.
63   * The generate method only calls verboseMessage if verbose is turned on.
64   * <dt> getPrintWriter(file)
65   * <dd> You should not need to override this method.  Given the file name, it
66   * creates a PrintWriter for it.
67   * <dt> * writeFileHeader(pw)
68   * <dd> You may want to override this method.  The default implementation
69   * generates nothing.
70   * <dt> * writeFileBody(pw)
71   * <dd> This is an abstract method that must be implemented by the subclass.
72   * This is where the body of a file is generated.
73   * <dt> * writeFileFooter(pw)
74   * <dd> You may want to override this method.  The default implementation
75   * generates nothing.
76   * <dt> closePrintWriter(pw)
77   * <dd> You should not need to override this method.  It simply closes the
78   * PrintWriter.
79   * </dl>
80   */
81  public abstract class JavaWriter implements Generator {
82  
83      /** This controls how many characters per line for javadoc comments */
84      protected final static int LINE_LENGTH = 65;
85  
86      /** Field emitter */
87      protected Emitter emitter;
88  
89      /** Field type */
90      protected String type;
91  
92      /**
93       * Constructor.
94       *
95       * @param emitter
96       * @param type
97       */
98      protected JavaWriter(Emitter emitter, String type) {
99          this.emitter = emitter;
100         this.type = type;
101     }    // ctor
102 
103     /**
104      * Generate a file.
105      *
106      * @throws IOException
107      */
108     public void generate() throws IOException {
109 
110         String file = getFileName();
111 
112         if (isFileGenerated(file)) {
113             throw new DuplicateFileException(
114                     Messages.getMessage("duplicateFile00", file), file);
115         }
116 
117         registerFile(file);
118 
119         if (emitter.isVerbose()) {
120             String msg = verboseMessage(file);
121 
122             if (msg != null) {
123                 System.out.println(msg);
124             }
125         }
126 
127         PrintWriter pw = getPrintWriter(file);
128 
129         writeFileHeader(pw);
130         writeFileBody(pw);
131         writeFileFooter(pw);
132         closePrintWriter(pw);
133     }    // generate
134 
135     /**
136      * This method must be implemented by a subclass.  It
137      * returns the fully-qualified name of the file to be
138      * generated.
139      *
140      * @return
141      */
142     protected abstract String getFileName();
143 
144     /**
145      * You should not need to override this method. It checks
146      * to see whether the given file is in the List returned
147      * by emitter.getGeneratedFileNames.
148      *
149      * @param file
150      * @return
151      */
152     protected boolean isFileGenerated(String file) {
153         return emitter.getGeneratedFileNames().contains(file);
154     }    // isFileGenerated
155 
156     /**
157      * You should not need to override this method.
158      * It registers the given file by calling
159      * emitter.getGeneratedFileInfo().add(...).
160      *
161      * @param file
162      */
163     protected void registerFile(String file) {
164         emitter.getGeneratedFileInfo().add(file, null, type);
165     }    // registerFile
166 
167     /**
168      * Return the string:  "Generating <file>".  Override this
169      * method if you want to provide more information.
170      *
171      * @param file
172      * @return
173      */
174     protected String verboseMessage(String file) {
175         return Messages.getMessage("generating", file);
176     }    // verboseMessage
177 
178     /**
179      * You should not need to override this method.
180      * Given the file name, it creates a PrintWriter for it.
181      *
182      * @param filename
183      * @return
184      * @throws IOException
185      */
186     protected PrintWriter getPrintWriter(String filename) throws IOException {
187 
188         File file = new File(filename);
189         File parent = new File(file.getParent());
190 
191         parent.mkdirs();
192 
193         return new PrintWriter(new FileWriter(file));
194     }                                // getPrintWriter
195 
196     /**
197      * This method is intended to be overridden as necessary
198      * to generate file header information.  This default
199      * implementation does nothing.
200      *
201      * @param pw
202      * @throws IOException
203      */
204     protected void writeFileHeader(PrintWriter pw)
205             throws IOException {
206     }    // writeFileHeader
207 
208     /**
209      * This method must be implemented by a subclass.  This
210      * is where the body of a file is generated.
211      *
212      * @param pw
213      * @throws IOException
214      */
215     protected abstract void writeFileBody(PrintWriter pw) throws IOException;
216 
217     /**
218      * You may want to override this method.  This default
219      * implementation generates nothing.
220      *
221      * @param pw
222      * @throws IOException
223      */
224     protected void writeFileFooter(PrintWriter pw)
225             throws IOException {
226     }    // writeFileFooter
227 
228     /**
229      * Close the print writer.
230      *
231      * @param pw
232      */
233     protected void closePrintWriter(PrintWriter pw) {
234         pw.close();
235     }    // closePrintWriter
236 
237     /**
238      * Takes out new lines and wraps at Javadoc tags
239      * @param documentation the raw comments from schema
240      * @param addTab if true adds a tab character when wrapping (methods)
241      */
242     protected String getJavadocDescriptionPart(String documentation, boolean addTab) {
243         if (documentation == null) {
244             return "";
245         }
246 
247         String doc = documentation.trim();
248 
249         if (documentation.trim().length() == 0) {
250             //nothing to do
251             return doc;
252         }
253 
254         // make @ tags start a new line (for javadoc tags mostly)
255         StringTokenizer st = new StringTokenizer(doc, "@");
256         StringBuffer newComments;
257         if (st.hasMoreTokens()) {
258             String token = st.nextToken();
259             boolean startLine = Character.isWhitespace(token.charAt(token.length() - 1))
260                 && (token.charAt(token.length() - 1) != '\n');
261             newComments = new StringBuffer(token);
262             
263             while (st.hasMoreTokens()) {
264                 token = st.nextToken();
265                 // don't span links across lines
266                 if (startLine) {
267                     newComments.append('\n');
268                 }
269                 newComments.append('@');
270                 startLine = Character.isWhitespace(token.charAt(token.length() - 1))
271             & (token.charAt(token.length() - 1) != '\n');
272 
273                 newComments.append(token);
274             }
275         } else {
276             newComments = new StringBuffer(doc);
277         }
278         newComments.insert(0, addTab ? "     * " : " * ");
279 
280         // tweak comment ending tags by insterting a
281         // space between the star and the slash, BUG13407
282         int pos = newComments.toString().indexOf("*/");
283         while (pos >= 0) {
284             newComments.insert(pos + 1, ' ');
285             pos = newComments.toString().indexOf("*/");
286         }
287         
288         // now pretty it up based on column length
289         int lineStart = 0;
290         int newlinePos = 0;
291         while (lineStart < newComments.length()) {
292             newlinePos = newComments.toString().indexOf("\n", lineStart);
293             if (newlinePos == -1) {
294                 newlinePos = newComments.length();
295             }
296             if ((newlinePos - lineStart) > LINE_LENGTH) {
297                 // find first whitespace after length
298                 lineStart += LINE_LENGTH;
299                 while ((lineStart < newComments.length()) 
300                     && !Character.isWhitespace(newComments.charAt(lineStart))) {
301                     lineStart++;
302                 }
303 
304                 if (lineStart < newComments.length()) {
305                     // don't insert if line wold break at EOF
306                     char next = newComments.charAt(lineStart);
307                     // insert new line header
308                     if ((next == '\r') || (next == '\n')) {
309                         //newline exists at the break point, don't put in another one
310                         newComments.insert(lineStart + 1, addTab ? "     * " : " * ");
311                         lineStart += addTab ? 8 : 4;
312                     } else {
313                         newComments.insert(lineStart, addTab ? "\n     * " : "\n * ");
314                         lineStart += addTab ? 8 : 4;
315                     }
316                 }
317 
318                 // chew up witespace after newline
319                 while ((lineStart < newComments.length()) 
320                     && (newComments.charAt(lineStart) == ' ')) { // only chew up simple spaces
321                     newComments.delete(lineStart, lineStart + 1);
322                 }
323             } else {
324                 if (++newlinePos < newComments.length()) {
325                     newComments.insert(newlinePos, addTab ? "     * " : " * ");
326                 }
327                 lineStart = newlinePos;
328                 lineStart += addTab ? 7 : 3;
329             }
330         }
331 
332         return newComments.toString();
333     }
334 
335     /**
336      * Output a documentation element as a Java comment.
337      *
338      * @param pw
339      * @param element
340      */
341     protected void writeComment(PrintWriter pw, Element element) {
342        writeComment(pw, element, true);
343     }
344 
345     /**
346      * Output a documentation element as a Java comment.
347      *
348      * @param pw
349      * @param element
350      * @param addTab
351      */
352     protected void writeComment(PrintWriter pw, Element element, boolean addTab) {
353 
354         if (element == null) {
355             return;
356         }
357 
358         Node child = element.getFirstChild();
359 
360         if (child == null) {
361             return;
362         }
363 
364         String comment = child.getNodeValue();
365 
366         if (comment != null) {
367             int start = 0;
368 
369             pw.println();    // blank line
370 
371             pw.println(addTab ? "    /**" : "/**");
372             pw.println(getJavadocDescriptionPart(comment, addTab));
373             pw.println(addTab ? "     */" : " */");
374         }
375     }                        // writeComment
376 }    // abstract class JavaWriter