Coverage Report - org.apache.maven.doxia.sink.SinkUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
SinkUtils
96%
57/59
91%
22/24
4
 
 1  
 package org.apache.maven.doxia.sink;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.util.Enumeration;
 23  
 import java.util.Arrays;
 24  
 
 25  
 import javax.swing.text.AttributeSet;
 26  
 import javax.swing.text.MutableAttributeSet;
 27  
 
 28  
 import org.apache.maven.doxia.markup.Markup;
 29  
 
 30  
 /**
 31  
  * Collection of common utility methods for sinks.
 32  
  *
 33  
  * @author ltheussl
 34  
  * @version $Id: SinkUtils.java 1185112 2011-10-17 11:33:00Z ltheussl $
 35  
  * @since 1.1
 36  
  */
 37  
 public class SinkUtils
 38  
 {
 39  
 
 40  
     /** Do not instantiate. */
 41  
     private SinkUtils()
 42  0
     {
 43  
         // Utility class
 44  0
     }
 45  
 
 46  
     /**
 47  
      * The set of base attributes.
 48  
      */
 49  2
     public static final String[] SINK_BASE_ATTRIBUTES =
 50  
     {
 51  
         SinkEventAttributes.CLASS, SinkEventAttributes.ID, SinkEventAttributes.LANG,
 52  
         SinkEventAttributes.STYLE, SinkEventAttributes.TITLE
 53  
     };
 54  
 
 55  
     /**
 56  
      * The attributes that are supported for the br tag.
 57  
      */
 58  2
     public static final String[] SINK_BR_ATTRIBUTES =
 59  
     {
 60  
         SinkEventAttributes.CLASS, SinkEventAttributes.ID,
 61  
         SinkEventAttributes.STYLE, SinkEventAttributes.TITLE
 62  
     };
 63  
 
 64  
     /**
 65  
      * The attributes that are supported for the <img> tag.
 66  
      */
 67  
     public static final String[] SINK_IMG_ATTRIBUTES;
 68  
 
 69  
     /**
 70  
      * The attributes that are supported for the section tags, like <p>, <h2>, <div>.
 71  
      */
 72  
     public static final String[] SINK_SECTION_ATTRIBUTES;
 73  
 
 74  
     /**
 75  
      * The attributes that are supported for the <div> and <pre> tags.
 76  
      */
 77  
     public static final String[] SINK_VERBATIM_ATTRIBUTES;
 78  
 
 79  
     /**
 80  
      * The attributes that are supported for the <hr> tag.
 81  
      */
 82  
     public static final String[] SINK_HR_ATTRIBUTES;
 83  
 
 84  
     /**
 85  
      * The attributes that are supported for the <a> tag.
 86  
      */
 87  
     public static final String[] SINK_LINK_ATTRIBUTES;
 88  
 
 89  
     /**
 90  
      * The attributes that are supported for the <table> tag.
 91  
      */
 92  
     public static final String[] SINK_TABLE_ATTRIBUTES;
 93  
 
 94  
     /**
 95  
      * The attributes that are supported for the <td> and <th> tags.
 96  
      */
 97  
     public static final String[] SINK_TD_ATTRIBUTES;
 98  
 
 99  
     /**
 100  
      * The attributes that are supported for the <tr> tag.
 101  
      */
 102  
     public static final String[] SINK_TR_ATTRIBUTES;
 103  
 
 104  2
     private static final String[] IMG_ATTRIBUTES =
 105  
     {
 106  
         SinkEventAttributes.ALIGN, SinkEventAttributes.ALT, SinkEventAttributes.BORDER,
 107  
         SinkEventAttributes.HEIGHT, SinkEventAttributes.HSPACE, SinkEventAttributes.ISMAP,
 108  
         SinkEventAttributes.SRC, SinkEventAttributes.USEMAP, SinkEventAttributes.VSPACE,
 109  
         SinkEventAttributes.WIDTH
 110  
     };
 111  
 
 112  2
     private static final String[] HR_ATTRIBUTES =
 113  
     {
 114  
         SinkEventAttributes.ALIGN, SinkEventAttributes.NOSHADE, SinkEventAttributes.SIZE,
 115  
         SinkEventAttributes.WIDTH
 116  
     };
 117  
 
 118  2
     private static final String[] LINK_ATTRIBUTES =
 119  
     {
 120  
         SinkEventAttributes.CHARSET, SinkEventAttributes.COORDS, SinkEventAttributes.HREF,
 121  
         SinkEventAttributes.HREFLANG, SinkEventAttributes.REL, SinkEventAttributes.REV,
 122  
         SinkEventAttributes.SHAPE, SinkEventAttributes.TARGET, SinkEventAttributes.TYPE
 123  
     };
 124  
 
 125  2
     private static final String[] TABLE_ATTRIBUTES =
 126  
     {
 127  
         SinkEventAttributes.ALIGN, SinkEventAttributes.BGCOLOR, SinkEventAttributes.BORDER,
 128  
         SinkEventAttributes.CELLPADDING, SinkEventAttributes.CELLSPACING, SinkEventAttributes.FRAME,
 129  
         SinkEventAttributes.RULES, SinkEventAttributes.SUMMARY, SinkEventAttributes.WIDTH
 130  
     };
 131  
 
 132  2
     private static final String[] TABLE_CELL_ATTRIBUTES =
 133  
     {
 134  
         SinkEventAttributes.ABBRV, SinkEventAttributes.ALIGN, SinkEventAttributes.AXIS,
 135  
         SinkEventAttributes.BGCOLOR, SinkEventAttributes.COLSPAN, SinkEventAttributes.HEADERS,
 136  
         SinkEventAttributes.HEIGHT, SinkEventAttributes.NOWRAP, SinkEventAttributes.ROWSPAN,
 137  
         SinkEventAttributes.SCOPE, SinkEventAttributes.VALIGN, SinkEventAttributes.WIDTH
 138  
     };
 139  
 
 140  
     static
 141  
     {
 142  2
         SINK_IMG_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, IMG_ATTRIBUTES );
 143  2
         SINK_SECTION_ATTRIBUTES =
 144  
                 join( SINK_BASE_ATTRIBUTES, new String[] {SinkEventAttributes.ALIGN} );
 145  2
         SINK_VERBATIM_ATTRIBUTES =
 146  
                 join( SINK_BASE_ATTRIBUTES,
 147  
                 new String[] {SinkEventAttributes.ALIGN, SinkEventAttributes.DECORATION, SinkEventAttributes.WIDTH} );
 148  2
         SINK_HR_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, HR_ATTRIBUTES );
 149  2
         SINK_LINK_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, LINK_ATTRIBUTES );
 150  2
         SINK_TABLE_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, TABLE_ATTRIBUTES );
 151  2
         SINK_TR_ATTRIBUTES =
 152  
                 join( SINK_BASE_ATTRIBUTES,
 153  
                 new String[] {SinkEventAttributes.ALIGN, SinkEventAttributes.BGCOLOR, SinkEventAttributes.VALIGN} );
 154  2
         SINK_TD_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, TABLE_CELL_ATTRIBUTES );
 155  2
     }
 156  
 
 157  
     private static String[] join( String[] a, String[] b )
 158  
     {
 159  16
         String[] temp = new String[a.length + b.length];
 160  16
         System.arraycopy( a, 0, temp, 0, a.length );
 161  16
         System.arraycopy( b, 0, temp, a.length, b.length );
 162  
 
 163  16
         Arrays.sort( temp ); // necessary for binary searches in filterAttributes()
 164  
 
 165  16
         return temp;
 166  
     }
 167  
 
 168  
     /**
 169  
      * Utility method to get an AttributeSet as a String.
 170  
      * The resulting String is in the form ' name1="value1" name2="value2" ...',
 171  
      * ie it can be appended directly to an xml start tag. Attribute values that are itself
 172  
      * AttributeSets are ignored unless the Attribute name is SinkEventAttributeSet.STYLE,
 173  
      * in which case they are written as outlined at
 174  
      * {@link org.apache.maven.doxia.sink.SinkEventAttributes#STYLE SinkEventAttributes.STYLE}.
 175  
      * All other keys and values are written as Strings.
 176  
      *
 177  
      * @param att The AttributeSet. May be null, in which case an empty String is returned.
 178  
      * @return the AttributeSet as a String in a form that can be appended to an xml start tag.
 179  
      */
 180  
     public static String getAttributeString( AttributeSet att )
 181  
     {
 182  232
         if ( att == null )
 183  
         {
 184  100
             return "";
 185  
         }
 186  
 
 187  132
         StringBuilder sb = new StringBuilder();
 188  
 
 189  132
         Enumeration<?> names = att.getAttributeNames();
 190  
 
 191  306
         while ( names.hasMoreElements() )
 192  
         {
 193  174
             Object key = names.nextElement();
 194  174
             Object value = att.getAttribute( key );
 195  
 
 196  174
             if ( value instanceof AttributeSet )
 197  
             {
 198  
                 // Other AttributeSets are ignored
 199  2
                 if ( SinkEventAttributes.STYLE.equals( key.toString() ) )
 200  
                 {
 201  2
                     sb.append( Markup.SPACE ).append( key.toString() ).append( Markup.EQUAL )
 202  
                         .append( Markup.QUOTE ).append( asCssString( (AttributeSet) value ) )
 203  
                         .append( Markup.QUOTE );
 204  
                 }
 205  
             }
 206  
             else
 207  
             {
 208  172
                 sb.append( Markup.SPACE ).append( key.toString() ).append( Markup.EQUAL )
 209  
                     .append( Markup.QUOTE ).append( value.toString() ).append( Markup.QUOTE );
 210  
             }
 211  174
         }
 212  
 
 213  132
         return sb.toString();
 214  
     }
 215  
 
 216  
     private static String asCssString( AttributeSet att )
 217  
     {
 218  2
         StringBuilder sb = new StringBuilder();
 219  
 
 220  2
         Enumeration<?> names = att.getAttributeNames();
 221  
 
 222  6
         while ( names.hasMoreElements() )
 223  
         {
 224  4
             Object key = names.nextElement();
 225  4
             Object value = att.getAttribute( key );
 226  
 
 227  
             // don't go recursive
 228  4
             if ( !( value instanceof AttributeSet ) )
 229  
             {
 230  4
                 sb.append( key.toString() ).append( Markup.COLON )
 231  
                     .append( Markup.SPACE ).append( value.toString() );
 232  
 
 233  4
                 if ( names.hasMoreElements() )
 234  
                 {
 235  2
                     sb.append( Markup.SEMICOLON ).append( Markup.SPACE );
 236  
                 }
 237  
             }
 238  4
         }
 239  
 
 240  2
         return sb.toString();
 241  
     }
 242  
 
 243  
     /**
 244  
      * Filters the given AttributeSet.
 245  
      * Removes all attributes whose name (key) is not contained in the sorted array valids.
 246  
      *
 247  
      * @param attributes The AttributeSet to filter. The String values of Attribute names
 248  
      * are compared to the elements of the valids array.
 249  
      * @param valids a sorted array of attribute names that are to be kept in the resulting AttributeSet.
 250  
      *      <b>Note:</b> a binary search is employed, so the array has to be sorted for correct results.
 251  
      * @return A filtered MutableAttributeSet object. Returns null if the input AttributeSet is null.
 252  
      *      If the array of valids is either null or empty, an empty AttributeSet is returned.
 253  
      */
 254  
     public static MutableAttributeSet filterAttributes( AttributeSet attributes, String[] valids )
 255  
     {
 256  158
         if ( attributes == null )
 257  
         {
 258  80
             return null;
 259  
         }
 260  
 
 261  78
         if ( valids == null || valids.length == 0 )
 262  
         {
 263  4
             return new SinkEventAttributeSet( 0 );
 264  
         }
 265  
 
 266  74
         MutableAttributeSet atts = new SinkEventAttributeSet( attributes.getAttributeCount() );
 267  
 
 268  74
         Enumeration<?> names = attributes.getAttributeNames();
 269  
 
 270  166
         while ( names.hasMoreElements() )
 271  
         {
 272  92
             String key = names.nextElement().toString();
 273  
 
 274  92
             if ( Arrays.binarySearch( valids, key ) >= 0 )
 275  
             {
 276  82
                 atts.addAttribute( key, attributes.getAttribute( key ) );
 277  
             }
 278  92
         }
 279  
 
 280  74
         return atts;
 281  
     }
 282  
 }