View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.shared.utils.xml;
20  
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  /**
27   *
28   */
29  public class Xpp3DomUtils {
30      /**
31       * @param dominant {@link Xpp3Dom}
32       * @param recessive {@link Xpp3Dom}
33       * @param childMergeOverride true/false.
34       * @return Merged dom.
35       */
36      public static Xpp3Dom mergeXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride) {
37          return dominant != null ? merge(dominant, recessive, childMergeOverride) : recessive;
38      }
39  
40      /**
41       * @param dominant {@link Xpp3Dom}
42       * @param recessive {@link Xpp3Dom}
43       * @return Merged dom.
44       */
45      public static Xpp3Dom mergeXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive) {
46          return dominant != null ? merge(dominant, recessive, null) : recessive;
47      }
48  
49      /**
50       * @param dominant {@link Xpp3Dom}
51       * @param recessive {@link Xpp3Dom}
52       * @param childMergeOverride true/false.
53       * @return Merged dom.
54       */
55      public static Xpp3Dom merge(Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride) {
56          if (recessive == null || isCombineSelfOverride(dominant)) {
57              return dominant;
58          }
59  
60          if (isEmpty(dominant.getValue())) {
61              dominant.setValue(recessive.getValue());
62          }
63  
64          for (String attr : recessive.getAttributeNames()) {
65              if (isEmpty(dominant.getAttribute(attr))) {
66                  dominant.setAttribute(attr, recessive.getAttribute(attr));
67              }
68          }
69  
70          if (recessive.getChildCount() > 0) {
71              boolean mergeChildren = isMergeChildren(dominant, childMergeOverride);
72  
73              if (mergeChildren) {
74                  Map<String, Iterator<Xpp3Dom>> commonChildren = getCommonChildren(dominant, recessive);
75                  for (Xpp3Dom recessiveChild : recessive) {
76                      Iterator<Xpp3Dom> it = commonChildren.get(recessiveChild.getName());
77                      if (it == null) {
78                          dominant.addChild(new Xpp3Dom(recessiveChild));
79                      } else if (it.hasNext()) {
80                          Xpp3Dom dominantChild = it.next();
81                          merge(dominantChild, recessiveChild, childMergeOverride);
82                      }
83                  }
84              } else {
85                  Xpp3Dom[] dominantChildren = dominant.getChildren();
86                  dominant.childList.clear();
87                  for (Xpp3Dom child : recessive) {
88                      dominant.addChild(new Xpp3Dom(child));
89                  }
90  
91                  for (Xpp3Dom aDominantChildren : dominantChildren) {
92                      dominant.addChild(aDominantChildren);
93                  }
94              }
95          }
96          return dominant;
97      }
98  
99      private static Map<String, Iterator<Xpp3Dom>> getCommonChildren(Xpp3Dom dominant, Xpp3Dom recessive) {
100         Map<String, Iterator<Xpp3Dom>> commonChildren = new HashMap<String, Iterator<Xpp3Dom>>();
101 
102         for (String childName : recessive.childMap.keySet()) {
103             List<Xpp3Dom> dominantChildren = dominant.getChildrenList(childName);
104             if (dominantChildren.size() > 0) {
105                 commonChildren.put(childName, dominantChildren.iterator());
106             }
107         }
108         return commonChildren;
109     }
110 
111     private static boolean isCombineSelfOverride(Xpp3Dom xpp3Dom) {
112         String selfMergeMode = xpp3Dom.getAttribute(Xpp3Dom.SELF_COMBINATION_MODE_ATTRIBUTE);
113         return Xpp3Dom.SELF_COMBINATION_OVERRIDE.equals(selfMergeMode);
114     }
115 
116     private static boolean isMergeChildren(Xpp3Dom dominant, Boolean override) {
117         return override != null ? override : !isMergeChildren(dominant);
118     }
119 
120     private static boolean isMergeChildren(Xpp3Dom dominant) {
121         return Xpp3Dom.CHILDREN_COMBINATION_APPEND.equals(
122                 dominant.getAttribute(Xpp3Dom.CHILDREN_COMBINATION_MODE_ATTRIBUTE));
123     }
124 
125     /**
126      * @deprecated use <code>str == null || String.isBlank(str)</code> (Java 11+)
127      *             or <code>org.apache.commons.lang3.StringUtils.isBlank(str)</code>
128      * @param str the string to be checked
129      * @return <code>true</code> if the string is null, empty, or whitespace only; <code>false</code> otherwise
130      */
131     @Deprecated
132     public static boolean isEmpty(String str) {
133         return str == null || str.trim().length() == 0;
134     }
135 }