feature[TW19378]: BAT - Implement new refreshing methods for tool
Change-Id: Id0181c4bfe928764d99d8784642730b0b3b94ba8
Signed-off-by: Branden Phillips <branden.w.phillips@boeing.com>
diff --git a/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/orcs/rest/ApplicabilityEndpointTest.java b/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/orcs/rest/ApplicabilityEndpointTest.java
index 9b0b0c5..2a0fd35 100644
--- a/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/orcs/rest/ApplicabilityEndpointTest.java
+++ b/plugins/org.eclipse.osee.client.integration.tests/src/org/eclipse/osee/client/integration/tests/integration/orcs/rest/ApplicabilityEndpointTest.java
@@ -24,7 +24,9 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.eclipse.osee.client.test.framework.OseeClientIntegrationRule;
import org.eclipse.osee.client.test.framework.OseeLogMonitorRule;
import org.eclipse.osee.framework.core.applicability.FeatureDefinition;
@@ -190,8 +192,10 @@
// First testing by commenting instead of removing all non-applicable code
ArtifactId productA =
ArtifactQuery.getArtifactFromTypeAndName(CoreArtifactTypes.BranchView, "Product A", DemoBranches.SAW_PL);
- BlockApplicabilityStageRequest data = new BlockApplicabilityStageRequest(productA, true, inputPath, stagePath);
- appl.applyBlockVisibility(data);
+ Map<Long, String> views = new HashMap<>();
+ views.put(productA.getId(), "");
+ BlockApplicabilityStageRequest blockApplicabilityData = new BlockApplicabilityStageRequest(views, true, inputPath, stagePath);
+ appl.applyBlockVisibility(blockApplicabilityData);
// Traversing the Staging Folders checking to see if each creation was successful
File stagingFolder = new File(stagePath, "Staging");
@@ -294,9 +298,10 @@
assertTrue(cacheFile.exists());
// Set the cache file and turn off commenting for the next test
- data.setCachePath(cacheFile.getAbsolutePath());
- data.setCommentNonApplicableBlocks(false);
- appl.applyBlockVisibility(data);
+ views.put(productA.getId(), cacheFile.getAbsolutePath());
+ blockApplicabilityData.setViews(views);
+ blockApplicabilityData.setCommentNonApplicableBlocks(false);
+ appl.applyBlockVisibility(blockApplicabilityData);
// Testing CppTest.cpp against expected CppTest.cpp output
cppFile = new File(codeFolder, "CppTest.cpp");
diff --git a/plugins/org.eclipse.osee.framework.core/src/org/eclipse/osee/framework/core/data/BlockApplicabilityStageRequest.java b/plugins/org.eclipse.osee.framework.core/src/org/eclipse/osee/framework/core/data/BlockApplicabilityStageRequest.java
index e10c342..1e2b31c 100644
--- a/plugins/org.eclipse.osee.framework.core/src/org/eclipse/osee/framework/core/data/BlockApplicabilityStageRequest.java
+++ b/plugins/org.eclipse.osee.framework.core/src/org/eclipse/osee/framework/core/data/BlockApplicabilityStageRequest.java
@@ -12,41 +12,37 @@
**********************************************************************/
package org.eclipse.osee.framework.core.data;
-import org.eclipse.osee.framework.jdk.core.util.Strings;
+import java.util.List;
+import java.util.Map;
/**
* @author Branden W. Phillips
*/
public class BlockApplicabilityStageRequest {
- private ArtifactId view;
+ private Map<Long, String> views;
private boolean commentNonApplicableBlocks;
private String sourcePath;
private String stagePath;
- private String cachePath = "";
+ private List<String> files;
public BlockApplicabilityStageRequest() {
// for jax-rs
}
- public BlockApplicabilityStageRequest(ArtifactId view, boolean commentNonApplicableBlocks, String sourcePath, String stagePath, String cachePath) {
- this.view = view;
+ public BlockApplicabilityStageRequest(Map<Long, String> views, boolean commentNonApplicableBlocks, String sourcePath, String stagePath) {
+ this.views = views;
this.commentNonApplicableBlocks = commentNonApplicableBlocks;
this.sourcePath = sourcePath;
this.stagePath = stagePath;
- this.cachePath = cachePath;
}
- public BlockApplicabilityStageRequest(ArtifactId view, boolean commentNonApplicableBlocks, String sourcePath, String stagePath) {
- this(view, commentNonApplicableBlocks, sourcePath, stagePath, Strings.EMPTY_STRING);
+ public Map<Long, String> getViews() {
+ return views;
}
- public ArtifactId getView() {
- return view;
- }
-
- public void setView(ArtifactId view) {
- this.view = view;
+ public void setViews(Map<Long, String> views) {
+ this.views = views;
}
public boolean isCommentNonApplicableBlocks() {
@@ -73,11 +69,11 @@
this.stagePath = stagePath;
}
- public String getCachePath() {
- return cachePath;
+ public List<String> getFiles() {
+ return files;
}
- public void setCachePath(String cachePath) {
- this.cachePath = cachePath;
+ public void setFiles(List<String> files) {
+ this.files = files;
}
}
diff --git a/plugins/org.eclipse.osee.framework.jdk.core/src/org/eclipse/osee/framework/jdk/core/text/Rule.java b/plugins/org.eclipse.osee.framework.jdk.core/src/org/eclipse/osee/framework/jdk/core/text/Rule.java
index bf90141..bdfba83 100644
--- a/plugins/org.eclipse.osee.framework.jdk.core/src/org/eclipse/osee/framework/jdk/core/text/Rule.java
+++ b/plugins/org.eclipse.osee.framework.jdk.core/src/org/eclipse/osee/framework/jdk/core/text/Rule.java
@@ -187,7 +187,7 @@
}
public final void setFileNamePattern(String fileNamePattern) {
- this.fileNamePattern = Pattern.compile(fileNamePattern);
+ this.fileNamePattern = Pattern.compile(fileNamePattern, Pattern.CASE_INSENSITIVE);
}
public final String getCharsetString() {
diff --git a/plugins/org.eclipse.osee.orcs.core/META-INF/MANIFEST.MF b/plugins/org.eclipse.osee.orcs.core/META-INF/MANIFEST.MF
index b641cb3..aef8abd 100644
--- a/plugins/org.eclipse.osee.orcs.core/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.osee.orcs.core/META-INF/MANIFEST.MF
@@ -14,6 +14,7 @@
com.fasterxml.jackson.databind.cfg,
com.fasterxml.jackson.databind.module,
com.fasterxml.jackson.databind.ser.std,
+ com.fasterxml.jackson.databind.type,
com.google.common.base,
com.google.common.collect,
com.google.common.io,
@@ -48,6 +49,7 @@
org.eclipse.osee.framework.jdk.core.text.change,
org.eclipse.osee.framework.jdk.core.type,
org.eclipse.osee.framework.jdk.core.util,
+ org.eclipse.osee.framework.jdk.core.util.io,
org.eclipse.osee.framework.jdk.core.util.io.xml,
org.eclipse.osee.framework.resource.management,
org.eclipse.osee.jaxrs,
diff --git a/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/BlockApplicabilityOps.java b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/BlockApplicabilityOps.java
index e881132..fa443a0 100644
--- a/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/BlockApplicabilityOps.java
+++ b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/BlockApplicabilityOps.java
@@ -13,8 +13,10 @@
package org.eclipse.osee.orcs.core.internal.applicability;
+import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Sets;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -24,6 +26,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.script.ScriptEngine;
@@ -96,11 +99,15 @@
private final ScriptEngine se;
private final BranchId branch;
private final ArtifactToken view;
- private final String plPreferences;
private final List<FeatureDefinition> featureDefinition;
private final Map<String, List<String>> viewApplicabilitiesMap;
- private final Map<String, List<String>> configurationMap;
private final boolean useCachedConfig;
+ private BlockApplicabilityRule rule;
+ private BlockApplicabilityCacheFile cache;
+ private String plPreferences;
+ private Map<String, FileTypeApplicabilityData> fileTypeApplicabilityDataMap;
+ private Map<String, List<String>> configurationMap;
+ private Map<String, Set<String>> fileApplicabilityCache = new HashMap<>();
public BlockApplicabilityOps(OrcsApi orcsApi, Log logger, BranchId branch, ArtifactToken view, BlockApplicabilityCacheFile cache) {
this.orcsApi = orcsApi;
@@ -113,6 +120,8 @@
this.viewApplicabilitiesMap = cache.getViewApplicabilitiesMap();
this.configurationMap = cache.getConfigurationMap();
this.plPreferences = cache.getProductLinePreferences();
+ this.fileTypeApplicabilityDataMap = populateFileTypeApplicabilityDataMap(plPreferences);
+ this.cache = cache;
this.useCachedConfig = true;
}
@@ -128,6 +137,7 @@
orcsApi.getQueryFactory().applicabilityQuery().getNamedViewApplicabilityMap(branch, view);
this.configurationMap = new HashMap<>();
this.plPreferences = getProductLinePreferences();
+ this.fileTypeApplicabilityDataMap = populateFileTypeApplicabilityDataMap(plPreferences);
this.useCachedConfig = false;
}
@@ -141,28 +151,78 @@
public XResultData applyApplicabilityToFiles(boolean commentNonApplicableBlocks, String sourcePath, String stagePath) throws OseeCoreException {
XResultData results = new XResultData();
- Map<String, FileTypeApplicabilityData> fileTypeApplicabilityDataMap = populateFileTypeApplicabilityDataMap();
-
- BlockApplicabilityRule rule =
- new BlockApplicabilityRule(this, fileTypeApplicabilityDataMap, commentNonApplicableBlocks);
-
- StringBuilder filePattern = new StringBuilder(".*\\.(");
- filePattern.append(Collections.toString("|", fileTypeApplicabilityDataMap.keySet()));
- filePattern.append(")");
- rule.setFileNamePattern(filePattern.toString());
-
HashSet<String> excludedFiles = new HashSet<>();
excludedFiles.add("Staging");
- rule.process(new File(sourcePath), stagePath, excludedFiles);
+ setUpBlockApplicability(commentNonApplicableBlocks);
+ File sourceFile = new File(sourcePath);
+ rule.process(sourceFile, stagePath, excludedFiles);
if (!useCachedConfig) {
createCacheFile(results, stagePath);
}
+ writeFileApplicabilityCache(results, sourceFile.getName(), stagePath);
+
return results;
}
+ public XResultData refreshStagedFiles(String sourcePath, String stagePath, List<String> files) {
+ XResultData results = new XResultData();
+
+ File sourceDir = new File(sourcePath);
+ File stageDir = new File(stagePath, sourceDir.getName());
+
+ File fileApplicCache = readFileApplicabilityCache(results, stageDir);
+
+ Set<String> excludedFiles;
+ for (String sourceFileString : files) {
+ File sourceFile = new File(sourceDir, sourceFileString);
+ File stageFile = new File(stageDir, sourceFileString).getParentFile();
+
+ if (sourceFile.getName().equals(".fileApplicability")) {
+ /**
+ * If it's a .fileApplicability file, it could be making changes to its' siblings and therefore those all
+ * need to be processed
+ */
+ sourceFile = sourceFile.getParentFile();
+ stageFile = stageFile.getParentFile();
+ }
+
+ excludedFiles = fileApplicabilityCache.getOrDefault(stageFile.getPath(), Sets.newHashSet("Staging"));
+
+ rule.process(sourceFile, stageFile.getPath(), excludedFiles);
+ }
+
+ writeFileApplicabilityCache(results, fileApplicCache);
+
+ return results;
+
+ }
+
+ /**
+ * This method can be used internally or externally to set up the BlockApplicabilityRule class for the
+ * BlockApplicabilityTool's use.
+ */
+ public void setUpBlockApplicability(boolean commentNonApplicableBlocks) {
+ if (useCachedConfig) {
+ configurationMap = cache.getConfigurationMap();
+ plPreferences = cache.getProductLinePreferences();
+ fileTypeApplicabilityDataMap = populateFileTypeApplicabilityDataMap(plPreferences);
+ } else {
+ configurationMap = new HashMap<>();
+ plPreferences = getProductLinePreferences();
+ fileTypeApplicabilityDataMap = populateFileTypeApplicabilityDataMap(plPreferences);
+ }
+
+ rule = new BlockApplicabilityRule(this, fileTypeApplicabilityDataMap, commentNonApplicableBlocks);
+
+ StringBuilder filePattern = new StringBuilder(".*\\.(");
+ filePattern.append(Collections.toString("|", fileTypeApplicabilityDataMap.keySet()));
+ filePattern.append(")");
+ rule.setFileNamePattern(filePattern.toString());
+ }
+
public String evaluateApplicabilityExpression(ApplicabilityBlock applic) {
String applicabilityExpression = applic.getApplicabilityExpression();
String toInsert = "";
@@ -453,6 +513,44 @@
return toReturn;
}
+ public void addFileApplicabilityEntry(String path, Set<String> excludedFiles) {
+ Set<String> excludedSet = new HashSet<>();
+ excludedSet.addAll(excludedFiles);
+ fileApplicabilityCache.put(path, excludedSet);
+ }
+
+ public ArtifactToken getOpsView() {
+ return view;
+ }
+
+ private File readFileApplicabilityCache(XResultData results, File stageDir) {
+ File fileApplicCache = new File(stageDir, ".fileApplicabilityCache");
+ ObjectMapper objMap = new ObjectMapper();
+ JavaType type = objMap.getTypeFactory().constructMapType(HashMap.class, String.class, Set.class);
+ try {
+ fileApplicabilityCache = objMap.readValue(fileApplicCache, type);
+ } catch (IOException ex) {
+ results.error("Error reading fileApplicabilityCache");
+ }
+
+ return fileApplicCache;
+ }
+
+ private void writeFileApplicabilityCache(XResultData results, String sourceFileName, String stagePath) {
+ File fileApplicCache = new File(stagePath, sourceFileName);
+ fileApplicCache = new File(fileApplicCache, ".fileApplicabilityCache");
+ writeFileApplicabilityCache(results, fileApplicCache);
+ }
+
+ private void writeFileApplicabilityCache(XResultData results, File fileApplicCache) {
+ ObjectMapper objMap = new ObjectMapper();
+ try {
+ objMap.writeValue(fileApplicCache, fileApplicabilityCache);
+ } catch (IOException ex) {
+ results.error("Error writing file applicability cache file");
+ }
+ }
+
/**
* This cache file is created to store necessary information to process applicability within this class. Anything
* that is normally queried from the database, should be stored in this json file and saved within the stagePath.
@@ -519,7 +617,7 @@
return preferences;
}
- private Map<String, FileTypeApplicabilityData> populateFileTypeApplicabilityDataMap() {
+ private Map<String, FileTypeApplicabilityData> populateFileTypeApplicabilityDataMap(String plPreferences) {
Map<String, FileTypeApplicabilityData> fileTypeApplicabilityDataMap = new HashMap<>();
JsonNode preferencesJson = orcsApi.jaxRsApi().readTree(plPreferences);
diff --git a/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/BlockApplicabilityRule.java b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/BlockApplicabilityRule.java
index 6f62eef..6c9dd2e 100644
--- a/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/BlockApplicabilityRule.java
+++ b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/BlockApplicabilityRule.java
@@ -28,6 +28,7 @@
import java.util.Map;
import java.util.Set;
import java.util.Stack;
+import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.osee.framework.core.data.FileTypeApplicabilityData;
@@ -95,7 +96,7 @@
List<File> stagedChildren = new ArrayList<>();
stagedChildren.addAll(Arrays.asList(stageFile.listFiles()));
- Set<String> filesInConfig = processConfig(children, stagedChildren, stageFile);
+ Set<String> filesInConfig = processConfig(children, stageFile);
excludedFiles.addAll(filesInConfig);
for (File child : children) {
File stagedFile = process(child, stageFile.getPath(), excludedFiles);
@@ -123,30 +124,40 @@
}
// The excluded files from this scope are removed from the list
+ if (!excludedFiles.isEmpty()) {
+ orcsApplicability.addFileApplicabilityEntry(stageFile.getPath(), excludedFiles);
+ }
excludedFiles.removeAll(filesInConfig);
} else {
try {
boolean ruleWasApplicable = false;
+ File outFile = new File(stageFile.toPath() + ".tmp");
if (fileNamePattern.matcher(inFile.getName()).matches()) {
- if (stageFile.exists()) {
- // In case this file has already been staged, we remove it before processing
- stageFile.delete();
- }
-
inputFile = inFile;
try {
- process(inFile, stageFile);
+ process(inFile, outFile);
} catch (Exception ex) {
- System.out.println("Exception " + ex.toString() + " with file " + inputFile);
+ logger.log(Level.SEVERE, "Exception " + ex.toString() + " with file " + inputFile);
}
ruleWasApplicable = this.ruleWasApplicable;
}
- if (!ruleWasApplicable) {
- Files.createLink(stageFile.toPath(), inFile.toPath());
- } else {
- // Only want to set new files to read only, otherwise the original will also be read only
- stageFile.setReadOnly();
+
+ /**
+ * If the processed outFile is not different than what was previously in the staging, no changes are
+ * made.
+ */
+ boolean isNew = isStageFileNew(stageFile, outFile);
+ if (isNew) {
+ if (!ruleWasApplicable) {
+ Files.createLink(stageFile.toPath(), inFile.toPath());
+ } else {
+ stageFile.delete();
+ // Only want to set new processed files to read only, otherwise the original will also be read only
+ outFile.setReadOnly();
+ com.google.common.io.Files.move(outFile, stageFile); // Another Files import is already taken for this class
+ }
}
+ outFile.delete();
} catch (IOException ex) {
OseeCoreException.wrap(ex);
}
@@ -161,6 +172,35 @@
}
}
+ /**
+ * If there is no previous stage file, then it is new. <br/>
+ * If the files are not equal lengths, they must be different. <br/>
+ * Read each file line by line until a different is found, if none are found, must be the same
+ */
+ private boolean isStageFileNew(File stageFile, File outFile) throws IOException {
+
+ if (!stageFile.exists()) {
+ return true;
+ }
+
+ if (stageFile.length() != outFile.length()) {
+ return true;
+ }
+
+ BufferedReader stageReader = Files.newBufferedReader(stageFile.toPath());
+ BufferedReader outReader = Files.newBufferedReader(outFile.toPath());
+ String stageLine, outLine;
+ while (((stageLine = stageReader.readLine()) != null) && ((outLine = outReader.readLine()) != null)) {
+ if (!stageLine.equals(outLine)) {
+ if (stageFile.length() != outFile.length()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
@Override
public ChangeSet computeChanges(CharSequence seq) {
ChangeSet changeSet = new ChangeSet(seq);
@@ -324,7 +364,7 @@
* text being left are applicable file names. If commenting is turned on, the isConfig boolean is used to fix that
* and make sure no commenting is enabled during that file processing.
*/
- private Set<String> processConfig(List<File> children, List<File> stagedChildren, File stageFile) {
+ private Set<String> processConfig(List<File> children, File stageFile) {
Set<String> filesToExclude = new HashSet<>();
BufferedReader reader;
String readLine;
diff --git a/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/OrcsApplicabilityOps.java b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/OrcsApplicabilityOps.java
index db8b1d0..65d146c 100644
--- a/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/OrcsApplicabilityOps.java
+++ b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/OrcsApplicabilityOps.java
@@ -23,6 +23,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.eclipse.osee.framework.core.applicability.ApplicabilityBranchConfig;
import org.eclipse.osee.framework.core.applicability.BranchViewDefinition;
@@ -71,6 +72,7 @@
private ArtifactToken featureFolder = ArtifactToken.SENTINEL;
private ArtifactToken configurationsFolder = ArtifactToken.SENTINEL;
private ArtifactToken plConfigurationGroupsFolder = ArtifactToken.SENTINEL;
+ private static StagedFileWatcher fileWatcher;
public OrcsApplicabilityOps(OrcsApi orcsApi, Log logger) {
this.orcsApi = orcsApi;
@@ -1448,11 +1450,120 @@
}
boolean commentNonApplicableBlocks = data.isCommentNonApplicableBlocks();
- ArtifactId viewId = data.getView();
- ArtifactToken viewToken;
- BlockApplicabilityOps ops;
+ Entry<Long, String> viewInfo = data.getViews().entrySet().iterator().next();
+ ArtifactId viewId = ArtifactId.valueOf(viewInfo.getKey());
+ String cachePath = viewInfo.getValue();
+ BlockApplicabilityOps ops = getBlockApplicabilityOps(results, data, viewId, cachePath, branch);
+ if (ops == null) {
+ return results;
+ }
- String cachePath = data.getCachePath();
+ stagePath = getFullStagePath(results, stagePath, ops.getOpsView().getName());
+ if (results.isErrors()) {
+ return results;
+ }
+
+ return ops.applyApplicabilityToFiles(commentNonApplicableBlocks, sourcePath, stagePath);
+ }
+
+ @Override
+ public XResultData refreshStagedFiles(BlockApplicabilityStageRequest data, BranchId branch) {
+ XResultData results = new XResultData();
+
+ String sourcePath = data.getSourcePath();
+ String stagePath = data.getStagePath();
+ List<String> files = data.getFiles();
+
+ if (sourcePath == null || stagePath == null) {
+ results.error("Both a source path and stage path are required");
+ return results;
+ }
+
+ boolean commentNonApplicableBlocks = data.isCommentNonApplicableBlocks();
+ Entry<Long, String> viewInfo = data.getViews().entrySet().iterator().next();
+ ArtifactId viewId = ArtifactId.valueOf(viewInfo.getKey());
+ String cachePath = viewInfo.getValue();
+ BlockApplicabilityOps ops = getBlockApplicabilityOps(results, data, viewId, cachePath, branch);
+ if (ops == null) {
+ return results;
+ }
+
+ stagePath = getFullStagePath(results, stagePath, ops.getOpsView().getName());
+ if (results.isErrors()) {
+ return results;
+ }
+
+ ops.setUpBlockApplicability(commentNonApplicableBlocks);
+
+ return ops.refreshStagedFiles(sourcePath, stagePath, files);
+ }
+
+ @Override
+ public XResultData startWatcher(BlockApplicabilityStageRequest data, BranchId branch) {
+ XResultData results = new XResultData();
+
+ if (fileWatcher == null) {
+ fileWatcher = new StagedFileWatcher();
+ }
+
+ String sourcePath = data.getSourcePath();
+ String stagePath = data.getStagePath();
+
+ if (sourcePath == null || stagePath == null) {
+ results.error("Both a source path and stage path are required");
+ return results;
+ }
+
+ boolean commentNonApplicableBlocks = data.isCommentNonApplicableBlocks();
+
+ for (Map.Entry<Long, String> viewInfo : data.getViews().entrySet()) {
+ ArtifactId viewId = ArtifactId.valueOf(viewInfo.getKey());
+ String cachePath = viewInfo.getValue();
+ BlockApplicabilityOps ops = getBlockApplicabilityOps(results, data, viewId, cachePath, branch);
+ if (ops == null) {
+ return results;
+ }
+
+ String fullStagePath = getFullStagePath(results, stagePath, ops.getOpsView().getName());
+ if (results.isErrors()) {
+ return results;
+ }
+
+ ops.setUpBlockApplicability(commentNonApplicableBlocks);
+ fileWatcher.addView(ops.getOpsView(), fullStagePath, ops);
+ }
+
+ Thread watcherThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ fileWatcher.runWatcher(data, data.getSourcePath());
+ }
+ }, "Starting StagedFileWatcher");
+ watcherThread.start();
+
+ results.log("Watcher is running");
+ return results;
+ }
+
+ @Override
+ public XResultData stopWatcher() {
+ XResultData results = new XResultData();
+ if (fileWatcher == null) {
+ results.error("File Watcher has yet to be started");
+ return results;
+ }
+
+ fileWatcher.stopWatcher();
+ fileWatcher = null;
+
+ results.log("Watcher has stopped");
+ return results;
+ }
+
+ private BlockApplicabilityOps getBlockApplicabilityOps(XResultData results, BlockApplicabilityStageRequest data, ArtifactId viewId, String cachePath, BranchId branch) {
+ BlockApplicabilityOps ops = null;
+ ArtifactToken viewToken;
+
if (cachePath.isEmpty()) {
// The user has not given a cache to use for processing
viewToken = orcsApi.getQueryFactory().fromBranch(branch).andId(viewId).asArtifactToken();
@@ -1467,14 +1578,14 @@
cache = objMap.readValue(cacheFile, BlockApplicabilityCacheFile.class);
} catch (IOException ex) {
results.error("There was a problem reading the cache file given");
- return results;
+ return ops;
}
Long cachedViewId = cache.getViewId();
if (!cachedViewId.equals(viewId.getId())) {
results.error(String.format("The entered view id (%s) does not match up with the cached view id (%s)",
viewId.getId(), cachedViewId));
- return results;
+ return ops;
}
// The token is created/queried from the token service as this should not be stored within the DB
@@ -1484,24 +1595,26 @@
ops = new BlockApplicabilityOps(orcsApi, logger, branch, viewToken, cache);
} else {
results.error("A cache path was given but no file was found");
- return results;
+ return ops;
}
}
+ return ops;
+ }
+
+ private String getFullStagePath(XResultData results, String stagePath, String viewName) {
File stageDir = new File(stagePath, "Staging");
if (!stageDir.exists() && !stageDir.mkdir()) {
results.error(String.format("Could not create stage directory %s", stageDir.toString()));
- return results;
+ return "";
}
- File stageViewDir = new File(stageDir.getPath(), viewToken.getName().replaceAll(" ", "_"));
+ File stageViewDir = new File(stageDir.getPath(), viewName.replaceAll(" ", "_"));
if (!stageViewDir.exists() && !stageViewDir.mkdir()) {
results.error(String.format("Could not create stage directory %s", stageViewDir.toString()));
- return results;
+ return "";
}
- stagePath = stageViewDir.getPath();
-
- return ops.applyApplicabilityToFiles(commentNonApplicableBlocks, sourcePath, stagePath);
+ return stageViewDir.getPath();
}
@Override
diff --git a/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/StagedFileWatcher.java b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/StagedFileWatcher.java
new file mode 100644
index 0000000..f981d6f
--- /dev/null
+++ b/plugins/org.eclipse.osee.orcs.core/src/org/eclipse/osee/orcs/core/internal/applicability/StagedFileWatcher.java
@@ -0,0 +1,126 @@
+/*********************************************************************
+ * Copyright (c) 2021 Boeing
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Boeing - initial API and implementation
+ **********************************************************************/
+package org.eclipse.osee.orcs.core.internal.applicability;
+
+import java.io.IOException;
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.osee.framework.core.data.ArtifactToken;
+import org.eclipse.osee.framework.core.data.BlockApplicabilityStageRequest;
+import org.eclipse.osee.framework.jdk.core.result.XResultData;
+import org.eclipse.osee.framework.jdk.core.type.Pair;
+
+/**
+ * This class is meant for the BlockApplicabilityTool Staging area to watch for changes within the source directory and
+ * apply them to any registered staging directory. <br/>
+ * KeyMap - Stores each WatchKey and associated Path. <br/>
+ * ViewMap - Stores each view token and maps it to a staging path and BlockApplicabilityOps, each ops class has view
+ * relevant data and cannot be shared within views. <br/>
+ *
+ * @author Branden W. Phillips
+ */
+public class StagedFileWatcher {
+
+ private WatchService watchService;
+ private final Map<WatchKey, Path> keyMap = new HashMap<>();
+ private final Map<ArtifactToken, Pair<String, BlockApplicabilityOps>> viewMap = new HashMap<>();
+
+ public StagedFileWatcher() {
+ // Do nothing
+ }
+
+ public void runWatcher(BlockApplicabilityStageRequest data, String directory) {
+ try {
+ watchService = FileSystems.getDefault().newWatchService();
+
+ Path dir = Paths.get(directory);
+
+ Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ String fileName = dir.getFileName().toString();
+ if (!fileName.equals("Staging") && !(fileName.startsWith(".") && dir.toFile().isDirectory())) {
+ WatchKey key = dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
+ StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
+ keyMap.put(key, dir);
+ return FileVisitResult.CONTINUE;
+ }
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ });
+
+ /**
+ * Each time a new WatchKey is gathered upon file change, first all files in that key are added to a list and
+ * then for each registered view the files are processed with the refresh method.
+ */
+ WatchKey key;
+ while ((key = watchService.take()) != null) {
+ List<String> files = new ArrayList<>();
+ for (WatchEvent<?> event : key.pollEvents()) {
+ Path path = keyMap.get(key);
+ String filePath = path.resolve((Path) event.context()).toString();
+ filePath = filePath.replace(directory, "");
+ files.add(filePath);
+ }
+ for (Map.Entry<ArtifactToken, Pair<String, BlockApplicabilityOps>> entry : viewMap.entrySet()) {
+ String stagePath = entry.getValue().getFirst();
+ BlockApplicabilityOps ops = entry.getValue().getSecond();
+ System.out.println(
+ String.format("File Watcher has started processing files for %s", entry.getKey().getName()));
+ XResultData results = ops.refreshStagedFiles(directory, stagePath, files);
+ if (results.isErrors()) {
+ System.out.println(results.getResults());
+ }
+ System.out.println(
+ String.format("File Watcher has completed file processing for %s", entry.getKey().getName()));
+ }
+ key.reset();
+ }
+
+ watchService.close();
+ } catch (ClosedWatchServiceException ex) {
+ return;
+ } catch (IOException | InterruptedException ex) {
+ System.out.println(ex.getMessage());
+ }
+ }
+
+ public void stopWatcher() {
+ try {
+ watchService.close();
+ keyMap.clear();
+ viewMap.clear();
+ } catch (IOException ex) {
+ System.out.println(ex.getMessage());
+ }
+ }
+
+ public void addView(ArtifactToken view, String stagePath, BlockApplicabilityOps ops) {
+ viewMap.put(view, new Pair<String, BlockApplicabilityOps>(stagePath, ops));
+ }
+
+}
diff --git a/plugins/org.eclipse.osee.orcs.rest.model/src/org/eclipse/osee/orcs/rest/model/ApplicabilityEndpoint.java b/plugins/org.eclipse.osee.orcs.rest.model/src/org/eclipse/osee/orcs/rest/model/ApplicabilityEndpoint.java
index 7d9f47e..91d02c1 100644
--- a/plugins/org.eclipse.osee.orcs.rest.model/src/org/eclipse/osee/orcs/rest/model/ApplicabilityEndpoint.java
+++ b/plugins/org.eclipse.osee.orcs.rest.model/src/org/eclipse/osee/orcs/rest/model/ApplicabilityEndpoint.java
@@ -286,6 +286,24 @@
@Produces(MediaType.APPLICATION_JSON)
XResultData applyBlockVisibility(BlockApplicabilityStageRequest data);
+ @POST
+ @Path("blockVisibility/refresh")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ XResultData refreshStagedFiles(BlockApplicabilityStageRequest data);
+
+ @PUT
+ @Path("blockVisibility/startWatcher")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ XResultData startBlockVisibilityWatcher(BlockApplicabilityStageRequest data);
+
+ @PUT
+ @Path("blockVisibility/stopWatcher")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ XResultData stopBlockVisibilityWatcher();
+
@PUT
@Path("validate")
@Produces(MediaType.APPLICATION_JSON)
diff --git a/plugins/org.eclipse.osee.orcs.rest/src/org/eclipse/osee/orcs/rest/internal/applicability/ApplicabilityEndpointImpl.java b/plugins/org.eclipse.osee.orcs.rest/src/org/eclipse/osee/orcs/rest/internal/applicability/ApplicabilityEndpointImpl.java
index 24edde4..edefdc9 100644
--- a/plugins/org.eclipse.osee.orcs.rest/src/org/eclipse/osee/orcs/rest/internal/applicability/ApplicabilityEndpointImpl.java
+++ b/plugins/org.eclipse.osee.orcs.rest/src/org/eclipse/osee/orcs/rest/internal/applicability/ApplicabilityEndpointImpl.java
@@ -398,6 +398,21 @@
}
@Override
+ public XResultData refreshStagedFiles(BlockApplicabilityStageRequest data) {
+ return ops.refreshStagedFiles(data, branch);
+ }
+
+ @Override
+ public XResultData startBlockVisibilityWatcher(BlockApplicabilityStageRequest data) {
+ return ops.startWatcher(data, branch);
+ }
+
+ @Override
+ public XResultData stopBlockVisibilityWatcher() {
+ return ops.stopWatcher();
+ }
+
+ @Override
public ConfigurationGroupDefinition getConfigurationGroup(String id) {
return ops.getConfigurationGroup(id, branch);
}
diff --git a/plugins/org.eclipse.osee.orcs/src/org/eclipse/osee/orcs/OrcsApplicability.java b/plugins/org.eclipse.osee.orcs/src/org/eclipse/osee/orcs/OrcsApplicability.java
index bbe708f..3c7014c 100644
--- a/plugins/org.eclipse.osee.orcs/src/org/eclipse/osee/orcs/OrcsApplicability.java
+++ b/plugins/org.eclipse.osee.orcs/src/org/eclipse/osee/orcs/OrcsApplicability.java
@@ -95,6 +95,12 @@
XResultData applyApplicabilityToFiles(BlockApplicabilityStageRequest data, BranchId branch);
+ XResultData refreshStagedFiles(BlockApplicabilityStageRequest data, BranchId branch);
+
+ XResultData startWatcher(BlockApplicabilityStageRequest data, BranchId branch);
+
+ XResultData stopWatcher();
+
ConfigurationGroupDefinition getConfigurationGroup(String cfgGroup, BranchId branch);
XResultData updateCfgGroup(ConfigurationGroupDefinition group, BranchId branch, UserId account);