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.plugins.shade.resource;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.StringReader;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.jar.JarEntry;
27  import java.util.jar.JarOutputStream;
28  
29  import org.apache.maven.plugins.shade.relocation.Relocator;
30  import org.jdom2.Attribute;
31  import org.jdom2.Content;
32  import org.jdom2.Document;
33  import org.jdom2.Element;
34  import org.jdom2.JDOMException;
35  import org.jdom2.input.SAXBuilder;
36  import org.jdom2.output.Format;
37  import org.jdom2.output.XMLOutputter;
38  import org.xml.sax.EntityResolver;
39  import org.xml.sax.InputSource;
40  import org.xml.sax.SAXException;
41  
42  /**
43   * Appends multiple occurrences of some XML file.
44   */
45  public class XmlAppendingTransformer extends AbstractCompatibilityTransformer {
46      public static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
47  
48      boolean ignoreDtd = true;
49  
50      String resource;
51  
52      Document doc;
53  
54      private long time = Long.MIN_VALUE;
55  
56      @Override
57      public boolean canTransformResource(String r) {
58          return resource != null && resource.equalsIgnoreCase(r);
59      }
60  
61      @Override
62      public void processResource(String resource, InputStream is, List<Relocator> relocators, long time)
63              throws IOException {
64          Document r;
65          try {
66              SAXBuilder builder = new SAXBuilder(false);
67              builder.setExpandEntities(false);
68              if (ignoreDtd) {
69                  builder.setEntityResolver(new EntityResolver() {
70                      @Override
71                      public InputSource resolveEntity(String publicId, String systemId)
72                              throws SAXException, IOException {
73                          return new InputSource(new StringReader(""));
74                      }
75                  });
76              }
77              r = builder.build(is);
78          } catch (JDOMException e) {
79              throw new RuntimeException("Error processing resource " + resource + ": " + e.getMessage(), e);
80          }
81  
82          if (doc == null) {
83              doc = r;
84          } else {
85              Element root = r.getRootElement();
86  
87              for (Iterator<Attribute> itr = root.getAttributes().iterator(); itr.hasNext(); ) {
88                  Attribute a = itr.next();
89                  itr.remove();
90  
91                  Element mergedEl = doc.getRootElement();
92                  Attribute mergedAtt = mergedEl.getAttribute(a.getName(), a.getNamespace());
93                  if (mergedAtt == null) {
94                      mergedEl.setAttribute(a);
95                  }
96              }
97  
98              for (Iterator<Element> itr = root.getChildren().iterator(); itr.hasNext(); ) {
99                  Content n = itr.next();
100                 itr.remove();
101 
102                 doc.getRootElement().addContent(n);
103             }
104         }
105 
106         if (time > this.time) {
107             this.time = time;
108         }
109     }
110 
111     @Override
112     public boolean hasTransformedResource() {
113         return doc != null;
114     }
115 
116     @Override
117     public void modifyOutputStream(JarOutputStream jos) throws IOException {
118         JarEntry jarEntry = new JarEntry(resource);
119         jarEntry.setTime(time);
120         jos.putNextEntry(jarEntry);
121 
122         new XMLOutputter(Format.getPrettyFormat()).output(doc, jos);
123 
124         doc = null;
125     }
126 }