1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  package com.puppycrawl.tools.checkstyle.site;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.Reader;
25  import java.io.StringReader;
26  import java.io.StringWriter;
27  import java.util.HashMap;
28  import java.util.Locale;
29  import java.util.Map;
30  
31  import javax.swing.text.html.HTML.Attribute;
32  
33  import org.apache.maven.doxia.macro.MacroExecutionException;
34  import org.apache.maven.doxia.macro.MacroRequest;
35  import org.apache.maven.doxia.macro.manager.MacroNotFoundException;
36  import org.apache.maven.doxia.module.xdoc.XdocParser;
37  import org.apache.maven.doxia.parser.ParseException;
38  import org.apache.maven.doxia.parser.Parser;
39  import org.apache.maven.doxia.sink.Sink;
40  import org.codehaus.plexus.component.annotations.Component;
41  import org.codehaus.plexus.util.IOUtil;
42  import org.codehaus.plexus.util.xml.pull.XmlPullParser;
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  @Component(role = Parser.class, hint = "xdocs-template")
57  public class XdocsTemplateParser extends XdocParser {
58  
59      
60      public static final String TEMP_DIR = System.getProperty("java.io.tmpdir");
61  
62      
63      private final Map<String, Object> macroParameters = new HashMap<>();
64  
65      
66      private String sourceContent;
67  
68      
69      private String macroName;
70  
71      @Override
72      public void parse(Reader source, Sink sink, String reference) throws ParseException {
73          try (StringWriter contentWriter = new StringWriter()) {
74              IOUtil.copy(source, contentWriter);
75              sourceContent = contentWriter.toString();
76              super.parse(new StringReader(sourceContent), sink, reference);
77          }
78          catch (IOException ioException) {
79              throw new ParseException("Error reading the input source", ioException);
80          }
81          finally {
82              sourceContent = null;
83          }
84      }
85  
86      @Override
87      protected void handleStartTag(XmlPullParser parser, Sink sink) throws MacroExecutionException {
88          final String tagName = parser.getName();
89          if (tagName.equals(DOCUMENT_TAG.toString())) {
90              sink.body();
91              sink.rawText(parser.getText());
92          }
93          else if (tagName.equals(MACRO_TAG.toString()) && !isSecondParsing()) {
94              processMacroStart(parser);
95              setIgnorableWhitespace(true);
96          }
97          else if (tagName.equals(PARAM.toString()) && !isSecondParsing()) {
98              processParamStart(parser, sink);
99          }
100         else {
101             sink.rawText(parser.getText());
102         }
103     }
104 
105     @Override
106     protected void handleEndTag(XmlPullParser parser, Sink sink) throws MacroExecutionException {
107         final String tagName = parser.getName();
108         if (!"hr".equalsIgnoreCase(tagName)) {
109             if (tagName.equals(DOCUMENT_TAG.toString())) {
110                 sink.rawText(parser.getText());
111                 sink.body_();
112             }
113             else if (macroName != null
114                     && tagName.equals(MACRO_TAG.toString())
115                     && !macroName.isEmpty()
116                     && !isSecondParsing()) {
117                 processMacroEnd(sink);
118                 setIgnorableWhitespace(false);
119             }
120             else if (!tagName.equals(PARAM.toString())) {
121                 sink.rawText(parser.getText());
122             }
123         }
124     }
125 
126     
127 
128 
129 
130 
131 
132     private void processMacroStart(XmlPullParser parser) throws MacroExecutionException {
133         macroName = parser.getAttributeValue(null, Attribute.NAME.toString());
134 
135         if (macroName == null || macroName.isEmpty()) {
136             final String message = String.format(Locale.ROOT,
137                     "The '%s' attribute for the '%s' tag is required.",
138                     Attribute.NAME, MACRO_TAG);
139             throw new MacroExecutionException(message);
140         }
141     }
142 
143     
144 
145 
146 
147 
148 
149 
150     private void processParamStart(XmlPullParser parser, Sink sink) throws MacroExecutionException {
151         if (macroName != null && !macroName.isEmpty()) {
152             final String paramName = parser
153                     .getAttributeValue(null, Attribute.NAME.toString());
154             final String paramValue = parser
155                     .getAttributeValue(null, Attribute.VALUE.toString());
156 
157             if (paramName == null
158                     || paramValue == null
159                     || paramName.isEmpty()
160                     || paramValue.isEmpty()) {
161                 final String message = String.format(Locale.ROOT,
162                         "'%s' and '%s' attributes for the '%s' tag are required"
163                                 + " inside the '%s' tag.",
164                         Attribute.NAME, Attribute.VALUE, PARAM, MACRO_TAG);
165                 throw new MacroExecutionException(message);
166             }
167 
168             macroParameters.put(paramName, paramValue);
169         }
170         else {
171             sink.rawText(parser.getText());
172         }
173     }
174 
175     
176 
177 
178 
179 
180 
181 
182 
183     private void processMacroEnd(Sink sink) throws MacroExecutionException {
184         final MacroRequest request = new MacroRequest(sourceContent,
185                 new XdocsTemplateParser(), macroParameters,
186                 new File(TEMP_DIR));
187 
188         try {
189             executeMacro(macroName, request, sink);
190         }
191         catch (MacroNotFoundException exception) {
192             final String message = String.format(Locale.ROOT, "Macro '%s' not found.", macroName);
193             throw new MacroExecutionException(message, exception);
194         }
195 
196         reinitializeMacroFields();
197     }
198 
199     
200 
201 
202     private void reinitializeMacroFields() {
203         macroName = "";
204         macroParameters.clear();
205     }
206 }