Skip to content

Commit

Permalink
ConDec-375: Change tags in issue comments to JIRA like tags (#50)
Browse files Browse the repository at this point in the history
* ConDec-375: Implement macros on client side. Failing tests disabled

* ConDec-375: Make Testcases great again. Implement new {tags} on client side.

* ConDec-375: Fix bugs from system tests

* ConDec-375: Move Mutex from Knowledge Rest to DecXtract Event handler

* ConDec-375: Fix codacy issues, Apply check if Decxtract and icon parsing are enabled. Implement icon parsing for event listener

* ConDec-375: Fixed indents and settings page issue for non settable toggles

* ConDec-375: write tags from automatic classfication back into comments

* ConDec-375: fix tree viewer in tab panel

* ConDec-375: Fix icons in TreeViewer

* ConDec-375: Add Project Check for DecXtract EL

* ConDEc-375: Fix Argument type icons in Treant

* ConDec-375 Fix codecy issues
  • Loading branch information
Jcl15 authored and dekome committed Nov 5, 2018
1 parent c5bd6c3 commit fdc55d3
Show file tree
Hide file tree
Showing 21 changed files with 785 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@

import com.atlassian.event.api.EventListener;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.event.issue.IssueEvent;
import com.atlassian.jira.event.type.EventType;
import com.atlassian.jira.issue.comments.MutableComment;
import com.atlassian.plugin.spring.scanner.annotation.imports.JiraImport;

import de.uhd.ifi.se.decision.management.jira.extraction.connector.ViewConnector;
import de.uhd.ifi.se.decision.management.jira.extraction.model.impl.CommentImpl;
import de.uhd.ifi.se.decision.management.jira.extraction.model.util.CommentSplitter;
import de.uhd.ifi.se.decision.management.jira.extraction.persistence.ActiveObjectsManager;
import de.uhd.ifi.se.decision.management.jira.model.DecisionKnowledgeElementImpl;
import de.uhd.ifi.se.decision.management.jira.persistence.ConfigPersistence;

/**
* Triggers the decXtract related function when some changes to comments are
Expand All @@ -30,6 +34,11 @@ public class DecXtractEventListener implements InitializingBean, DisposableBean

private IssueEvent issueEvent;

/**
* locks the editComment Event function if a rest service writes edites comments
*/
public static boolean editCommentLock;

@Autowired
public DecXtractEventListener(@JiraImport EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
Expand Down Expand Up @@ -59,30 +68,75 @@ public void destroy() throws Exception {
public void onIssueEvent(IssueEvent issueEvent) {
this.issueEvent = issueEvent;
this.projectKey = issueEvent.getProject().getKey();
if(ConfigPersistence.isActivated(this.projectKey) && ConfigPersistence.isKnowledgeExtractedFromIssues(this.projectKey)) {
return;
}
Long eventTypeId = issueEvent.getEventTypeId();
if(eventTypeId.equals(EventType.ISSUE_COMMENTED_ID) || eventTypeId.equals(EventType.ISSUE_COMMENT_EDITED_ID)) {
parseIconsToTags();
}
if (eventTypeId.equals(EventType.ISSUE_COMMENTED_ID)) {
handleNewComment(new DecisionKnowledgeElementImpl(issueEvent.getIssue()));
}
if (eventTypeId.equals(EventType.ISSUE_COMMENT_DELETED_ID)) {
handleDeleteComment(new DecisionKnowledgeElementImpl(issueEvent.getIssue()));

}
if (eventTypeId.equals(EventType.ISSUE_COMMENT_EDITED_ID)) {
handleEditComment(new DecisionKnowledgeElementImpl(issueEvent.getIssue()));
}
if (eventTypeId.equals(EventType.ISSUE_DELETED_ID)) {
handleDeleteIssue(new DecisionKnowledgeElementImpl(issueEvent.getIssue()));
}
pareseSlashTagsOutOfComment();
}

private void parseIconsToTags() {
if(!ConfigPersistence.isIconParsing(issueEvent.getProject().getKey())) {
return ;
}
MutableComment comment = getCurrentEditedComment();
for (int i = 0; i < CommentSplitter.manualRationalIconList.length; i++) {
String icon = CommentSplitter.manualRationalIconList[i];
while(comment.getBody().contains(icon)) {
comment.setBody(comment.getBody().replaceFirst(icon.replace("(", "\\(").replace(")", "\\)"), CommentSplitter.manualRationaleTagList[i]));
if(comment.getBody().split(System.getProperty("line.separator")).length == 1 && !comment.getBody().endsWith("\r\n")) {
comment.setBody(comment.getBody()+ CommentSplitter.manualRationaleTagList[i]);
}
comment.setBody(comment.getBody().replaceFirst("\r\n", CommentSplitter.manualRationaleTagList[i]));
ComponentAccessor.getCommentManager().update(comment, true);
}
}
}

/**
* Parse \{ out of tags. These slashes are inserted by the visual mode editor
*/
private void pareseSlashTagsOutOfComment() {
if (issueEvent.getComment() != null && issueEvent.getComment().getBody().contains("\\{")) {
MutableComment comment = getCurrentEditedComment();
comment.setBody(issueEvent.getComment().getBody().replace("\\{", "{"));
ComponentAccessor.getCommentManager().update(comment, true);
}
}

private MutableComment getCurrentEditedComment() {
return (MutableComment) ComponentAccessor.getCommentManager()
.getCommentById(issueEvent.getComment().getId());
}

private void handleDeleteIssue(DecisionKnowledgeElementImpl decisionKnowledgeElement) {
ActiveObjectsManager.cleanSentenceDatabaseForProject(this.projectKey);
ActiveObjectsManager.createLinksForNonLinkedElementsForIssue(decisionKnowledgeElement.getId() + "");
}

private void handleEditComment(DecisionKnowledgeElementImpl decisionKnowledgeElement) {
ActiveObjectsManager.checkIfCommentBodyHasChangedOutsideOfPlugin(new CommentImpl(issueEvent.getComment()));
new ViewConnector(this.issueEvent.getIssue(), false);
ActiveObjectsManager.createLinksForNonLinkedElementsForIssue(decisionKnowledgeElement.getId() + "");
if (!DecXtractEventListener.editCommentLock) {// If locked, a rest service is manipulating the comment and
// should not be handled by EL
ActiveObjectsManager.checkIfCommentBodyHasChangedOutsideOfPlugin(new CommentImpl(issueEvent.getComment()));
new ViewConnector(this.issueEvent.getIssue(), false);
ActiveObjectsManager.createLinksForNonLinkedElementsForIssue(decisionKnowledgeElement.getId() + "");
}
}

private void handleDeleteComment(DecisionKnowledgeElementImpl decisionKnowledgeElement) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,17 @@ public CommentImpl(com.atlassian.jira.issue.comments.Comment comment) {
private void splitCommentIntoSentences() {
List<String> rawSentences = this.splitter.sliceCommentRecursionCommander(this.body, this.projectKey);
runBreakIterator(rawSentences);
// ActiveObjectsManager.checkIfCommentBodyHasChangedOutsideOfPlugin(this); //ConDec-373: Now in EventListener
// Create AO entries
// Create AO entries
for (int i = 0; i < this.splitter.getStartSubstringCount().size(); i++) {
int startIndex = this.splitter.getStartSubstringCount().get(i);
int endIndex = this.splitter.getEndSubstringCount().get(i);
long aoId2 = ActiveObjectsManager.addNewSentenceintoAo(this.jiraCommentId, endIndex, startIndex,
this.authorId, this.issueId, this.projectKey);
Sentence sentence = new SentenceImpl(this.body.substring(startIndex, endIndex), aoId2);
sentence.setCreated(this.created);
this.sentences.add(sentence);
if(startIndex >= 0 && endIndex >= 0 &&(endIndex - startIndex) >0 && this.body.substring(startIndex, endIndex).replaceAll("\r\n", "").trim().length() > 1) {
long aoId2 = ActiveObjectsManager.addNewSentenceintoAo(this.jiraCommentId, endIndex, startIndex,
this.authorId, this.issueId, this.projectKey);
Sentence sentence = new SentenceImpl(this.body.substring(startIndex, endIndex), aoId2);
sentence.setCreated(this.created);
this.sentences.add(sentence);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ private void checkForPlainText(String body) {
if (StringUtils.indexOfAny(body.toLowerCase(), CommentSplitter.excludedTagList) >= 0) {
this.isPlainText = false;
}
if (CommentSplitter.containsOpenAndCloseTags(body,this.projectKey)
if (CommentSplitter.isAnyKnowledgeTypeTwiceExisintg(body,this.projectKey)
|| (ConfigPersistence.isIconParsing(projectKey)
&& StringUtils.indexOfAny(body, CommentSplitter.manualRationalIconList) >= 0)) {
this.setKnowledgeTypeString(CommentSplitter.getKnowledgeTypeFromManuallIssueTag(body, this.projectKey,true));
Expand All @@ -264,10 +264,10 @@ private void checkForPlainText(String body) {
}

private void stripTagsFromBody(String body) {
if (StringUtils.indexOfAny(body.toLowerCase(), CommentSplitter.getAllTagsUsedInProject(this.projectKey)) >= 0) {
if (CommentSplitter.isAnyKnowledgeTypeTwiceExisintg(body,this.projectKey)) {
int tagLength = 2
+ CommentSplitter.getKnowledgeTypeFromManuallIssueTag(body, this.projectKey, true).length();
super.setDescription(body.substring(tagLength, body.length() - (1 + tagLength)));
super.setDescription(body.substring(tagLength, body.length() - ( tagLength)));
super.setSummary(super.getDescription());
} else {
super.setDescription(body.replaceAll("\\(.*?\\)", ""));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ public class CommentSplitter {

public static final String[] excludedTagList = new String[] { "{code}", "{quote}", "{noformat}", "{panel}" };

public static final String[] manualRationaleTagList = new String[] { "[issue]", "[decision]", "[alternative]",
"[pro]", "[con]", "[goal]" };

public static final String[] manualRationalIconList = new String[] { "(!)", "(/)", "(?)", "(y)", "(n)" };
/**List with all knowledgeTypes as tags. Sequence matters! */
public static final String[] manualRationaleTagList = new String[] { "{issue}", "{alternative}", "{decision}",
"{pro}", "{con}" };

/**List with all knowledgeTypes as icons. Sequence matters! */
public static final String[] manualRationalIconList = new String[] { "(!)", "(?)", "(/)", "(y)", "(n)" };

public static final String[] allExcluded = (String[]) ArrayUtils
.addAll(ArrayUtils.addAll(excludedTagList, manualRationaleTagList), manualRationalIconList);
Expand All @@ -35,6 +37,10 @@ public CommentSplitter() {
this.setEndSubstringCount(new ArrayList<Integer>());
}

public List<String> splitSentence(String body) {
return sliceCommentRecursionCommander(body, "");
}

public List<String> sliceCommentRecursionCommander(String body, String projectKey) {
List<String> firstSplit = searchBetweenTagsRecursive(body, "{quote}", "{quote}", new ArrayList<String>());

Expand All @@ -43,7 +49,7 @@ public List<String> sliceCommentRecursionCommander(String body, String projectKe
firstSplit = searchForFurtherTags(firstSplit, "{code:", "{code}");
for (int i = 0; i < manualRationaleTagList.length; i++) {
String tag = manualRationaleTagList[i];
firstSplit = searchForFurtherTags(firstSplit, tag, tag.replace("[", "[/"));
firstSplit = searchForFurtherTags(firstSplit, tag, tag);
}
if (ConfigPersistence.isIconParsing(projectKey)) {
for (int i = 0; i < manualRationalIconList.length; i++) {
Expand Down Expand Up @@ -75,8 +81,12 @@ private List<String> searchForFurtherTags(List<String> firstSplit, String openTa

private ArrayList<String> searchBetweenTagsRecursive(String toSearch, String openTag, String closeTag,
ArrayList<String> slices) {
if(checkIncorrectTagMix(toSearch,openTag,closeTag)) {
slices.add(toSearch);
return slices;
}
// Icon is used to identify a sentence or a closing tag is forgotten
if (toSearch.contains(openTag) && !toSearch.contains(closeTag)) {
if (toSearch.contains(openTag) && !toSearch.contains(closeTag) ) {
return slices;
} // Open and close tags are existent
if (toSearch.startsWith(openTag) && toSearch.contains(closeTag)) {
Expand All @@ -97,6 +107,10 @@ private ArrayList<String> searchBetweenTagsRecursive(String toSearch, String ope
return slices;
}

private boolean checkIncorrectTagMix(String toSearch, String openTag, String closeTag) {
return openTag.equals(closeTag) && !isKnowledgeTypeTagTwiceExistant(toSearch,openTag);
}

public List<Integer> getStartSubstringCount() {
return startSubstringCount;
}
Expand All @@ -117,29 +131,30 @@ public void addSentenceIndex(int startIndex, int endIndex) {
this.startSubstringCount.add(startIndex);
this.endSubstringCount.add(endIndex);
}

/**
*
* @param body
* @param projectKey
* @param lookOutForIcons search also for icons
* @param lookOutForIcons
* search also for icons
* @return The manual tagged knowledge type of a given string
*/
public static String getKnowledgeTypeFromManuallIssueTag(String body, String projectKey, boolean lookOutForIcons) {
boolean checkIcons = lookOutForIcons && ConfigPersistence.isIconParsing(projectKey);
if (body.toLowerCase().contains("[issue]") || (checkIcons && body.contains("(!)"))) {
if (body.toLowerCase().contains(manualRationaleTagList[0]) || (checkIcons && body.contains(manualRationalIconList[0]))) {
return KnowledgeType.ISSUE.toString();
}
if (body.toLowerCase().contains("[alternative]") || (checkIcons && body.contains("(?)"))) {
if (body.toLowerCase().contains(manualRationaleTagList[1]) || (checkIcons && body.contains(manualRationalIconList[1]))) {
return KnowledgeType.ALTERNATIVE.toString();
}
if (body.toLowerCase().contains("[decision]") || (checkIcons && body.contains("(/)"))) {
if (body.toLowerCase().contains(manualRationaleTagList[2]) || (checkIcons && body.contains(manualRationalIconList[2]))) {
return KnowledgeType.DECISION.toString();
}
if (body.toLowerCase().contains("[pro]") || (checkIcons && body.contains("y)"))) {
if (body.toLowerCase().contains(manualRationaleTagList[3]) || (checkIcons && body.contains(manualRationalIconList[3]))) {
return "pro";
}
if (body.toLowerCase().contains("[con]") || (checkIcons && body.contains("(n)"))) {
if (body.toLowerCase().contains(manualRationaleTagList[4]) || (checkIcons && body.contains(manualRationalIconList[4]))) {
return "con";
}
return matchSelectableKnowledgeTypes(body, projectKey);
Expand All @@ -165,19 +180,33 @@ public static boolean containsOpenAndCloseTags(String body, String projectKey) {
return false;
}

public static String[] getAllTagsUsedInProject(String projectKey) {
public static boolean isAnyKnowledgeTypeTwiceExisintg(String body, String projectKey) {
for (int i = 0; i < getAllTagsUsedInProject(projectKey).length; i++) {
String tag = getAllTagsUsedInProject(projectKey)[i].toLowerCase().replace("[", "{").replace("]", "}");
if (isKnowledgeTypeTagTwiceExistant(body, tag)) {
return true;
}
}
return false;
}

public static boolean isKnowledgeTypeTagTwiceExistant(String body, String knowledgeType) {
return StringUtils.countMatches(body.toLowerCase(), knowledgeType.toLowerCase()) >= 2;
}

public static String[] getAllTagsUsedInProject(String projectKey) {
Set<KnowledgeType> projectKnowledgeTypes = new DecisionKnowledgeProjectImpl(projectKey).getKnowledgeTypes();
ArrayList<String> projectList = new ArrayList<String>();
for(int i = 0; i < projectKnowledgeTypes.size(); i++) {
projectList.add("["+projectKnowledgeTypes.toArray()[i].toString().toLowerCase()+"]");
for (int i = 0; i < projectKnowledgeTypes.size(); i++) {
projectList.add("[" + projectKnowledgeTypes.toArray()[i].toString().toLowerCase() + "]");
}
for (int i = 0; i < manualRationaleTagList.length; i++) {
projectList.add(manualRationaleTagList[i].toLowerCase());
}
return projectList.toArray(new String[0]);
}

public static boolean isCommentIconTagged(String text) {
return StringUtils.indexOfAny(text, CommentSplitter.manualRationalIconList) > 0 ;
return StringUtils.indexOfAny(text, CommentSplitter.manualRationalIconList) > 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.atlassian.sal.api.transaction.TransactionCallback;

import de.uhd.ifi.se.decision.management.jira.ComponentGetter;
import de.uhd.ifi.se.decision.management.jira.extraction.DecXtractEventListener;
import de.uhd.ifi.se.decision.management.jira.extraction.model.Comment;
import de.uhd.ifi.se.decision.management.jira.extraction.model.Sentence;
import de.uhd.ifi.se.decision.management.jira.extraction.model.impl.SentenceImpl;
Expand Down Expand Up @@ -168,12 +169,16 @@ public static void setSentenceKnowledgeType(Sentence sentence) {
ActiveObjects.executeInTransaction(new TransactionCallback<DecisionKnowledgeInCommentEntity>() {
@Override
public DecisionKnowledgeInCommentEntity doInTransaction() {

for (DecisionKnowledgeInCommentEntity databaseEntry : ActiveObjects
.find(DecisionKnowledgeInCommentEntity.class)) {
if (databaseEntry.getId() == sentence.getId()) {
databaseEntry.setKnowledgeTypeString(sentence.getKnowledgeTypeString());
int additionalLength = addTagsToCommentWhenAutoClassified(databaseEntry);
databaseEntry.setTaggedFineGrained(true);
databaseEntry.setArgument(sentence.getArgument());
databaseEntry.setEndSubstringCount(databaseEntry.getEndSubstringCount()+additionalLength);
updateSentenceLengthForOtherSentencesInSameComment(sentence.getCommentId(),sentence.getStartSubstringCount(),additionalLength,sentence.getId());
databaseEntry.save();
return databaseEntry;
}
Expand All @@ -184,6 +189,21 @@ public DecisionKnowledgeInCommentEntity doInTransaction() {

}

protected static int addTagsToCommentWhenAutoClassified(DecisionKnowledgeInCommentEntity sentence) {
CommentManager cm = ComponentAccessor.getCommentManager();
MutableComment mc = (MutableComment) cm.getMutableComment(sentence.getCommentId());
String newBody = mc.getBody().substring(sentence.getStartSubstringCount(), sentence.getEndSubstringCount());

newBody = "{"+sentence.getKnowledgeTypeString()+"}"+newBody+"{"+sentence.getKnowledgeTypeString()+"}";
int lengthDiff = (sentence.getKnowledgeTypeString().length()+2)*2;

DecXtractEventListener.editCommentLock = true;
mc.setBody(mc.getBody().substring(0, sentence.getStartSubstringCount())+newBody+mc.getBody().substring(sentence.getEndSubstringCount()));
cm.update(mc, true);
DecXtractEventListener.editCommentLock = false;
return lengthDiff;
}

public static Boolean updateKnowledgeTypeOfSentence(long id, KnowledgeType knowledgeType, String argument) {
init();
return ActiveObjects.executeInTransaction(new TransactionCallback<Boolean>() {
Expand All @@ -193,12 +213,11 @@ public Boolean doInTransaction() {
.find(DecisionKnowledgeInCommentEntity.class)) {
if (sentenceEntity.getId() == id) {
if (sentenceEntity.isTaggedManually()) {
int oldTextLength = sentenceEntity.getEndSubstringCount()
- sentenceEntity.getStartSubstringCount();
int oldTextLength = getTextLengthOfAoElement(sentenceEntity);
int newTextLength = updateTagsInComment(sentenceEntity, knowledgeType, argument);
sentenceEntity
.setEndSubstringCount(sentenceEntity.getStartSubstringCount() + newTextLength);
updateSentenceLengthForOtherSentencesInSameComment(sentenceEntity.getCommentId(),
ActiveObjectsManager.updateSentenceLengthForOtherSentencesInSameComment(sentenceEntity.getCommentId(),
sentenceEntity.getStartSubstringCount(), newTextLength - oldTextLength,
sentenceEntity.getId());
sentenceEntity.save();
Expand Down Expand Up @@ -230,6 +249,12 @@ public Boolean doInTransaction() {
});

}

private static int getTextLengthOfAoElement(DecisionKnowledgeInCommentEntity sentence) {
return sentence.getEndSubstringCount()- sentence.getStartSubstringCount();
}



private static int updateTagsInComment(DecisionKnowledgeInCommentEntity sentenceEntity, KnowledgeType knowledgeType,
String argument) {
Expand All @@ -241,10 +266,10 @@ private static int updateTagsInComment(DecisionKnowledgeInCommentEntity sentence
sentenceEntity.getEndSubstringCount());
if (knowledgeType.toString().equalsIgnoreCase("other")
|| knowledgeType.toString().equalsIgnoreCase("argument")) {
newBody = newBody.replaceAll("(?i)" + sentenceEntity.getKnowledgeTypeString() + "]", argument + "]");
newBody = newBody.replaceAll("(?i)" + sentenceEntity.getKnowledgeTypeString() + "}", argument + "}");
} else {
newBody = newBody.replaceAll("(?i)" + sentenceEntity.getKnowledgeTypeString() + "]",
knowledgeType.toString() + "]");
newBody = newBody.replaceAll("(?i)" + sentenceEntity.getKnowledgeTypeString() + "}",
knowledgeType.toString() + "}");
}
// build body with first text and changed text
int newEndSubstringCount = newBody.length();
Expand All @@ -253,6 +278,7 @@ private static int updateTagsInComment(DecisionKnowledgeInCommentEntity sentence
if (oldBody.length() > sentenceEntity.getEndSubstringCount()) {
newBody = newBody + oldBody.substring(sentenceEntity.getEndSubstringCount());
}

mc.setBody(newBody);
cm.update(mc, true);
return newEndSubstringCount;
Expand Down
Loading

0 comments on commit fdc55d3

Please sign in to comment.