package com.anasoft.os.m2st.doxia.macro;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.apache.maven.doxia.macro.AbstractMacro;
import org.apache.maven.doxia.macro.Macro;
import org.apache.maven.doxia.macro.MacroExecutionException;
import org.apache.maven.doxia.macro.MacroRequest;
/**
* Base class for custom {@link Macro} implementations.
*
* @see AbstractMacro
* @see Macro
*
* @author milan.skuhra
* @author vojtech.szocs
*/
public abstract class BaseMacro extends AbstractMacro {
// default source file encoding
protected static final String DEFAULT_ENCODING = "UTF-8";
// regular expressions for matching start and end of a snippet
private static final Pattern START_SNIPPET = Pattern.compile("START SNIPPET:\\s*(\\S+)");
private static final Pattern END_SNIPPET = Pattern.compile("END SNIPPET:\\s*(\\S+)");
/**
* Returns a {@link URL} for the resource location specified
* either by <tt>urlParamName</tt> or <tt>fileParamName</tt>
* {@link MacroRequest} parameters.
*
* <p>
*
* Note that the <tt>urlParamName</tt> parameter always takes
* precedence over the <tt>fileParamName</tt> when searching
* for the resource location.
*
* @param request {@link MacroRequest} instance containing
* appropriate resource location parameter(s).
* @param urlParamName Parameter name pointing to direct
* resource {@link URL} as a string value (can be <tt>null</tt>).
* @param fileParamName Parameter name pointing to absolute
* or relative {@link File} location (can be <tt>null</tt>).
* @return Corresponding resource {@link URL}.
*/
protected URL getResourceUrl(MacroRequest request, String urlParamName, String fileParamName) {
String url = null;
if (urlParamName != null)
url = (String) request.getParameter(urlParamName);
String file = null;
if (fileParamName != null)
file = (String) request.getParameter(fileParamName);
if (url != null) {
try {
return new URL(url);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Malformed URL " + url);
}
}
else if (file != null) {
File f = new File(file);
if (!f.isAbsolute())
f = new File(request.getBasedir(), file);
try {
return f.toURL();
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Malformed URL for file " + file);
}
}
else {
throw new IllegalArgumentException("Either '" + urlParamName + "' or '"
+ fileParamName + "' macro parameter needs to be specified");
}
}
/**
* Returns the value of a macro parameter from the <tt>request</tt>.
*
* <p>
*
* Note that the method throws a {@link MacroExecutionException}
* when a <tt>required</tt> macro parameter is not found.
*
* @param <T> Expected value type.
* @param request {@link MacroRequest} instance to check.
* @param paramName Macro parameter name.
* @param required <tt>true</tt> to check the presence of the macro
* parameter within the <tt>request</tt>, <tt>false</tt> otherwise.
* @return Corresponding macro parameter value.
* @throws MacroExecutionException
*/
@SuppressWarnings("unchecked")
protected <T> T getParameterValue(MacroRequest request, String paramName, boolean required) throws MacroExecutionException {
T value = (T) request.getParameter(paramName);
if (required && value == null)
throw new MacroExecutionException("'" + paramName + "' macro parameter needs to be specified");
return value;
}
/**
* Loads a snippet from the given <tt>url</tt>.
*
* <p>
*
* This method uses regular expressions to identify the data region
* within the source file according to the given <tt>id</tt>, for
* example:
*
* <pre>
* Some content
*
* START SNIPPET: myCode
* Content for snippet with id 'myCode'
* END SNIPPET: myCode
*
* Some content
* </pre>
*
* @param id Snippet identifier (can be <tt>null</tt>
* to include the entire source file contents).
* @param url Source file {@link URL}.
* @param encoding Source file encoding.
* @return Snippet contents.
* @throws IOException
*/
public static String loadSnippet(String id, URL url, String encoding) throws IOException {
StringBuilder snippet = new StringBuilder();
LineIterator lines = IOUtils.lineIterator(url.openStream(), encoding);
try {
boolean include = (id == null);
while (lines.hasNext()) {
String line = lines.nextLine();
if (match(line, START_SNIPPET, id)) {
include = true;
} else if (match(line, END_SNIPPET, id)) {
break;
} else if (include == true) {
snippet.append(line).append(System.getProperty("line.separator"));
}
}
} finally {
LineIterator.closeQuietly(lines);
}
return snippet.toString();
}
/**
* Returns <tt>true</tt> when <tt>line</tt> matches
* the given <tt>pattern</tt> and the first match
* group is equal to <tt>value</tt>.
*
* <p>
*
* Returns <tt>false</tt> when the <tt>value</tt>
* is <tt>null</tt>.
*
* @param line Line input to match.
* @param pattern Pattern to match against.
* @param value Expected first match group value.
* @return Input match result.
*/
private static boolean match(String line, Pattern pattern, String value) {
if (value == null)
return false;
Matcher m = pattern.matcher(line);
return m.find() && value.equals(m.group(1));
}
}