Clover coverage report - XJavaDoc - 1.1 Coverage timestamp: Sun Oct 3 2004 19:56:54 BST FRAMES NO FRAMES |
file stats: | LOC: | 508 |  | Methods: | 23
| NCLOC: | 295 |  | Classes: | 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
Source file | Conditionals | Statements | Methods | TOTAL
DefaultXTag.java | 63.2% | 68.2% | 52.2% | 65% |

1 |  |
     /*
2 |  |
      * Copyright (c) 2001-2003 The XDoclet team
3 |  |
      * All rights reserved.
4 |  |
      */
5 |  |
     package xjavadoc;
6 |  |
7 |  |
     import java.util.*;
8 |  |
9 |  |
     import xjavadoc.event.XTagListener;
10 |  |
     import xjavadoc.event.XTagEvent;
11 |  |
     import xjavadoc.filesystem.AbstractFile;
12 |  |
13 |  |
     /**
14 |  |
      * @author    Aslak Hellesøy
15 |  |
      * @created   11. januar 2002
16 |  |
      */
17 |  |
     public class DefaultXTag implements XTag
18 |  |
     {
19 |  |
         public static int  instanceCount = 0;
20 |  |
21 |  |
         /**
22 |  |
          * tag name
23 |  |
          */
24 |  |
         private String     _name;
25 |  |
26 |  |
         /**
27 |  |
          * string representation of tag
28 |  |
          */
29 |  |
         private String     _value;
30 |  |
31 |  |
         /**
32 |  |
          * attribute map
33 |  |
          */
34 |  |
         private Map        _attributes;
35 |  |
36 |  |
         /**
37 |  |
          * Ordered List of attribute names
38 |  |
          */
39 |  |
         private List       _attributeNames = null;
40 |  |
41 |  |
         /**
42 |  |
          * tag parse status
43 |  |
          */
44 |  |
         private boolean    _isParsed = false;
45 |  |
46 |  |
         private int        _hash = Integer.MIN_VALUE;
47 |  |
48 |  |
         /**
49 |  |
          * indicate dirty state
50 |  |
          */
51 |  |
         private boolean    _isDirty = false;
52 |  |
53 |  |
         private XDoc       _doc;
54 |  |
55 |  |
         /**
56 |  |
          * tag listeners interested in changes. This would be parent xdoc
57 |  |
          */
58 |  |
         private Set        _tagListeners;
59 |  |
60 |  |
         private int        _lineNumber;
61 |  |
62 |  |
         private XJavaDoc _xJavaDoc;
63 |  |
64 | 712 |
         public DefaultXTag()
65 |  |
         {
66 | 712 |
             instanceCount++;
67 |  |
         }
68 |  |
69 |  |
         /**
70 |  |
          * Skips whitespaces, starting from index i till the first non-whitespace
71 |  |
          * character or end of s and returns the new index.
72 |  |
          *
73 |  |
          * @param s  Describe what the parameter does
74 |  |
          * @param i  Describe what the parameter does
75 |  |
          * @return   Describe the return value
76 |  |
          */
77 | 138 |
         private static int skipWhitespace( String s, int i )
78 |  |
         {
79 | 138 |
             while( i < s.length() && Character.isWhitespace( s.charAt( i ) ) )
80 |  |
             {
81 | 24 |
                 i++;
82 |  |
             }
83 | 138 |
             return i;
84 |  |
         }
85 |  |
86 | 0 |
         public final XDoc getDoc()
87 |  |
         {
88 | 0 |
             return _doc;
89 |  |
         }
90 |  |
91 |  |
         /**
92 |  |
          * Returns the first tag parameter with the given name, or null if none exist;
93 |  |
          *
94 |  |
          * @param attributeName  Describe what the parameter does
95 |  |
          * @return               The Parameter value
96 |  |
          */
97 | 28 |
         public final String getAttributeValue( String attributeName )
98 |  |
         {
99 | 28 |
             if( !_isParsed )
100 |  |
             {
101 | 6 |
                 parse();
102 |  |
             }
103 |  |
104 | 28 |
             return _attributes == null ? null : ( String ) _attributes.get( attributeName );
105 |  |
         }
106 |  |
107 |  |
         /**
108 |  |
          * Returns all tag parameters with the given name, or an empty List if none
109 |  |
          * exist;
110 |  |
          *
111 |  |
          * @return   The Parameters value
112 |  |
          */
113 | 18 |
         public final Collection getAttributeNames()
114 |  |
         {
115 | 18 |
             if( !_isParsed )
116 |  |
             {
117 | 0 |
                 parse();
118 |  |
             }
119 | 18 |
             return _attributeNames == null ? AbstractProgramElement.EMPTY_LIST : _attributeNames;
120 |  |
         }
121 |  |
122 |  |
         /**
123 |  |
          * Returns the full name of the tag, excluding the @
124 |  |
          *
125 |  |
          * @return   tag name
126 |  |
          */
127 | 28 |
         public final String getName()
128 |  |
         {
129 | 28 |
             if( !_isParsed )
130 |  |
             {
131 | 26 |
                 parse();
132 |  |
             }
133 | 28 |
             return _name;
134 |  |
         }
135 |  |
136 |  |
         /**
137 |  |
          * Returns the full value of the tag.
138 |  |
          *
139 |  |
          * @return   full value of the tag
140 |  |
          */
141 | 318 |
         public final String getValue()
142 |  |
         {
143 | 318 |
             return _value;
144 |  |
         }
145 |  |
146 | 0 |
         public final int getLineNumber()
147 |  |
         {
148 | 0 |
             return _lineNumber;
149 |  |
         }
150 |  |
151 | 0 |
         public final String getInfo()
152 |  |
         {
153 | 0 |
             XProgramElement pe = getDoc().getOwner();
154 | 0 |
             AbstractFile file = XJavaDoc.getSourceFileFor( pe );
155 |  |
156 | 0 |
             return "@" + getName() + " at " + file.getPath() + ":" + getLineNumber();
157 |  |
         }
158 |  |
159 |  |
         /**
160 |  |
          * Adds a parameter
161 |  |
          *
162 |  |
          * @param attributeName   The new Attribute value
163 |  |
          * @param attributeValue  The new Attribute value
164 |  |
          */
165 | 0 |
         public final void setAttribute( String attributeName, String attributeValue )
166 |  |
         {
167 | 0 |
             if( !_isParsed )
168 |  |
             {
169 | 0 |
                 parse();
170 |  |
             }
171 | 0 |
             setAttribute_Impl( attributeName, attributeValue );
172 | 0 |
             fireTagChanged();
173 | 0 |
             _isDirty = true;
174 | 0 |
             _value = null;
175 |  |
         }
176 |  |
177 |  |
         /**
178 |  |
          * add doc listener interested in chages
179 |  |
          *
180 |  |
          * @param tagListener  The feature to be added to the TagListener attribute
181 |  |
          */
182 | 710 |
         public final void addTagListener( XTagListener tagListener )
183 |  |
         {
184 | 710 |
             ensureTagListenersInitialised();
185 |  |
186 | 710 |
             _tagListeners.add( tagListener );
187 |  |
         }
188 |  |
189 |  |
         /**
190 |  |
          * remove doc listener
191 |  |
          *
192 |  |
          * @param tagListener
193 |  |
          */
194 | 0 |
         public final void removeTagListener( XTagListener tagListener )
195 |  |
         {
196 | 0 |
             ensureTagListenersInitialised();
197 |  |
198 | 0 |
             _tagListeners.remove( tagListener );
199 |  |
         }
200 |  |
201 |  |
         /**
202 |  |
          * Removes an attribute
203 |  |
          *
204 |  |
          * @param attributeName  atribute to remove
205 |  |
          * @return               the removed attribute value or null if it didn't exist
206 |  |
          */
207 | 0 |
         public final String removeAttribute( String attributeName )
208 |  |
         {
209 | 0 |
             if( !_isParsed )
210 |  |
             {
211 | 0 |
                 parse();
212 |  |
             }
213 | 0 |
             _isDirty = true;
214 | 0 |
             resetValue();
215 | 0 |
             fireTagChanged();
216 |  |
217 | 0 |
             String removed = ( String ) _attributes.remove( attributeName );
218 |  |
219 | 0 |
             if( removed != null )
220 |  |
             {
221 | 0 |
                 _attributeNames.remove( attributeName );
222 | 0 |
                 _value = null;
223 |  |
             }
224 | 0 |
             return removed;
225 |  |
         }
226 |  |
227 | 0 |
         public final boolean equals( Object o )
228 |  |
         {
229 |  |
             // we compare by equality
230 | 0 |
             return this == o;
231 |  |
         }
232 |  |
233 | 0 |
         public final int hashCode()
234 |  |
         {
235 | 0 |
             if( _hash == Integer.MIN_VALUE )
236 |  |
             {
237 | 0 |
                 _hash += _name.hashCode();
238 |  |
             }
239 | 0 |
             return _hash;
240 |  |
         }
241 |  |
242 |  |
         /**
243 |  |
          * Validates the tag
244 |  |
          *
245 |  |
          * @exception TagValidationException
246 |  |
          */
247 | 0 |
         public void validate() throws TagValidationException
248 |  |
         {
249 |  |
             // Default is OK.
250 |  |
         }
251 |  |
252 |  |
         /**
253 |  |
          * Utility method that should be called from {@link #validate()} in
254 |  |
          * case ov a validation failure. Throws a new TagValidationException
255 |  |
          * with
256 |  |
          * @param message the message to include
257 |  |
          * @throws TagValidationException always thrown.
258 |  |
          */
259 | 0 |
         protected final void fail(String message) throws TagValidationException {
260 | 0 |
             throw new TagValidationException( message, this );
261 |  |
         }
262 |  |
263 |  |
         /**
264 |  |
          * Sets the name and value. Called immediately after initialisation by
265 |  |
          * XTagFactory. Don't call this method from anywhere else.
266 |  |
          *
267 |  |
          * @param name
268 |  |
          * @param value
269 |  |
          * @param doc
270 |  |
          * @param lineNumber
271 |  |
          */
272 | 712 |
         final void init( String name, String value, XDoc doc, int lineNumber )
273 |  |
         {
274 | 712 |
             _name = name;
275 | 712 |
             _doc = doc;
276 | 712 |
             _lineNumber = lineNumber;
277 | 712 |
             _isDirty = false;
278 | 712 |
             _value = value;
279 |  |
280 |  |
             // we register ourself as one of the global tags in the corresponding
281 |  |
             // SourceClass. This is to make it easier for the SourceClass to
282 |  |
             // loop over all tags and ask them to validate themselves when the parsing
283 |  |
             // is done.
284 |  |
285 | 712 |
             if( doc != null )
286 |  |
             {
287 |  |
                 // In fact, doc should never be null. -But some of the JUnit tests
288 |  |
                 // fail to set up mocks properly, so they pass in null for doc.
289 |  |
                 // This is only to avoid NPE from tht JUnit tests. It's a dirty
290 |  |
                 // hack and the tests should be fixed.
291 | 710 |
                 XProgramElement owner = doc.getOwner();
292 | 710 |
                 _xJavaDoc = owner.getXJavaDoc();
293 | 710 |
                 _value = _xJavaDoc.dereferenceProperties( value );
294 |  |
295 | 710 |
                 if( owner != null )
296 |  |
                 {
297 | 710 |
                     SourceClass sourceClass;
298 |  |
299 | 710 |
                     if( owner.getContainingClass() != null )
300 |  |
                     {
301 | 690 |
                         sourceClass = ( SourceClass ) owner.getContainingClass();
302 |  |
                     }
303 |  |
                     else
304 |  |
                     {
305 | 20 |
                         sourceClass = ( SourceClass ) owner;
306 |  |
                     }
307 | 710 |
                     sourceClass.addTagForValidation( this );
308 |  |
                 }
309 |  |
             }
310 |  |
         }
311 |  |
312 | 38 |
         private final void setAttribute_Impl( String attributeName, String attributeValue )
313 |  |
         {
314 | 38 |
             if( attributeName == null )
315 |  |
             {
316 | 0 |
                 throw new IllegalArgumentException( "attributeName can't be null!" );
317 |  |
             }
318 | 38 |
             if( _attributes == null )
319 |  |
             {
320 | 22 |
                 _attributes = new HashMap();
321 | 22 |
                 _attributeNames = new LinkedList();
322 |  |
             }
323 | 38 |
             if( !_attributes.containsKey( attributeName ) )
324 |  |
             {
325 |  |
                 // New attribute. Just append it.
326 | 38 |
                 _attributeNames.add( attributeName );
327 |  |
             }
328 |  |
329 | 38 |
             if( _xJavaDoc != null ) {
330 | 32 |
                 attributeValue = _xJavaDoc.dereferenceProperties( attributeValue );
331 |  |
             }
332 | 38 |
             _attributes.put( attributeName, attributeValue );
333 |  |
334 | 38 |
             resetValue();
335 |  |
         }
336 |  |
337 | 710 |
         private final void ensureTagListenersInitialised()
338 |  |
         {
339 | 710 |
             if( _tagListeners == null )
340 |  |
             {
341 | 710 |
                 _tagListeners = new HashSet();
342 |  |
             }
343 |  |
         }
344 |  |
345 |  |
         /**
346 |  |
          * fire tagChanged event
347 |  |
          */
348 | 0 |
         private void fireTagChanged()
349 |  |
         {
350 | 0 |
             if( _tagListeners == null )
351 | 0 |
                 return;
352 |  |
353 | 0 |
             for( Iterator i = _tagListeners.iterator(); i.hasNext();  )
354 |  |
             {
355 | 0 |
                 XTagListener tagListener = ( XTagListener ) i.next();
356 |  |
357 | 0 |
                 tagListener.tagChanged( new XTagEvent( this ) );
358 |  |
             }
359 |  |
         }
360 |  |
361 |  |
         /**
362 |  |
          * Given the raw javadoc tag content as the <i>value</i> parameter parses it
363 |  |
          * and sets the parameter. If anything is malformed (not (foo="xxx")+), then
364 |  |
          * nothing is set.
365 |  |
          */
366 | 32 |
         private final void parse()
367 |  |
         {
368 | 32 |
             if( !_isParsed )
369 |  |
             {
370 | 32 |
                 String attributeName = null;
371 | 32 |
                 StringBuffer attributeValue = new StringBuffer();
372 | 32 |
                 int i = 0;
373 | 32 |
                 int end = 0;
374 |  |
375 | 32 |
                 String value = getValue();
376 |  |
377 | 32 |
                 while( i < value.length() )
378 |  |
                 {
379 | 46 |
                     i = skipWhitespace( value, i );
380 |  |
381 |  |
                     //explicitly to handle the tailing white spaces
382 |  |
383 | 46 |
                     if( i >= value.length() )
384 |  |
                     {
385 | 0 |
                         break;
386 |  |
                     }
387 |  |
388 |  |
                     //read attribute name
389 |  |
390 | 46 |
                     end = i;
391 | 46 |
                     while( end < value.length() && value.charAt( end ) != '=' && ( !Character.isWhitespace( value.charAt( end ) ) ) )
392 |  |
                     {
393 | 206 |
                         end++;
394 |  |
                     }
395 |  |
396 | 46 |
                     attributeName = value.substring( i, end );
397 | 46 |
                     i = skipWhitespace( value, end );
398 |  |
399 |  |
                     //skip = sign
400 |  |
401 | 46 |
                     if( i < value.length() && value.charAt( i ) == '=' )
402 |  |
                     {
403 | 38 |
                         i++;
404 |  |
                     }
405 |  |
406 |  |
                     /*
407 |  |
                      * removed single valued
408 |  |
                      */
409 | 46 |
                     i = skipWhitespace( value, i );
410 |  |
411 |  |
                     //skip " sign
412 |  |
413 | 46 |
                     if( i < value.length() && value.charAt( i ) == '"' )
414 |  |
                     {
415 | 38 |
                         i++;
416 |  |
                     }
417 |  |
                     else
418 |  |
                     {
419 |  |
                         //if (_log.isDebugEnabled()) _log.debug("Error in @tag: \" sign expected but something different found, @tags=" + value);
420 | 8 |
                         _isParsed = true;
421 | 8 |
                         return;
422 |  |
                     }
423 |  |
424 |  |
                     //read attribute value
425 |  |
426 | 362 |
                     while( i < value.length() )
427 |  |
                     {
428 | 362 |
                         if( value.charAt( i ) == '"' )
429 |  |
                         {
430 |  |
                             //if not escaped \" char
431 |  |
432 | 38 |
                             if( value.charAt( i - 1 ) != '\\' )
433 |  |
                             {
434 |  |
                                 //if last " (last parameter) in whole value string
435 |  |
436 | 38 |
                                 if( i + 1 >= value.length() )
437 |  |
                                 {
438 | 22 |
                                     break;
439 |  |
                                 }
440 |  |
                                 else
441 |  |
                                 {
442 |  |
                                     //if tailing " with whitespace after it
443 |  |
444 | 16 |
                                     if( Character.isWhitespace( value.charAt( i + 1 ) ) )
445 |  |
                                     {
446 | 16 |
                                         break;
447 |  |
                                     }
448 |  |
                                     else
449 |  |
                                     {
450 |  |
                                         //probably user does not know escaping is needed!
451 |  |
                                         //if (_log.isDebugEnabled()) _log.debug("Error in @tag: to put \" in a parameter value you need to escape \" character with \\\", @tags=" + value);
452 | 0 |
                                         _isParsed = true;
453 | 0 |
                                         return;
454 |  |
                                     }
455 |  |
                                 }
456 |  |
                             }
457 |  |
                             else
458 |  |
                             {
459 |  |
                                 //remove previous \
460 | 0 |
                                 attributeValue.delete( attributeValue.length() - 1, attributeValue.length() );
461 |  |
                             }
462 |  |
                         }
463 |  |
464 | 324 |
                         attributeValue.append( value.charAt( i ) );
465 |  |
466 | 324 |
                         i++;
467 |  |
                     }
468 |  |
469 |  |
                     //skip " sign
470 |  |
471 | 38 |
                     if( i < value.length() && value.charAt( i ) == '"' )
472 |  |
                     {
473 | 38 |
                         i++;
474 |  |
                     }
475 |  |
                     else
476 |  |
                     {
477 |  |
                         //_log.warn("Error in @tag: tailing \" sign expected but not found, @tags=" + value);
478 | 0 |
                         _isParsed = true;
479 | 0 |
                         return;
480 |  |
                     }
481 | 38 |
                     setAttribute_Impl( attributeName, attributeValue.toString() );
482 | 38 |
                     attributeName = null;
483 | 38 |
                     attributeValue.delete( 0, attributeValue.length() );
484 |  |
                 }
485 | 24 |
                 _isParsed = true;
486 |  |
             }
487 |  |
         }
488 |  |
489 | 38 |
         private final void resetValue() {
490 | 38 |
             StringBuffer sb = new StringBuffer();
491 |  |
492 | 38 |
             if( _attributeNames != null )
493 |  |
             {
494 | 38 |
                 for( Iterator attributeNames = _attributeNames.iterator(); attributeNames.hasNext();  )
495 |  |
                 {
496 | 56 |
                     String attributeName = ( String ) attributeNames.next();
497 | 56 |
                     String attributeValue = ( String ) _attributes.get( attributeName );
498 |  |
499 | 56 |
                     sb.append( attributeName );
500 | 56 |
                     sb.append( "=\"" );
501 | 56 |
                     sb.append( attributeValue.trim() );
502 | 56 |
                     sb.append( "\" " );
503 |  |
                 }
504 |  |
             }
505 | 38 |
             _value = sb.toString().trim();
506 |  |
         }
507 |  |
     }
508 |  |