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.cling.invoker.mvnup.goals;
20  
21  import eu.maveniverse.domtrip.Document;
22  import eu.maveniverse.domtrip.Editor;
23  import eu.maveniverse.domtrip.Element;
24  import eu.maveniverse.domtrip.maven.PomEditor;
25  
26  import static eu.maveniverse.domtrip.maven.MavenPomElements.Elements.ARTIFACT_ID;
27  import static eu.maveniverse.domtrip.maven.MavenPomElements.Elements.DEPENDENCY;
28  import static eu.maveniverse.domtrip.maven.MavenPomElements.Elements.GROUP_ID;
29  import static eu.maveniverse.domtrip.maven.MavenPomElements.Elements.PLUGIN;
30  import static eu.maveniverse.domtrip.maven.MavenPomElements.Elements.VERSION;
31  
32  /**
33   * Utility class for XML operations on Maven POM files.
34   *
35   * <p>This class provides convenience methods that delegate to:
36   * <ul>
37   * <li>{@link eu.maveniverse.domtrip.maven.PomEditor} - DomTrip's PomEditor</li>
38   * <li>{@link eu.maveniverse.domtrip.Element} - DomTrip's Element API</li>
39   * </ul>
40   *
41   * <p>These methods are kept for convenience and backward compatibility.
42   * For more advanced operations, consider using ExtendedPomEditor or DomTrip directly.
43   *
44   * <h2>Using DomTrip Directly</h2>
45   * <p>Many operations can be performed directly using DomTrip's Element API:
46   * <pre>{@code
47   * // Find child element
48   * Element child = parent.child("version").orElse(null);
49   *
50   * // Check if child exists
51   * boolean hasVersion = parent.child("version").isPresent();
52   *
53   * // Get child text content
54   * String version = parent.child("version")
55   *     .map(Element::textContent)
56   *     .orElse(null);
57   *
58   * // Get trimmed text content
59   * String trimmedVersion = parent.child("version")
60   *     .map(Element::textContentTrimmed)
61   *     .orElse(null);
62   *
63   * // Set text content (fluent API)
64   * element.textContent("4.0.0");
65   * }</pre>
66   *
67   * <h2>When to Use DomUtils</h2>
68   * <p>Use DomUtils methods when you need:
69   * <ul>
70   * <li>Maven-specific element ordering (insertNewElement, insertContentElement)</li>
71   * <li>High-level helpers (addGAVElements, createDependency, createPlugin)</li>
72   * <li>Null-safe operations (updateElementContent, removeElement)</li>
73   * <li>Update-or-create patterns (updateOrCreateChildElement)</li>
74   * </ul>
75   *
76   * @see eu.maveniverse.domtrip.Element
77   * @see eu.maveniverse.domtrip.Editor
78   * @see eu.maveniverse.domtrip.maven.PomEditor
79   */
80  public class DomUtils {
81  
82      private DomUtils() {
83          // Utility class
84      }
85  
86      /**
87       * Inserts a new child element to the given parent element with proper Maven POM ordering.
88       *
89       * @param name the name of the new element
90       * @param parent the parent element
91       * @return the new element
92       *
93       */
94      public static Element insertNewElement(String name, Element parent) {
95          PomEditor editor = new PomEditor(parent.document());
96          return editor.insertMavenElement(parent, name);
97      }
98  
99      /**
100      * Inserts a new content element with the given name and text content.
101      *
102      * @param parent the parent element
103      * @param name the name of the new element
104      * @param content the text content
105      * @return the new element
106      *
107      */
108     public static Element insertContentElement(Element parent, String name, String content) {
109         PomEditor editor = new PomEditor(parent.document());
110         return editor.insertMavenElement(parent, name, content);
111     }
112 
113     /**
114      * Finds a child element by name under the specified parent.
115      *
116      * @param parent the parent element
117      * @param name the child element name to find
118      * @return the child element if found, null otherwise
119      *
120      */
121     public static Element findChildElement(Element parent, String name) {
122         return parent.child(name).orElse(null);
123     }
124 
125     /**
126      * Serializes a domtrip Document to XML string with preserved formatting.
127      *
128      * @param document the domtrip Document
129      * @return the XML string with preserved formatting
130      *
131      */
132     public static String toXml(Document document) {
133         Editor editor = new Editor(document);
134         return editor.toXml();
135     }
136 
137     /**
138      * Removes an element from its parent.
139      *
140      * @param element the element to remove
141      *
142      */
143     public static void removeElement(Element element) {
144         Editor editor = new Editor(element.document());
145         editor.removeElement(element);
146     }
147 
148     /**
149      * Convenience method to add GAV (groupId, artifactId, version) elements to a parent.
150      *
151      * @param parent the parent element (e.g., dependency or plugin)
152      * @param groupId the groupId value
153      * @param artifactId the artifactId value
154      * @param version the version value (can be null to skip)
155      *
156      */
157     public static void addGAVElements(Element parent, String groupId, String artifactId, String version) {
158         insertContentElement(parent, GROUP_ID, groupId);
159         insertContentElement(parent, ARTIFACT_ID, artifactId);
160         if (version != null && !version.isEmpty()) {
161             insertContentElement(parent, VERSION, version);
162         }
163     }
164 
165     /**
166      * Convenience method to create a dependency element with GAV.
167      *
168      * @param dependenciesElement the dependencies parent element
169      * @param groupId the groupId value
170      * @param artifactId the artifactId value
171      * @param version the version value (can be null)
172      * @return the created dependency element
173      *
174      */
175     public static Element createDependency(
176             Element dependenciesElement, String groupId, String artifactId, String version) {
177         Element dependency = insertNewElement(DEPENDENCY, dependenciesElement);
178         addGAVElements(dependency, groupId, artifactId, version);
179         return dependency;
180     }
181 
182     /**
183      * Convenience method to create a plugin element with GAV.
184      *
185      * @param pluginsElement the plugins parent element
186      * @param groupId the groupId value
187      * @param artifactId the artifactId value
188      * @param version the version value (can be null)
189      * @return the created plugin element
190      *
191      */
192     public static Element createPlugin(Element pluginsElement, String groupId, String artifactId, String version) {
193         Element plugin = insertNewElement(PLUGIN, pluginsElement);
194         addGAVElements(plugin, groupId, artifactId, version);
195         return plugin;
196     }
197 
198     /**
199      * Updates or creates a child element with the given content.
200      *
201      * @param parent the parent element
202      * @param childName the child element name
203      * @param content the content to set
204      * @return the updated or created element
205      *
206      */
207     public static Element updateOrCreateChildElement(Element parent, String childName, String content) {
208         PomEditor editor = new PomEditor(parent.document());
209         return editor.updateOrCreateChildElement(parent, childName, content);
210     }
211 }