1 package com.simpligility.maven.plugins.android.resource;
2
3 import org.apache.maven.plugins.shade.relocation.Relocator;
4 import org.apache.maven.plugins.shade.resource.ResourceTransformer;
5 import org.jdom2.Attribute;
6 import org.jdom2.Content;
7 import org.jdom2.Document;
8 import org.jdom2.Element;
9 import org.jdom2.JDOMException;
10 import org.jdom2.input.SAXBuilder;
11 import org.jdom2.output.Format;
12 import org.jdom2.output.XMLOutputter;
13 import org.jdom2.xpath.XPath;
14 import org.xml.sax.EntityResolver;
15 import org.xml.sax.InputSource;
16 import org.xml.sax.SAXException;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.StringReader;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.jar.JarEntry;
24 import java.util.jar.JarOutputStream;
25
26 import static java.lang.String.format;
27
28
29
30
31
32 public class XpathAppendingTransformer implements ResourceTransformer
33 {
34 public static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
35
36 boolean ignoreDtd = true;
37
38 String resource;
39
40
41 String[] elements;
42
43 Document doc;
44
45 public boolean canTransformResource( String r )
46 {
47 if ( resource != null && resource.equalsIgnoreCase( r ) )
48 {
49 return true;
50 }
51
52 return false;
53 }
54
55 public void processResource( String resource, InputStream is, List<Relocator> relocators )
56 throws IOException
57 {
58 Document r;
59 try
60 {
61 SAXBuilder builder = new SAXBuilder( false );
62 builder.setExpandEntities( false );
63 if ( ignoreDtd )
64 {
65 builder.setEntityResolver( new EntityResolver()
66 {
67 public InputSource resolveEntity( String publicId, String systemId )
68 throws SAXException, IOException
69 {
70 return new InputSource( new StringReader( "" ) );
71 }
72 } );
73 }
74 r = builder.build( is );
75 }
76 catch ( JDOMException e )
77 {
78 throw new RuntimeException( "Error processing resource " + resource + ": " + e.getMessage(), e );
79 }
80
81 if ( doc == null )
82 {
83 doc = r;
84 }
85 else if ( elements == null || elements.length == 0 )
86 {
87 appendElement( r.getRootElement(), doc.getRootElement() );
88 }
89 else
90 {
91 for ( String xpath : elements )
92 {
93 try
94 {
95 XPath path = XPath.newInstance( xpath );
96 Object source = path.selectSingleNode( r.getRootElement() );
97 if ( !( source instanceof Element ) )
98 {
99 throw new IOException( format( "xpath result must be element. %s returned %s",
100 xpath, source ) );
101 }
102 Object target = path.selectSingleNode( doc.getRootElement() );
103 if ( !( target instanceof Element ) )
104 {
105 throw new IOException( format( "xpath result must be element. %s returned %s",
106 xpath, target ) );
107 }
108 appendElement( (Element) source, (Element) target );
109 }
110 catch ( JDOMException e )
111 {
112 throw new IOException( e );
113 }
114 }
115 }
116 }
117
118 @SuppressWarnings( "unchecked" )
119 private void appendElement( Element source, Element target )
120 {
121 for ( Iterator<Attribute> itr = source.getAttributes().iterator(); itr.hasNext(); )
122 {
123 Attribute a = itr.next();
124 itr.remove();
125
126 Attribute mergedAtt = target.getAttribute( a.getName(), a.getNamespace() );
127 if ( mergedAtt == null )
128 {
129 target.setAttribute( a );
130 }
131 }
132
133 for ( Iterator<Element> itr = source.getChildren().iterator(); itr.hasNext(); )
134 {
135 Content n = itr.next();
136 itr.remove();
137
138 target.addContent( n );
139 }
140 }
141
142 public boolean hasTransformedResource()
143 {
144 return doc != null;
145 }
146
147 public void modifyOutputStream( JarOutputStream jos )
148 throws IOException
149 {
150 jos.putNextEntry( new JarEntry( resource ) );
151
152 new XMLOutputter( Format.getPrettyFormat() ).output( doc, jos );
153
154 doc = null;
155 }
156 }