| /* |
| * Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * o Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * o Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * o Neither the name of syntevo GmbH nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
| * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| package com.syntevo.bugtraq; |
| |
| import java.util.*; |
| import java.util.regex.*; |
| |
| import org.jetbrains.annotations.*; |
| |
| final class BugtraqParser { |
| |
| // Static ================================================================= |
| |
| @NotNull |
| public static BugtraqParser createInstance(@NotNull String idRegex, @Nullable String linkRegex, @Nullable String filterRegex) throws BugtraqException { |
| try { |
| return new BugtraqParser(idRegex, linkRegex, filterRegex); |
| } |
| catch (PatternSyntaxException ex) { |
| throw new BugtraqException(ex); |
| } |
| } |
| |
| // Fields ================================================================= |
| |
| private final Pattern idPattern; |
| private final Pattern linkPattern; |
| private final Pattern filterPattern; |
| |
| // Setup ================================================================== |
| |
| private BugtraqParser(@NotNull String idRegex, @Nullable String linkRegex, @Nullable String filterRegex) { |
| idPattern = compilePatternSafe(idRegex); |
| linkPattern = linkRegex != null ? compilePatternSafe(linkRegex) : null; |
| filterPattern = filterRegex != null ? compilePatternSafe(filterRegex) : null; |
| } |
| |
| // Accessing ============================================================== |
| |
| @Nullable |
| public List<BugtraqParserIssueId> parse(@NotNull String message) { |
| List<Part> parts = new ArrayList<Part>(); |
| parts.add(new Part(message, 0, message.length() - 1)); |
| |
| if (filterPattern != null) { |
| parts = collectParts(parts, filterPattern); |
| } |
| |
| if (linkPattern != null) { |
| parts = collectParts(parts, linkPattern); |
| } |
| |
| final List<BugtraqParserIssueId> ids = new ArrayList<BugtraqParserIssueId>(); |
| for (final Part part : parts) { |
| final Matcher matcher = idPattern.matcher(part.text); |
| while (matcher.find()) { |
| final Part subPart = createSubPart(part, matcher, matcher.groupCount() == 0 ? 0 : 1); |
| if (subPart == null) { |
| continue; |
| } |
| |
| final BugtraqParserIssueId id; |
| if (linkPattern == null) { |
| id = new BugtraqParserIssueId(subPart.from, subPart.to, subPart.text); |
| } |
| else { |
| if (matcher.find()) { |
| // If we are using links, the last pattern (link) must produce exactly one id. |
| continue; |
| } |
| |
| id = new BugtraqParserIssueId(part.from, part.to, subPart.text); |
| } |
| |
| if (ids.size() > 0) { |
| final BugtraqParserIssueId lastId = ids.get(ids.size() - 1); |
| if (id.getFrom() <= lastId.getTo()) { |
| continue; |
| } |
| } |
| |
| ids.add(id); |
| } |
| } |
| |
| return ids; |
| } |
| |
| // Utils ================================================================== |
| |
| private static List<Part> collectParts(@NotNull List<Part> mainParts, @NotNull Pattern pattern) { |
| final List<Part> subParts = new ArrayList<Part>(); |
| for (final Part part : mainParts) { |
| final Matcher matcher = pattern.matcher(part.text); |
| while (matcher.find()) { |
| final Part newPart = createSubPart(part, matcher, matcher.groupCount() == 0 ? 0 : 1); |
| if (newPart != null) { |
| subParts.add(newPart); |
| } |
| } |
| } |
| |
| return subParts; |
| } |
| |
| @Nullable |
| private static Part createSubPart(Part part, Matcher matcher, int group) { |
| final int textStart = matcher.start(group) + part.from; |
| final int textEnd = matcher.end(group) - 1 + part.from; |
| if (textEnd < 0) { |
| return null; |
| } |
| |
| return new Part(matcher.group(group), textStart, textEnd); |
| } |
| |
| private static Pattern compilePatternSafe(String pattern) throws PatternSyntaxException { |
| return Pattern.compile(pattern); |
| } |
| |
| // Inner Classes ========================================================== |
| |
| private static class Part { |
| |
| private final int from; |
| private final int to; |
| private final String text; |
| |
| public Part(String text, int from, int to) { |
| this.text = text; |
| this.from = from; |
| this.to = to; |
| } |
| } |
| } |