View Javadoc
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      private static final long serialVersionUID = 2567894443061173996L;
41  
42      private String name; // plexus: protected
43  
44      private String value; // plexus: protected
45  
46      private Map<String, String> attributes; // plexus: protected
47  
48      final List<Xpp3Dom> childList; // plexus: protected
49  
50      final Map<String, Xpp3Dom> childMap; // plexus: protected
51  
52      private Xpp3Dom parent; // plexus: protected
53  
54      /**
55       * The attribute which identifies merge/append.
56       */
57      public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
58  
59      private static final String CHILDREN_COMBINATION_MERGE = "merge";
60  
61      /**
62       * The attribute append.
63       */
64      public static final String CHILDREN_COMBINATION_APPEND = "append";
65  
66      @SuppressWarnings( "UnusedDeclaration" )
67      private static final String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE; // plexus: public
68  
69      /**
70       * The name of the attribute.
71       */
72      public static final String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
73  
74      /**
75       * The attributes which identifies <code>override</code>.
76       */
77      public static final String SELF_COMBINATION_OVERRIDE = "override";  // plexus: public
78  
79      /**
80       * The attribute which identifies <code>merge</code>
81       */
82      public static final String SELF_COMBINATION_MERGE = "merge";
83  
84      @SuppressWarnings( "UnusedDeclaration" )
85      private static final String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;  // plexus: public
86  
87      private static final String[] EMPTY_STRING_ARRAY = new String[0];
88      private static final Xpp3Dom[] EMPTY_DOM_ARRAY = new Xpp3Dom[0];
89  
90      /**
91       * @param name The name of the instance.
92       */
93      public Xpp3Dom( String name )
94      {
95          this.name = name;
96          childList = new ArrayList<Xpp3Dom>();
97          childMap = new HashMap<String, Xpp3Dom>();
98      }
99  
100     /**
101      * Create instance.
102      * @param source The source.
103      */
104     public Xpp3Dom( Xpp3Dom source )
105     {
106         this( source, source.getName() );
107     }
108 
109     /**
110      * Create instance.
111      * @param src The source Dom.
112      * @param name The name of the Dom.
113      */
114     public Xpp3Dom( @Nonnull Xpp3Dom src, String name )
115     {
116         this.name = name;
117 
118         int size = src.getChildCount();
119         childList = new ArrayList<Xpp3Dom>( size );
120         childMap = new HashMap<String, Xpp3Dom>();
121 
122         setValue( src.getValue() );
123 
124         for ( String attributeName : src.getAttributeNames() )
125         {
126             setAttribute( attributeName, src.getAttribute( attributeName ) );
127         }
128 
129         for ( Xpp3Dom xpp3Dom : src.getChildren() )
130         {
131             addChild( new Xpp3Dom( xpp3Dom ) );
132         }
133     }
134 
135     /**
136      * @return The current name.
137      */
138     public String getName()
139     {
140         return name;
141     }
142 
143     /**
144      * @return The current value.
145      */
146     @Nonnull public String getValue()
147     {
148         return value;
149     }
150 
151     /**
152      * @param value The value to be set.
153      */
154     public void setValue( @Nonnull String value )
155     {
156         this.value = value;
157     }
158 
159 
160     /**
161      * @return The array of attribute names.
162      */
163     public String[] getAttributeNames()
164     {
165         boolean isNothing = attributes == null || attributes.isEmpty();
166         return isNothing ? EMPTY_STRING_ARRAY :  attributes.keySet().toArray( new String[attributes.size()] );
167     }
168 
169 
170     /**
171      * @param nameParameter The name of the attribute.
172      * @return The attribute value.
173      */
174     public String getAttribute( String nameParameter )
175     {
176         return this.attributes != null ? this.attributes.get( nameParameter ) : null;
177     }
178 
179     /**
180      * @param nameParameter The name of the attribute.
181      * @param valueParameter The value of the attribute.
182      */
183     public void setAttribute( @Nonnull String nameParameter, @Nonnull String valueParameter )
184     {
185         if ( valueParameter == null )
186         {
187             throw new NullPointerException( "value can not be null" );
188         }
189         if ( nameParameter == null )
190         {
191             throw new NullPointerException( "name can not be null" );
192         }
193         if ( attributes == null )
194         {
195             attributes = new HashMap<String, String>();
196         }
197 
198         attributes.put( nameParameter, valueParameter );
199     }
200 
201     /**
202      * @param i The index to be selected.
203      * @return The child selected by index.
204      */
205     public Xpp3Dom getChild( int i )
206     {
207         return childList.get( i );
208     }
209 
210     /**
211      * @param nameParameter The name of the child.
212      * @return The child selected by name.
213      */
214     public Xpp3Dom getChild( String nameParameter )
215     {
216         return childMap.get( nameParameter );
217     }
218 
219     /**
220      * @param child The child to be added.
221      */
222     public void addChild( Xpp3Dom child )
223     {
224         child.setParent( this );
225         childList.add( child );
226         childMap.put( child.getName(), child );
227     }
228 
229     /**
230      * @return The array of childs.
231      */
232     public Xpp3Dom[] getChildren()
233     {
234         boolean isNothing = childList == null || childList.isEmpty();
235         return isNothing ? EMPTY_DOM_ARRAY : childList.toArray( new Xpp3Dom[childList.size()] );
236     }
237 
238     private List<Xpp3Dom> getChildrenList()
239     {
240         boolean isNothing = childList == null || childList.isEmpty();
241         return isNothing ? Collections.<Xpp3Dom>emptyList() : childList;
242     }
243 
244     /**
245      * @param nameParameter The name of the child.
246      * @return The array of the Dom.
247      */
248     public Xpp3Dom[] getChildren( String nameParameter )
249     {
250         List<Xpp3Dom> children = getChildrenList( nameParameter );
251         return children.toArray( new Xpp3Dom[children.size()] );
252     }
253 
254     List<Xpp3Dom> getChildrenList( String nameParameter )
255     {
256         if ( childList == null )
257         {
258             return Collections.emptyList();
259         }
260         else
261         {
262             ArrayList<Xpp3Dom> children = new ArrayList<Xpp3Dom>();
263             for ( Xpp3Dom aChildList : childList )
264             {
265                 if ( nameParameter.equals( aChildList.getName() ) )
266                 {
267                     children.add( aChildList );
268                 }
269             }
270             return children;
271         }
272     }
273 
274     /**
275      * @return The number of childs.
276      */
277     public int getChildCount()
278     {
279         if ( childList == null )
280         {
281             return 0;
282         }
283 
284         return childList.size();
285     }
286 
287     /**
288      * @param i The child to be removed.
289      */
290     public void removeChild( int i )
291     {
292         Xpp3Dom child = childList.remove( i );
293         childMap.values().remove( child );
294         child.setParent( null );
295     }
296 
297     /**
298      * @return The current parent.
299      */
300     public Xpp3Dom getParent()
301     {
302         return parent;
303     }
304 
305     /**
306      * @param parent Set the parent.
307      */
308     public void setParent( Xpp3Dom parent )
309     {
310        this.parent = parent;
311     }
312 
313     // Todo: Support writing to serializer (>1.0)
314   //  public void writeToSerializer( String namespace, XmlSerializer serializer )
315     //        throws IOException
316 
317     private static Xpp3Dom merge( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride )
318     {
319         return Xpp3DomUtils.merge( dominant, recessive, childMergeOverride );
320     }
321 
322     /**
323      * @param dominant The dominant part.
324      * @param recessive The recessive part.
325      * @param childMergeOverride true if child merge will take precedence false otherwise.
326      * @return The merged Xpp3Dom.
327      */
328     public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride )
329     {
330         return Xpp3DomUtils.mergeXpp3Dom( dominant, recessive, childMergeOverride );
331     }
332 
333     /**
334      * @param dominant The dominant part.
335      * @param recessive The recessive part.
336      * @return The merged Xpp3Dom.
337      */
338     public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive )
339     {
340         return Xpp3DomUtils.mergeXpp3Dom( dominant, recessive );
341     }
342 
343     /** {@inheritDoc} */
344     public boolean equals( Object obj )
345     {
346         if ( obj == this )
347         {
348             return true;
349         }
350 
351         if ( !( obj instanceof Xpp3Dom ) )
352         {
353             return false;
354         }
355 
356         Xpp3Dom dom = (Xpp3Dom) obj;
357 
358         return !( name == null ? dom.name != null : !name.equals( dom.name ) )
359             && !( value == null ? dom.value != null : !value.equals( dom.value ) )
360             && !( attributes == null ? dom.attributes != null : !attributes.equals( dom.attributes ) )
361             && !( childList == null ? dom.childList != null : !childList.equals( dom.childList ) );
362     }
363 
364     /** {@inheritDoc} */
365     public int hashCode()
366     {
367         int result = 17;
368         result = 37 * result + ( name != null ? name.hashCode() : 0 );
369         result = 37 * result + ( value != null ? value.hashCode() : 0 );
370         result = 37 * result + ( attributes != null ? attributes.hashCode() : 0 );
371         result = 37 * result + ( childList != null ? childList.hashCode() : 0 );
372         return result;
373     }
374 
375     /** {@inheritDoc} */
376     public String toString()
377     {
378         StringWriter writer = new StringWriter();
379         Xpp3DomWriter.write( getPrettyPrintXMLWriter( writer ), this );
380         return writer.toString();
381 
382     }
383 
384     /**
385      * @return Unescaped string.
386      */
387     public String toUnescapedString()
388     {
389         StringWriter writer = new StringWriter();
390         Xpp3DomWriter.write( getPrettyPrintXMLWriter( writer ), this, false );
391         return writer.toString();
392     }
393 
394     private PrettyPrintXMLWriter getPrettyPrintXMLWriter( StringWriter writer )
395     {
396         return new PrettyPrintXMLWriter( writer, "UTF-8", null );
397     }
398 
399     /**
400      * @param str The string to be checked.
401      * @return true if the string is not empty (length &gt; 0) and not <code>null</code>.
402      */
403     public static boolean isNotEmpty( String str )
404     {
405         return str != null && str.length() > 0;
406     }
407 
408     /**
409      * @param str The string to be checked.
410      * @return true if the string is empty or <code>null</code>.
411      */
412     public static boolean isEmpty( String str )
413     {
414         return str == null || str.trim().length() == 0;
415     }
416 
417     /** {@inheritDoc} */
418     public Iterator<Xpp3Dom> iterator()
419     {
420         return getChildrenList().iterator();
421     }
422 }