(missingDependencies);
+ boolean ok = true;
+ for (String dependency : dependencies) {
+ boolean found = false;
+ for (String suffix : MIB_SUFFIXES) {
+ final String fileName = (dependency+suffix).toLowerCase();
+ if (mibDirectoryFiles.containsKey(fileName)) {
+ File f = mibDirectoryFiles.get(fileName);
+ LOG.debug("Checking dependency file {}", f.getAbsolutePath());
+ if (f.exists()) {
+ LOG.info("Adding dependency file {}", f.getAbsolutePath());
+ addFileToQueue(queue, f);
+ missingDependencies.remove(dependency);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ LOG.warn("Couldn't find dependency {} on {}", dependency, mibDirectory);
+ ok = false;
+ }
+ }
+ return ok;
+ }
+
+ /**
+ * Gets the module.
+ *
+ * @param mibObject the MIB object
+ * @param mibFile the MIB file
+ * @return the module
+ */
+ private SmiModule getModule(SmiMib mibObject, File mibFile) {
+ for (SmiModule m : mibObject.getModules()) {
+ URL source = null;
+ try {
+ source = new URL(m.getIdToken().getLocation().getSource());
+ } catch (Exception e) {}
+ if (source != null) {
+ try {
+ File srcFile = new File(source.toURI());
+ if (srcFile.getAbsolutePath().equals(mibFile.getAbsolutePath())) {
+ return m;
+ }
+ } catch (Exception e) {}
+ }
+ }
+ LOG.error("Can't find the MIB module for " + mibFile);
+ errorHandler.addError("Can't find the MIB module for " + mibFile);
+ return null;
+ }
+
+ /*
+ * Data Collection processing methods
+ */
+
+ /**
+ * Gets the metric type.
+ * This should be consistent with NumericAttributeType and StringAttributeType.
+ * For this reason the valid types are: counter, gauge, timeticks, integer, octetstring, string.
+ * Any derivative is also valid, for example: Counter32, Integer64, etc...
+ *
+ * @param smiType the type
+ * @return the type
+ */
+ private String getMetricType(final SmiType smiType) {
+ if(Objects.isNull(smiType)){
+ return null;
+ }
+ if(!Objects.isNull(smiType.getId()) && smiType.getId().equalsIgnoreCase("CounterBasedGauge64")){
+ return "gauge";
+ }
+ final SmiPrimitiveType type = smiType.getPrimitiveType();
+ if (Objects.isNull(type)) {
+ return null;
+ }
+ if (type.equals(SmiPrimitiveType.ENUM)) // ENUM are just informational elements.
+ return "string";
+ if (type.equals(SmiPrimitiveType.OBJECT_IDENTIFIER)) // ObjectIdentifier will be treated as strings.
+ return "string";
+ if (type.equals(SmiPrimitiveType.UNSIGNED_32)) // Unsigned32 will be treated as integer.
+ return "integer";
+ if (type.equals(SmiPrimitiveType.IP_ADDRESS)) // IpAddress will be treated as strings.
+ return "string";
+ if (type.equals(SmiPrimitiveType.BITS)) // BITS are extension of octet string.
+ return "octetstring";
+ return type.toString().replaceAll("_", "").toLowerCase();
+ }
+
+ /**
+ * Gets the group.
+ *
+ * @param data the data collection group object
+ * @param groupName the group name
+ * @param resourceType the resource type
+ * @return the group
+ */
+ protected Group getGroup(DatacollectionGroup data, String groupName, String resourceType) {
+ for (Group group : data.getGroups()) {
+ if (group.getName().equals(groupName))
+ return group;
+ }
+ Group group = new Group();
+ group.setName(groupName);
+ group.setIfType(resourceType == null ? "ignore" : "all");
+ if (resourceType != null) {
+ ResourceType type = new ResourceType();
+ type.setName(resourceType);
+ type.setLabel(resourceType);
+ type.setResourceLabel("${index}");
+ type.setPersistenceSelectorStrategy(new PersistenceSelectorStrategy("org.opennms.netmgt.collection.support.PersistAllSelectorStrategy")); // To avoid requires opennms-services
+ type.setStorageStrategy(new StorageStrategy(IndexStorageStrategy.class.getName()));
+ data.addResourceType(type);
+ }
+ data.addGroup(group);
+ return group;
+ }
+
+ /*
+ * Event processing methods
+ *
+ */
+
+ /**
+ * Convert MIB to events.
+ *
+ * @param module the module object
+ * @param ueibase the UEI base
+ * @return the events
+ */
+ protected Events convertMibToEvents(SmiModule module, String ueibase) {
+ Events events = new Events();
+ for (SmiNotificationType trap : module.getNotificationTypes()) {
+ events.addEvent(getTrapEvent(trap, ueibase));
+ }
+ for (SmiTrapType trap : module.getTrapTypes()) {
+ events.addEvent(getTrapEvent(trap, ueibase));
+ }
+ return events;
+ }
+
+ /**
+ * Gets the trap event.
+ *
+ * @param trap the trap object
+ * @param ueibase the UEI base
+ * @return the trap event
+ */
+ protected Event getTrapEvent(Notification trap, String ueibase) {
+ // Build default severity
+ String severity = OnmsSeverity.INDETERMINATE.toString();
+ severity = severity.substring(0, 1).toUpperCase() + severity.substring(1).toLowerCase();
+ // Set the event's UEI, event-label, logmsg, severity, and descr
+ Event evt = new Event();
+ evt.setUei(getTrapEventUEI(trap, ueibase));
+ evt.setEventLabel(getTrapEventLabel(trap));
+ evt.setLogmsg(getTrapEventLogmsg(trap));
+ evt.setSeverity(severity);
+ evt.setDescr(getTrapEventDescr(trap));
+ List decode = getTrapVarbindsDecode(trap);
+ if (!decode.isEmpty()) {
+ evt.setVarbindsdecodes(decode);
+ }
+ evt.setMask(new Mask());
+ // The "ID" mask element (trap enterprise)
+ addMaskElement(evt, "id", getTrapEnterprise(trap));
+ // The "generic" mask element: hard-wired to enterprise-specific(6)
+ addMaskElement(evt, "generic", "6");
+ // The "specific" mask element (trap specific-type)
+ addMaskElement(evt, "specific", getTrapSpecificType(trap));
+ return evt;
+ }
+
+ /**
+ * Gets the trap event UEI.
+ *
+ * @param trap the trap object
+ * @param ueibase the UEI base
+ * @return the trap event UEI
+ */
+ protected String getTrapEventUEI(Notification trap, String ueibase) {
+ final StringBuilder buf = new StringBuilder(ueibase);
+ if (! ueibase.endsWith("/")) {
+ buf.append("/");
+ }
+ buf.append(trap.getId());
+ return buf.toString();
+ }
+
+ /**
+ * Gets the trap event label.
+ *
+ * @param trap the trap object
+ * @return the trap event label
+ */
+ protected String getTrapEventLabel(Notification trap) {
+ final StringBuilder buf = new StringBuilder();
+ buf.append(trap.getModule().getId());
+ buf.append(" defined trap event: ");
+ buf.append(trap.getId());
+ return buf.toString();
+ }
+
+ /**
+ * Gets the trap event LogMsg.
+ *
+ * @param trap the trap object
+ * @return the trap event LogMsg
+ */
+ protected Logmsg getTrapEventLogmsg(Notification trap) {
+ Logmsg msg = new Logmsg();
+ msg.setDest(LogDestType.LOGNDISPLAY);
+ final StringBuilder dbuf = new StringBuilder();
+ dbuf.append("");
+ dbuf.append("\n");
+ dbuf.append("\t").append(trap.getId()).append(" trap received\n");
+ int vbNum = 1;
+ for (SmiVariable var : trap.getObjects()) {
+ dbuf.append("\t").append(var.getId()).append("=%parm[#").append(vbNum).append("]%\n");
+ vbNum++;
+ }
+ if (dbuf.charAt(dbuf.length() - 1) == '\n') {
+ dbuf.deleteCharAt(dbuf.length() - 1); // delete the \n at the end
+ }
+ dbuf.append("
\n\t");
+ msg.setContent(dbuf.toString());
+ return msg;
+ }
+
+ /**
+ * Gets the trap event description.
+ *
+ * @param trap the trap object
+ * @return the trap event description
+ */
+ protected String getTrapEventDescr(Notification trap) {
+ String description = trap.getDescription();
+ if (description == null) {
+ LOG.warn("The trap {} doesn't have a description field", trap.getOidStr());
+ }
+ // FIXME There a lot of detail here (like removing the last \n) that can go away when we don't need to match mib2opennms exactly
+ final String descrEndingNewlines = description == null ? "No Description." : description.replaceAll("^", "\n").replaceAll("$", "
\n");
+ final StringBuffer dbuf = new StringBuffer(descrEndingNewlines);
+ if (dbuf.charAt(dbuf.length() - 1) == '\n') {
+ dbuf.deleteCharAt(dbuf.length() - 1); // delete the \n at the end
+ }
+ dbuf.append("");
+ dbuf.append("\n");
+ int vbNum = 1;
+ for (SmiVariable var : trap.getObjects()) {
+ dbuf.append("\t| \n\n\t").append(var.getId());
+ dbuf.append(" | \n\t%parm[#").append(vbNum).append("]%; | ");
+ SmiPrimitiveType type = var.getType().getPrimitiveType();
+ if (type.equals(SmiPrimitiveType.ENUM)) {
+ SortedMap map = new TreeMap();
+ SmiType t = var.getType();
+ while (t.getEnumValues() == null) {
+ t = t.getBaseType();
+ }
+ List enumValues = t.getEnumValues();
+ if (enumValues != null) {
+ for (SmiNamedNumber v : enumValues) {
+ map.put(v.getValue(), v.getId());
+ }
+ } else {
+ // This is theoretically impossible, but in case of another bug in JSMIParser, better than an NPE.
+ map.put(new BigInteger("0"), "Unable to derive list of possible values.");
+ }
+ dbuf.append("\n");
+ for (Entry entry : map.entrySet()) {
+ dbuf.append("\t\t").append(entry.getValue()).append("(").append(entry.getKey()).append(")\n");
+ }
+ dbuf.append("\t");
+ }
+ dbuf.append(" |
\n");
+ vbNum++;
+ }
+ if (dbuf.charAt(dbuf.length() - 1) == '\n') {
+ dbuf.deleteCharAt(dbuf.length() - 1); // delete the \n at the end
+ }
+ dbuf.append("
\n\t");
+ return dbuf.toString();
+ }
+
+ /**
+ * Gets the trap varbinds decode.
+ *
+ * @param trap the trap object
+ * @return the trap varbinds decode
+ */
+ protected List getTrapVarbindsDecode(Notification trap) {
+ Map decode = new LinkedHashMap();
+ int vbNum = 1;
+ for (SmiVariable var : trap.getObjects()) {
+ String parmName = "parm[#" + vbNum + "]";
+ SmiPrimitiveType type = var.getType().getPrimitiveType();
+ if (type.equals(SmiPrimitiveType.ENUM)) {
+ SortedMap map = new TreeMap();
+ SmiType t = var.getType();
+ while (t.getEnumValues() == null) {
+ t = t.getBaseType();
+ }
+ List enumValues = t.getEnumValues();
+ if (enumValues != null) {
+ for (SmiNamedNumber v : enumValues) {
+ map.put(v.getValue(), v.getId());
+ }
+ for (Entry entry : map.entrySet()) {
+ if (!decode.containsKey(parmName)) {
+ Varbindsdecode newVarbind = new Varbindsdecode();
+ newVarbind.setParmid(parmName);
+ decode.put(newVarbind.getParmid(), newVarbind);
+ }
+ Decode d = new Decode();
+ d.setVarbinddecodedstring(entry.getValue());
+ d.setVarbindvalue(entry.getKey().toString());
+ decode.get(parmName).addDecode(d);
+ }
+ }
+ }
+ vbNum++;
+ }
+ return new ArrayList(decode.values());
+ }
+
+ /**
+ * Gets the trap enterprise.
+ *
+ * @param trap the trap object
+ * @return the trap enterprise
+ */
+ private String getTrapEnterprise(Notification trap) {
+ String trapOid = getMatcherForOid(getTrapOid(trap)).group(1);
+
+ /* RFC3584 sec 3.2 (1) bullet 2 sub-bullet 1 states:
+ *
+ * "If the next-to-last sub-identifier of the snmpTrapOID value
+ * is zero, then the SNMPv1 enterprise SHALL be the SNMPv2
+ * snmpTrapOID value with the last 2 sub-identifiers removed..."
+ *
+ * Issue SPC-592 boils down to the fact that we were not doing the above.
+ *
+ */
+
+ if (trapOid.endsWith(".0")) {
+ trapOid = trapOid.substring(0, trapOid.length() - 2);
+ }
+ return trapOid;
+ }
+
+ /**
+ * Gets the trap specific type.
+ *
+ * @param trap the trap object
+ * @return the trap specific type
+ */
+ private String getTrapSpecificType(Notification trap) {
+ return getMatcherForOid(getTrapOid(trap)).group(2);
+ }
+
+ /**
+ * Gets the matcher for OID.
+ *
+ * @param trapOid the trap OID
+ * @return the matcher for OID
+ */
+ private Matcher getMatcherForOid(String trapOid) {
+ Matcher m = TRAP_OID_PATTERN.matcher(trapOid);
+ if (!m.matches()) {
+ throw new IllegalStateException("Could not match the trap OID '" + trapOid + "' against '" + m.pattern().pattern() + "'");
+ }
+ return m;
+ }
+
+ /**
+ * Gets the trap OID.
+ *
+ * @param trap the trap object
+ * @return the trap OID
+ */
+ private String getTrapOid(Notification trap) {
+ return '.' + trap.getOidStr();
+ }
+
+ /**
+ * Adds the mask element.
+ *
+ * @param event the event object
+ * @param name the name
+ * @param value the value
+ */
+ private void addMaskElement(Event event, String name, String value) {
+ if (event.getMask() == null) {
+ throw new IllegalStateException("Event mask is not present, must have been set before this method was called");
+ }
+ Maskelement me = new Maskelement();
+ me.setMename(name);
+ me.addMevalue(value);
+ event.getMask().addMaskelement(me);
+ }
+}
diff --git a/features/mib-compiler-rest/parser/src/main/java/org/opennms/features/mibcompiler/services/OnmsProblemEventHandler.java b/features/mib-compiler-rest/parser/src/main/java/org/opennms/features/mibcompiler/services/OnmsProblemEventHandler.java
new file mode 100644
index 000000000000..ef6ecb91915d
--- /dev/null
+++ b/features/mib-compiler-rest/parser/src/main/java/org/opennms/features/mibcompiler/services/OnmsProblemEventHandler.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to The OpenNMS Group, Inc (TOG) under one or more
+ * contributor license agreements. See the LICENSE.md file
+ * distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * TOG licenses this file to You under the GNU Affero General
+ * Public License Version 3 (the "License") or (at your option)
+ * any later version. You may not use this file except in
+ * compliance with the License. You may obtain a copy of the
+ * License at:
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.opennms.features.mibcompiler.services;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.jsmiparser.parser.SmiDefaultParser;
+import org.jsmiparser.util.location.Location;
+import org.jsmiparser.util.problem.DefaultProblemReporterFactory;
+import org.jsmiparser.util.problem.ProblemEvent;
+import org.jsmiparser.util.problem.ProblemEventHandler;
+import org.jsmiparser.util.problem.ProblemReporterFactory;
+import org.jsmiparser.util.problem.annotations.ProblemSeverity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Implementation of the ProblemEventHandler interface for OpenNMS.
+ *
+ * @author Alejandro Galue
+ */
+public class OnmsProblemEventHandler implements ProblemEventHandler {
+
+ /** The Constant LOG. */
+ private static final Logger LOG = LoggerFactory.getLogger(OnmsProblemEventHandler.class);
+
+ /** The Constant FILE_PREFIX. */
+ private static final String FILE_PREFIX_LINUX = "file://";
+
+ /** The Constant FILE_PREFIX. */
+ private static final String FILE_PREFIX_WINDOWS = "file:///";
+
+ /** The Constant DEPENDENCY_PATERN. */
+ private static final Pattern DEPENDENCY_PATERN = Pattern.compile("Cannot find module ([^,]+)", Pattern.MULTILINE);
+
+ /** The severity counters. */
+ private int[] m_severityCounters = new int[ProblemSeverity.values().length];
+
+ /** The total counter. */
+ private int m_totalCounter;
+
+ /** The output stream. */
+ private ByteArrayOutputStream m_outputStream = new ByteArrayOutputStream();
+
+ /** The print stream. */
+ private PrintStream m_out;
+
+ /**
+ * The Class Source.
+ */
+ private static class Source {
+ public File file;
+ public int row;
+ public int column;
+ }
+
+ /**
+ * Instantiates a new OpenNMS problem event handler.
+ *
+ * @param parser the parser
+ */
+ public OnmsProblemEventHandler(SmiDefaultParser parser) {
+ m_out = new PrintStream(m_outputStream);
+ ProblemReporterFactory problemReporterFactory = new DefaultProblemReporterFactory(getClass().getClassLoader(), this);
+ parser.setProblemReporterFactory(problemReporterFactory);
+ }
+
+ /* (non-Javadoc)
+ * @see org.jsmiparser.util.problem.ProblemEventHandler#handle(org.jsmiparser.util.problem.ProblemEvent)
+ */
+ @Override
+ public void handle(ProblemEvent event) {
+ m_severityCounters[event.getSeverity().ordinal()]++;
+ m_totalCounter++;
+ print(m_out, event.getSeverity().toString(), event.getLocation(), event.getLocalizedMessage());
+ }
+
+ /* (non-Javadoc)
+ * @see org.jsmiparser.util.problem.ProblemEventHandler#isOk()
+ */
+ @Override
+ public boolean isOk() {
+ for (int i = 0; i < m_severityCounters.length; i++) {
+ if (i >= ProblemSeverity.ERROR.ordinal()) {
+ int severityCounter = m_severityCounters[i];
+ if (severityCounter > 0) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jsmiparser.util.problem.ProblemEventHandler#isNotOk()
+ */
+ @Override
+ public boolean isNotOk() {
+ return !isOk();
+ }
+
+ /* (non-Javadoc)
+ * @see org.jsmiparser.util.problem.ProblemEventHandler#getSeverityCount(org.jsmiparser.util.problem.annotations.ProblemSeverity)
+ */
+ @Override
+ public int getSeverityCount(ProblemSeverity severity) {
+ return m_severityCounters[severity.ordinal()];
+ }
+
+ /* (non-Javadoc)
+ * @see org.jsmiparser.util.problem.ProblemEventHandler#getTotalCount()
+ */
+ @Override
+ public int getTotalCount() {
+ return m_totalCounter;
+ }
+
+ /**
+ * Gets the prefix.
+ * The URL prefix depending on the host Operating System
+ *
+ * @return the prefix
+ */
+ private String getPrefix() {
+ return File.separatorChar == '\\' ? FILE_PREFIX_WINDOWS : FILE_PREFIX_LINUX;
+ }
+
+ /**
+ * Gets the MIB from source.
+ *
+ * @param source the source
+ * @return the MIB from source
+ */
+ private String getMibFromSource(final String source) {
+ return getMibFromSource(source, File.separatorChar);
+ }
+
+ /**
+ * Gets the MIB from source.
+ *
+ * @param source the source
+ * @param separatorChar the separatoe character
+ * @return the MIB from source
+ */
+ String getMibFromSource(final String source, final char separatorChar) {
+ final String arr[] = source.split(":");
+
+ if (separatorChar == '\\') {
+ if (arr.length == 5) {
+ return arr[4];
+ }
+ } else {
+ if (arr.length == 4) {
+ return arr[3];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Prints the error message.
+ *
+ * @param stream the stream
+ * @param severity the severity
+ * @param location the location
+ * @param localizedMessage the localized message
+ */
+ private void print(final PrintStream stream, final String severity, final Location location, final String localizedMessage) {
+ LOG.debug("[{}] Location: {}, Message: {}", severity, location, localizedMessage);
+ int n = localizedMessage.indexOf(getPrefix());
+ if (n > 0) {
+ final String source = localizedMessage.substring(n).replaceAll(getPrefix(), "");
+ final String mibFromSource = getMibFromSource(source);
+
+ final String message;
+
+ if (mibFromSource == null) {
+ message = localizedMessage;
+ } else {
+ message = localizedMessage.substring(0, n) + getMibFromSource(source);
+ }
+
+ processMessage(stream, severity, source, message);
+ } else {
+ if (location == null) {
+ stream.println(severity + ": " + localizedMessage);
+ } else {
+ final String source = location.toString().replaceAll(getPrefix(), "");
+ final String message = localizedMessage;
+ processMessage(stream, severity, source, message);
+ }
+ }
+ }
+
+ /**
+ * Gets the source data.
+ * Analyzes the source string and build the data source depending on the host Operating System
+ *
+ * @param strSource the string source
+ * @return the source data
+ */
+ private Source getSourceData(String strSource) {
+ String[] data = strSource.split(":");
+ Source src = new Source();
+ int rowIdx = 1;
+ int colIdx = 2;
+ if (File.separatorChar == '\\') { // Windows
+ src.file = new File(data[0] + ':' + data[1]);
+ rowIdx = 2;
+ colIdx = 3;
+ } else { // Linux
+ src.file = new File(data[0]);
+ }
+ try {
+ src.row = Integer.parseInt(data[rowIdx]);
+ } catch (Exception e) {
+ src.row = -1;
+ }
+ try {
+ src.column = Integer.parseInt(data[colIdx]);
+ } catch (Exception e) {
+ src.column = -1;
+ }
+ return src;
+ }
+
+ /**
+ * Process the error message.
+ *
+ * @param stream the stream
+ * @param severity the severity
+ * @param source the location source
+ * @param message the message
+ */
+ // TODO This implementation might be expensive.
+ private void processMessage(final PrintStream stream, final String severity, final String source, final String message) {
+ final Source src = getSourceData(source);
+ if (src.row != -1 && src.column != -1) {
+ stream.println(severity + ": " + message + ", Source: " + src.file.getName() + ", Row: " + src.row + ", Col: " + src.column);
+ } else {
+ stream.println(severity + ": " + message + ", Source: " + src.file.getName());
+ }
+ try {
+ if (!src.file.exists()) {
+ LOG.warn("File {} doesn't exist", src.file);
+ return;
+ }
+ final FileInputStream fs = new FileInputStream(src.file);
+ final BufferedReader br = new BufferedReader(new InputStreamReader(fs));
+ for (int i = 1; i < src.row; i++)
+ br.readLine();
+ stream.println(br.readLine());
+ br.close();
+ stream.println(String.format("%" + src.column + "s", "^"));
+ } catch (Exception e) {
+ LOG.warn("Can't retrieve line {} from file {}", src.row, src.file);
+ }
+ }
+
+ /**
+ * Reset.
+ */
+ public void reset() {
+ m_outputStream.reset();
+ m_severityCounters = new int[ProblemSeverity.values().length];
+ m_totalCounter = 0;
+ }
+
+ /**
+ * Gets the dependencies.
+ *
+ * @return the dependencies
+ */
+ public List getDependencies() {
+ List dependencies = new ArrayList<>();
+ if (m_outputStream.size() > 0) {
+ Matcher m = DEPENDENCY_PATERN.matcher(m_outputStream.toString());
+ while (m.find()) {
+ final String dep = m.group(1);
+ if (!dependencies.contains(dep))
+ dependencies.add(dep);
+ }
+ }
+ return dependencies;
+ }
+
+ /**
+ * Gets the messages.
+ *
+ * @return the messages
+ */
+ public String getMessages() {
+ return m_outputStream.size() > 0 ? m_outputStream.toString() : null;
+ }
+
+ /**
+ * Adds a new error message.
+ *
+ * @param errorMessage the error message
+ */
+ public void addError(String errorMessage) {
+ m_out.println(errorMessage);
+ }
+
+}
diff --git a/features/mib-compiler-rest/parser/src/main/java/org/opennms/features/mibcompiler/services/PrefabGraphDumper.java b/features/mib-compiler-rest/parser/src/main/java/org/opennms/features/mibcompiler/services/PrefabGraphDumper.java
new file mode 100644
index 000000000000..da607d15111c
--- /dev/null
+++ b/features/mib-compiler-rest/parser/src/main/java/org/opennms/features/mibcompiler/services/PrefabGraphDumper.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to The OpenNMS Group, Inc (TOG) under one or more
+ * contributor license agreements. See the LICENSE.md file
+ * distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * TOG licenses this file to You under the GNU Affero General
+ * Public License Version 3 (the "License") or (at your option)
+ * any later version. You may not use this file except in
+ * compliance with the License. You may obtain a copy of the
+ * License at:
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.opennms.features.mibcompiler.services;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.opennms.netmgt.model.PrefabGraph;
+
+/**
+ * The Class PrefabGraphDumper.
+ *
+ * @author Alejandro Galue
+ */
+public class PrefabGraphDumper {
+
+ /**
+ * Dump.
+ * This only cover the main variables from the PrefabGraph.
+ *
+ * @param graphs the graphs
+ * @param writer the writer
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void dump(List graphs, Writer writer) throws IOException {
+ List templates = new ArrayList<>();
+ final StringBuilder sb = new StringBuilder();
+ for (PrefabGraph graph : graphs) {
+ String name = "report." + graph.getName();
+ templates.add(graph.getName());
+ sb.append(name).append(".name=").append(graph.getTitle()).append("\n");
+ sb.append(name).append(".columns=").append(StringUtils.join(graph.getColumns(), ",")).append("\n");
+ sb.append(name).append(".type=").append(StringUtils.join(graph.getTypes(), ",")).append("\n");
+ sb.append(name).append(".description=").append(graph.getDescription()).append("\n");
+ sb.append(name).append(".command=").append(graph.getCommand());
+ }
+ writer.write("reports=" + StringUtils.join(templates, ", \\\n") + "\n\n");
+ writer.write(sb.toString());
+ }
+
+}
diff --git a/features/mib-compiler-rest/parser/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/features/mib-compiler-rest/parser/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 000000000000..9ab61de06f96
--- /dev/null
+++ b/features/mib-compiler-rest/parser/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/features/mib-compiler-rest/pom.xml b/features/mib-compiler-rest/pom.xml
new file mode 100644
index 000000000000..6ba3cf6dbc34
--- /dev/null
+++ b/features/mib-compiler-rest/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ org.opennms.features
+ org.opennms
+ 36.0.0-SNAPSHOT
+
+ 4.0.0
+
+ org.opennms.features
+ org.opennms.features.mib-compiler-rest
+ pom
+ OpenNMS :: Features :: Mib Compiler Rest
+
+
+ parser
+ api
+
+
+
\ No newline at end of file
diff --git a/features/pom.xml b/features/pom.xml
index 4a34a6132b5c..e3625e5b358f 100644
--- a/features/pom.xml
+++ b/features/pom.xml
@@ -195,5 +195,6 @@
grpc
elastic
+ mib-compiler-rest