Coverage Report - org.apache.maven.shared.utils.xml.Xpp3Dom
 
Classes in this File Line Coverage Branch Coverage Complexity
Xpp3Dom
84%
107/126
66%
78/118
2.571
 
 1  
 package org.apache.maven.shared.utils.xml;
 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.io.StringWriter;
 23  
 import java.util.ArrayList;
 24  
 import java.util.Collections;
 25  
 import java.util.HashMap;
 26  
 import java.util.Iterator;
 27  
 import java.util.List;
 28  
 import java.util.Map;
 29  
 
 30  
 import javax.annotation.Nonnull;
 31  
 
 32  
 /**
 33  
  * A reimplementation of Plexus Xpp3Dom based on the public interface of Plexus Xpp3Dom.
 34  
  *
 35  
  * @author Kristian Rosenvold
 36  
  */
 37  
 public class Xpp3Dom
 38  
     implements Iterable<Xpp3Dom>
 39  
 {
 40  
     @SuppressWarnings( "UnusedDeclaration" )
 41  
     private static final long serialVersionUID = 2567894443061173996L;
 42  
 
 43  
     private String name; // plexus: protected
 44  
 
 45  
     private String value; // plexus: protected
 46  
 
 47  
     private Map<String, String> attributes; // plexus: protected
 48  
 
 49  
     private final List<Xpp3Dom> childList; // plexus: protected
 50  
 
 51  
     private final Map<String, Xpp3Dom> childMap; // plexus: protected
 52  
 
 53  
     private Xpp3Dom parent; // plexus: protected
 54  
 
 55  
     public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
 56  
 
 57  
     private static final String CHILDREN_COMBINATION_MERGE = "merge";
 58  
 
 59  
     public static final String CHILDREN_COMBINATION_APPEND = "append";
 60  
 
 61  
     @SuppressWarnings("UnusedDeclaration")
 62  
     private static final String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE; // plexus: public
 63  
 
 64  
     public static final String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
 65  
 
 66  
     public static final String SELF_COMBINATION_OVERRIDE = "override";  // plexus: public
 67  
 
 68  
     public static final String SELF_COMBINATION_MERGE = "merge";
 69  
 
 70  
     @SuppressWarnings("UnusedDeclaration")
 71  
     private static final String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;  // plexus: public
 72  
 
 73  1
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 74  1
     private static final Xpp3Dom[] EMPTY_DOM_ARRAY = new Xpp3Dom[0];
 75  
 
 76  
     public Xpp3Dom( String name )
 77  96
     {
 78  96
         this.name = name;
 79  96
         childList = new ArrayList<Xpp3Dom>();
 80  96
         childMap = new HashMap<String, Xpp3Dom>();
 81  96
     }
 82  
 
 83  
     public Xpp3Dom( Xpp3Dom source)
 84  
     {
 85  5
         this( source, source.getName() );
 86  5
     }
 87  
 
 88  
     public Xpp3Dom( @Nonnull Xpp3Dom src, String name )
 89  5
     {
 90  5
         this.name = name;
 91  
 
 92  5
         int size = src.getChildCount();
 93  5
         childList = new ArrayList<Xpp3Dom>( size );
 94  5
         childMap = new HashMap<String, Xpp3Dom>();
 95  
 
 96  5
         setValue( src.getValue() );
 97  
 
 98  5
         for ( String attributeName : src.getAttributeNames() )
 99  
         {
 100  0
             setAttribute( attributeName, src.getAttribute( attributeName ) );
 101  
         }
 102  
 
 103  5
         for ( Xpp3Dom xpp3Dom : src.getChildren() )
 104  
         {
 105  0
             addChild( new Xpp3Dom( xpp3Dom ) );
 106  
         }
 107  5
     }
 108  
 
 109  
     public String getName()
 110  
     {
 111  113
         return name;
 112  
     }
 113  
 
 114  
     public @Nonnull String getValue()
 115  
     {
 116  79
         return value;
 117  
     }
 118  
 
 119  
     public void setValue( @Nonnull String value )
 120  
     {
 121  73
         this.value = value;
 122  73
     }
 123  
 
 124  
 
 125  
     public String[] getAttributeNames()
 126  
     {
 127  39
         boolean isNothing = attributes == null || attributes.isEmpty();
 128  39
         return isNothing ? EMPTY_STRING_ARRAY :  attributes.keySet().toArray( new String[attributes.size()] );
 129  
     }
 130  
 
 131  
 
 132  
     public String getAttribute( String name )
 133  
     {
 134  41
         return attributes != null ? attributes.get( name ) : null;
 135  
     }
 136  
 
 137  
     @SuppressWarnings( "ConstantConditions" )
 138  
     public void setAttribute( @Nonnull String name, @Nonnull String value )
 139  
     {
 140  25
         if ( value == null )
 141  
         {
 142  1
             throw new NullPointerException( "value can not be null" );
 143  
         }
 144  24
         if ( name == null )
 145  
         {
 146  1
             throw new NullPointerException( "name can not be null" );
 147  
         }
 148  23
         if ( attributes == null )
 149  
         {
 150  19
             attributes = new HashMap<String, String>();
 151  
         }
 152  
 
 153  23
         attributes.put( name, value );
 154  23
     }
 155  
 
 156  
     public Xpp3Dom getChild( int i )
 157  
     {
 158  9
         return childList.get( i );
 159  
     }
 160  
 
 161  
     public Xpp3Dom getChild( String name )
 162  
     {
 163  17
         return childMap.get( name );
 164  
     }
 165  
 
 166  
     public void addChild( Xpp3Dom child )
 167  
     {
 168  69
         child.setParent( this );
 169  69
         childList.add( child );
 170  69
         childMap.put( child.getName(), child );
 171  69
     }
 172  
 
 173  
     public Xpp3Dom[] getChildren()
 174  
     {
 175  17
         boolean isNothing = childList == null || childList.isEmpty();
 176  17
         return isNothing ? EMPTY_DOM_ARRAY : childList.toArray( new Xpp3Dom[childList.size()] );
 177  
     }
 178  
 
 179  
     private List<Xpp3Dom> getChildrenList()
 180  
     {
 181  13
         boolean isNothing = childList == null || childList.isEmpty();
 182  13
         return isNothing ? Collections.<Xpp3Dom>emptyList() : childList;
 183  
     }
 184  
 
 185  
     public Xpp3Dom[] getChildren( String name )
 186  
     {
 187  2
         List<Xpp3Dom> children = getChildrenList( name );
 188  2
         return children.toArray( new Xpp3Dom[children.size()] );
 189  
     }
 190  
 
 191  
     private List<Xpp3Dom> getChildrenList( String name )
 192  
     {
 193  13
         if ( childList == null )
 194  
         {
 195  0
             return Collections.emptyList();
 196  
         }
 197  
         else
 198  
         {
 199  13
             ArrayList<Xpp3Dom> children = new ArrayList<Xpp3Dom>();
 200  13
             for ( Xpp3Dom aChildList : childList )
 201  
             {
 202  16
                 if ( name.equals( aChildList.getName() ) )
 203  
                 {
 204  15
                     children.add( aChildList );
 205  
                 }
 206  
             }
 207  13
             return children;
 208  
         }
 209  
     }
 210  
 
 211  
     public int getChildCount()
 212  
     {
 213  113
         if ( childList == null )
 214  
         {
 215  0
             return 0;
 216  
         }
 217  
 
 218  113
         return childList.size();
 219  
     }
 220  
 
 221  
     public void removeChild( int i )
 222  
     {
 223  0
         Xpp3Dom child = childList.remove( i );
 224  0
         childMap.values().remove( child );
 225  0
         child.setParent( null );
 226  0
     }
 227  
 
 228  
     public Xpp3Dom getParent()
 229  
     {
 230  0
         return parent;
 231  
     }
 232  
 
 233  
     public void setParent( Xpp3Dom parent )
 234  
     {
 235  69
        this.parent = parent;
 236  69
     }
 237  
 
 238  
     // Todo: Support writing to serializer (>1.0)
 239  
   //  public void writeToSerializer( String namespace, XmlSerializer serializer )
 240  
     //        throws IOException
 241  
 
 242  
     private static Xpp3Dom merge( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride )
 243  
     {
 244  23
         if ( recessive == null || isCombineSelfOverride( dominant ) )
 245  
         {
 246  1
             return dominant;
 247  
         }
 248  
 
 249  22
         if ( isEmpty( dominant.getValue() ) )
 250  
         {
 251  17
             dominant.setValue( recessive.getValue() );
 252  
         }
 253  
 
 254  24
         for ( String attr : recessive.getAttributeNames() )
 255  
         {
 256  2
             if ( isEmpty( dominant.getAttribute( attr ) ) )
 257  
             {
 258  2
                 dominant.setAttribute( attr, recessive.getAttribute( attr ) );
 259  
             }
 260  
         }
 261  
 
 262  22
         if ( recessive.getChildCount() > 0 )
 263  
         {
 264  13
             boolean mergeChildren = isMergeChildren( dominant, childMergeOverride );
 265  
 
 266  13
             if ( mergeChildren )
 267  
             {
 268  11
                 Map<String, Iterator<Xpp3Dom>> commonChildren = getCommonChildren( dominant, recessive );
 269  11
                 for ( Xpp3Dom recessiveChild : recessive )
 270  
                 {
 271  14
                     Iterator<Xpp3Dom> it = commonChildren.get( recessiveChild.getName() );
 272  14
                     if ( it == null )
 273  
                     {
 274  1
                         dominant.addChild( new Xpp3Dom( recessiveChild ) );
 275  
                     }
 276  13
                     else if ( it.hasNext() )
 277  
                     {
 278  12
                         Xpp3Dom dominantChild = it.next();
 279  12
                         merge( dominantChild, recessiveChild, childMergeOverride );
 280  
                     }
 281  14
                 }
 282  11
             }
 283  
             else
 284  
             {
 285  2
                 Xpp3Dom[] dominantChildren = dominant.getChildren();
 286  2
                 dominant.childList.clear();
 287  2
                 for ( Xpp3Dom child : recessive )
 288  
                 {
 289  4
                     dominant.addChild( new Xpp3Dom( child ) );
 290  
                 }
 291  
 
 292  4
                 for ( Xpp3Dom aDominantChildren : dominantChildren )
 293  
                 {
 294  2
                     dominant.addChild( aDominantChildren );
 295  
                 }
 296  
             }
 297  
         }
 298  22
         return dominant;
 299  
     }
 300  
 
 301  
     private static Map<String, Iterator<Xpp3Dom>> getCommonChildren( Xpp3Dom dominant, Xpp3Dom recessive )
 302  
     {
 303  11
         Map<String, Iterator<Xpp3Dom>> commonChildren = new HashMap<String, Iterator<Xpp3Dom>>();
 304  
 
 305  11
         for ( String childName : recessive.childMap.keySet() )
 306  
         {
 307  11
             List<Xpp3Dom> dominantChildren = dominant.getChildrenList( childName );
 308  11
             if ( dominantChildren.size() > 0 )
 309  
             {
 310  10
                 commonChildren.put( childName, dominantChildren.iterator() );
 311  
             }
 312  11
         }
 313  11
         return commonChildren;
 314  
     }
 315  
 
 316  
     private static boolean isMergeChildren( Xpp3Dom dominant, Boolean override )
 317  
     {
 318  13
         return override != null ? override : !isMergeChildren( dominant );
 319  
     }
 320  
 
 321  
     private static boolean isMergeChildren( Xpp3Dom dominant )
 322  
     {
 323  12
         return CHILDREN_COMBINATION_APPEND.equals( dominant.getAttribute( CHILDREN_COMBINATION_MODE_ATTRIBUTE ) );
 324  
     }
 325  
 
 326  
     private static boolean isCombineSelfOverride( Xpp3Dom xpp3Dom )
 327  
     {
 328  23
         String selfMergeMode = xpp3Dom.getAttribute( SELF_COMBINATION_MODE_ATTRIBUTE );
 329  23
         return SELF_COMBINATION_OVERRIDE.equals( selfMergeMode );
 330  
     }
 331  
 
 332  
     public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride )
 333  
     {
 334  1
         return dominant != null ? merge( dominant, recessive, childMergeOverride ) : recessive;
 335  
     }
 336  
 
 337  
     public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive )
 338  
     {
 339  10
         return dominant != null ? merge( dominant, recessive, null ) : recessive;
 340  
     }
 341  
 
 342  
     public boolean equals( Object obj )
 343  
     {
 344  5
         if ( obj == this )
 345  
         {
 346  1
             return true;
 347  
         }
 348  
 
 349  4
         if ( !( obj instanceof Xpp3Dom ) )
 350  
         {
 351  1
             return false;
 352  
         }
 353  
 
 354  3
         Xpp3Dom dom = (Xpp3Dom) obj;
 355  
 
 356  3
         return !( name == null ? dom.name != null : !name.equals( dom.name ) )
 357  
             && !( value == null ? dom.value != null : !value.equals( dom.value ) )
 358  
             && !( attributes == null ? dom.attributes != null : !attributes.equals( dom.attributes ) )
 359  
             && !( childList == null ? dom.childList != null : !childList.equals( dom.childList ) );
 360  
     }
 361  
 
 362  
     public int hashCode()
 363  
     {
 364  0
         int result = 17;
 365  0
         result = 37 * result + ( name != null ? name.hashCode() : 0 );
 366  0
         result = 37 * result + ( value != null ? value.hashCode() : 0 );
 367  0
         result = 37 * result + ( attributes != null ? attributes.hashCode() : 0 );
 368  0
         result = 37 * result + ( childList != null ? childList.hashCode() : 0 );
 369  0
         return result;
 370  
     }
 371  
 
 372  
     public String toString()
 373  
     {
 374  1
         StringWriter writer = new StringWriter();
 375  1
         Xpp3DomWriter.write( getPrettyPrintXMLWriter( writer ), this );
 376  1
         return writer.toString();
 377  
 
 378  
     }
 379  
 
 380  
     public String toUnescapedString()
 381  
     {
 382  0
         StringWriter writer = new StringWriter();
 383  0
         Xpp3DomWriter.write( getPrettyPrintXMLWriter( writer ), this, false );
 384  0
         return writer.toString();
 385  
     }
 386  
 
 387  
     private PrettyPrintXMLWriter getPrettyPrintXMLWriter( StringWriter writer )
 388  
     {
 389  1
         return new PrettyPrintXMLWriter( writer, "UTF-8", null );
 390  
     }
 391  
 
 392  
     public static boolean isNotEmpty( String str )
 393  
     {
 394  0
         return str != null && str.length() > 0;
 395  
     }
 396  
 
 397  
     public static boolean isEmpty( String str )
 398  
     {
 399  24
         return str == null || str.trim().length() == 0;
 400  
     }
 401  
 
 402  
     public Iterator<Xpp3Dom> iterator()
 403  
     {
 404  13
         return getChildrenList().iterator();
 405  
     }
 406  
 }