/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*******************************************************************************/
package org.ebayopensource.turmeric.plugins.maven.tasks;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import edu.emory.mathcs.backport.java.util.Collections;
/**
* Replacement of the XSL process to generate an error descriptor. Mainly due to JDK bugs causing the merge of id &
* metadata xmls to fail, depending on the JDK in use.
* <p>
* Example culprit, the antrun xslt task for ErrorDescriptor will fail on JDK 1.6.0_14 (32-bit, on Linux) to generate an
* xslt internal key needed to produce an ErrorDescriptor.value in the output.
*/
public class GenErrorDescriptorTask {
private static final String URL_SOA_ERROR_DESCRIPTORS = "http://wiki.arch.ebay.com/index.php?page=SOAErrorDescriptors";
public class ErrorDescriptor {
/* found in both id and metadata xmls */
public String id;
/* found in id xml only */
public int value;
public String author;
public String created;
/* found in metadata xml only */
public String severity;
public String category;
public String description;
}
public class ErrorDescriptorSorter implements Comparator<ErrorDescriptor> {
@Override
public int compare(ErrorDescriptor o1, ErrorDescriptor o2) {
return (o1.value - o2.value);
}
}
private Map<String, ErrorDescriptor> descriptors = new HashMap<String, GenErrorDescriptorTask.ErrorDescriptor>();
private String packageName;
private String className;
private String subDomain;
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
private Document parseXml(File xmlfile) throws MojoExecutionException {
try {
SAXBuilder builder = new SAXBuilder(false);
return builder.build(xmlfile);
} catch (JDOMException e) {
throw new MojoExecutionException("Unable to parse: " + xmlfile, e);
} catch (IOException e) {
throw new MojoExecutionException("Unable to parse: " + xmlfile, e);
}
}
public void parseMetadataErrorXml(File metadataErrorFile)
throws MojoExecutionException, MojoFailureException {
Document doc = parseXml(metadataErrorFile);
Element root = doc.getRootElement();
if ("ErrorDescriptors".equals(root.getName()) == false) {
throw new MojoFailureException(
"Not a proper ErrorDescriptors file (metadata): "
+ metadataErrorFile);
}
this.subDomain = root.getChildTextTrim("SubDomain");
String actualPackageName = root.getChildTextTrim("Package");
String actualClassName = root.getChildTextTrim("ClassName");
// Sanity Check
if (packageName.equals(actualPackageName) == false) {
throw new MojoFailureException(
"The plugin configured <packageName>,"
+ " does not match the xml specified <Package>. "
+ " Expected [" + packageName + "], but found ["
+ actualPackageName + "] instead");
}
// Sanity Check
if (className.equals(actualClassName) == false) {
throw new MojoFailureException(
"The plugin configured <className>,"
+ " does not match the xml specified <ClassName>. "
+ " Expected [" + className + "], but found ["
+ actualClassName + "] instead");
}
@SuppressWarnings("unchecked")
List<Element> children = root.getChildren("ErrorDescriptor");
for (Element child : children) {
String id = child.getAttributeValue("id");
if (StringUtils.isBlank(id)) {
throw new MojoFailureException(
"Bad Metadata ErrorDescriptor XML: "
+ "Encountered blank id on ErrorDescriptor");
}
ErrorDescriptor ed = descriptors.get(id);
if (ed == null) {
ed = new ErrorDescriptor();
}
ed.id = id;
ed.severity = child.getAttributeValue("severity");
ed.category = child.getAttributeValue("category");
ed.description = child.getChildTextTrim("Description");
descriptors.put(id, ed);
}
}
public void parseIdErrorXml(File idErrorFile)
throws MojoExecutionException, MojoFailureException {
Document doc = parseXml(idErrorFile);
Element root = doc.getRootElement();
if ("ErrorDescriptors".equals(root.getName()) == false) {
throw new MojoFailureException(
"Not a proper ErrorDescriptors file (id): " + idErrorFile);
}
@SuppressWarnings("unchecked")
List<Element> children = root.getChildren("ErrorDescriptor");
for (Element child : children) {
String id = child.getAttributeValue("id");
if (StringUtils.isBlank(id)) {
throw new MojoFailureException(
"Bad Metadata ErrorDescriptor XML: "
+ "Encountered blank id on ErrorDescriptor");
}
ErrorDescriptor ed = descriptors.get(id);
if (ed == null) {
ed = new ErrorDescriptor();
}
ed.id = id;
ed.value = asInt(id, child.getAttributeValue("value"));
ed.author = child.getAttributeValue("author");
ed.created = child.getAttributeValue("created");
descriptors.put(id, ed);
}
}
private int asInt(String id, String value) throws MojoFailureException {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new MojoFailureException("Bad value on ErrorDescriptor: "
+ id + ", [" + value + "] is not a parsable number.");
}
}
public void generate(File outputSourceFile) throws MojoExecutionException {
PrintStream out = null;
FileOutputStream stream = null;
try {
stream = new FileOutputStream(outputSourceFile);
out = new PrintStream(stream);
printSource(out);
out.flush();
} catch (IOException e) {
throw new MojoExecutionException(
"Unable to generate output source file: "
+ outputSourceFile);
} finally {
IOUtil.close(out);
IOUtil.close(stream);
}
}
public void printSource(PrintStream out) {
// File Header
out.println("/*");
out.println(" * Generated Source, DO NOT EDIT OR COMMIT TO SCM");
out.printf(" * Generated On: %s%n", (new Date()).toString());
out.println(" */");
// Package Namespace
out.printf("package %s;%n", packageName);
out.println();
// Imports
out.println("import com.ebay.kernel.CodeGenerated;");
out.println("import org.ebayopensource.turmeric.common.v1.types.ErrorCategory;");
out.println("import org.ebayopensource.turmeric.common.v1.types.ErrorSeverity;");
out.println("import org.ebayopensource.turmeric.runtime.types.common.error.ServiceBaseErrorDescriptor;");
out.println();
// Class Header
out.println("/**");
out.println(" * Please DONOT EDIT/CHECKIN this file. If you want to add new Errors to this file");
out.printf(" * please reserve the error in Entity File %s.xml%n",
className);
out.println(" *");
out.printf(" * For more information please see wiki - %s%n",
URL_SOA_ERROR_DESCRIPTORS);
out.println(" *");
out.println(" * @author turmeric-maven-plugin:gen-errordescriptor");
out.println(" */");
// Class
out.printf("public final class %s%n", className);
out.println(" extends ServiceBaseErrorDescriptor");
out.println(" implements CodeGenerated {");
// Fields
// TODO: handle ErrorArgument (not seen yet)
// public static final String PARAM_@name@ = "@name@";
out.println();
out.println(" private static final long serialVersionUID = 1L;");
out.printf(" private static final String SUB_DOMAIN = \"%s\";%n",
subDomain);
out.println();
// Constructor Declaration
out.printf(" private %s(", className);
out.print("long errorId, String errorName, String subDomain,");
out.print(" ErrorSeverity errorSeverity, ErrorCategory category,");
out.println(" String message) {");
out.print(" super(errorId, errorName, subDomain,");
out.println(" errorSeverity, category, message);");
out.println(" }");
out.println();
// Constants
List<ErrorDescriptor> sorted = new ArrayList<ErrorDescriptor>();
sorted.addAll(descriptors.values());
Collections.sort(sorted, new ErrorDescriptorSorter());
for (ErrorDescriptor ed : sorted) {
out.printf(" public static final %s %s = new %s(%n", className,
ed.id, className);
out.printf(" %d,%n", ed.value);
out.printf(" \"%s\",%n", ed.id);
out.printf(" SUB_DOMAIN,%n");
out.printf(" ErrorSeverity.%s,%n", ed.severity);
out.printf(" ErrorCategory.%s,%n", ed.category);
out.printf(" \"%s\");%n", ed.description);
out.println();
}
out.println("}");
}
}