OfficeHandler now using relative paths
The handler for office documents has so far used absolute paths to
locate the files to which traces were created. This causes issues
when trace information is exchanged between parties. Therefore, the
OfficeHandler now tries to use a path relative to the workspace.
Warning: this commit breaks existing trace models that contain trace
links to Excel files, Word files, or Google Sheets. To migrate, please
replace strings in artifactWrappers.xmi as follows:
/some-root/some-ws/some-path/some-file.xlsx\\\\::Sheetname\\\\::Row-ID
with
platform:/resource/some-path/some-file.xlsx?sheet=SheetName&row=Row-ID
Change-Id: I51273d7611bc3e15998933933630ce7d350fdb1c
diff --git a/bundles/org.eclipse.capra.handler.office/src/org/eclipse/capra/handler/office/OfficeHandler.java b/bundles/org.eclipse.capra.handler.office/src/org/eclipse/capra/handler/office/OfficeHandler.java
index 3f59860..031af92 100644
--- a/bundles/org.eclipse.capra.handler.office/src/org/eclipse/capra/handler/office/OfficeHandler.java
+++ b/bundles/org.eclipse.capra.handler.office/src/org/eclipse/capra/handler/office/OfficeHandler.java
@@ -39,8 +39,8 @@
// Returns the EObject corresponding to the input object if the input is
// an EObject, or if it is Adaptable to an EObject
ArtifactMetaModelAdapter adapter = ExtensionPointHelper.getArtifactWrapperMetaModelAdapter().orElseThrow();
- return adapter.createArtifact(artifactModel, this.getClass().getName(), officeObject.getUri(),
- this.getDisplayName(officeObject), officeObject.getUri());
+ return adapter.createArtifact(artifactModel, this.getClass().getName(), officeObject.getUri().toString(),
+ this.getDisplayName(officeObject), officeObject.getUri().toString());
}
@Override
diff --git a/bundles/org.eclipse.capra.ui.office/META-INF/MANIFEST.MF b/bundles/org.eclipse.capra.ui.office/META-INF/MANIFEST.MF
index 5dfddf7..35e7a7b 100644
--- a/bundles/org.eclipse.capra.ui.office/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.capra.ui.office/META-INF/MANIFEST.MF
@@ -19,7 +19,10 @@
org.dom4j,
org.eclipse.core.runtime,
org.eclipse.core.expressions,
- javax.xml.bind;bundle-version="2.2.0"
+ javax.xml.bind;bundle-version="2.2.0",
+ org.apache.httpcomponents.httpclient,
+ org.eclipse.core.resources,
+ org.apache.httpcomponents.httpcore
Bundle-ActivationPolicy: lazy
Export-Package: org.eclipse.capra.ui.office,
org.eclipse.capra.ui.office.exceptions;x-internal:=true,
diff --git a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraExcelRow.java b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraExcelRow.java
index 4bea427..0c7aedf 100644
--- a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraExcelRow.java
+++ b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraExcelRow.java
@@ -17,11 +17,18 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
import java.nio.file.NoSuchFileException;
import java.util.Arrays;
+import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.poi.hssf.OldExcelFormatException;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
@@ -36,6 +43,11 @@
import org.eclipse.capra.ui.office.exceptions.CapraOfficeObjectNotFound;
import org.eclipse.capra.ui.office.preferences.OfficePreferences;
import org.eclipse.capra.ui.office.utils.CapraOfficeUtils;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
@@ -127,11 +139,26 @@
Matcher m = p.matcher(rowBuilder);
String rowData = (m.replaceAll(" ")).trim();
- String rowUriEnd = row.getSheet().getSheetName() + CapraOfficeObject.URI_DELIMITER + rowId;
- String rowUri = createUri(officeFile.getAbsolutePath(), rowUriEnd);
+ IPath path = new Path(officeFile.getAbsolutePath());
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IFile file = root.getFileForLocation(path);
- this.setData(rowData);
- this.setUri(rowUri);
+ URI uri;
+ try {
+ if (file != null) {
+ uri = new URIBuilder().setScheme("platform").setPath("/resource" + file.getFullPath())
+ .addParameter(CapraOfficeObject.SHEET_PARAMETER, row.getSheet().getSheetName())
+ .addParameter(CapraOfficeObject.ROW_PARAMETER, rowId).build();
+ } else {
+ uri = new URIBuilder().setScheme("file").setPath(officeFile.getAbsolutePath())
+ .addParameter(CapraOfficeObject.SHEET_PARAMETER, row.getSheet().getSheetName())
+ .addParameter(CapraOfficeObject.ROW_PARAMETER, rowId).build();
+ }
+ this.setData(rowData);
+ this.setUri(uri);
+ } catch (URISyntaxException e) {
+ LOG.error("Could not build URI for ", officeFile.getPath());
+ }
}
}
@@ -143,13 +170,13 @@
try {
officeFile = getFile();
} catch (NoSuchFileException e) {
- LOG.warn("Could not find file {}", getFileId());
+ LOG.warn("Could not find file {}", getPath());
return;
}
// Extract relevant info from the object.
String fileType = Files.getFileExtension(officeFile.getAbsolutePath());
- String rowId = getRowIdFromObjectUri();
+ String rowId = getRowId();
String sheetName = getSheetName();
// Get the object's sheet
@@ -180,7 +207,7 @@
}
if (rowIndex == NO_ROW_INDEX || lastCellReference.equals(NO_LAST_CELL_REFERENCE)) {
- throw new CapraOfficeObjectNotFound(getRowIdFromObjectUri());
+ throw new CapraOfficeObjectNotFound(getRowId());
}
// firstDisplayedRowIndex is used to set the first visible row in the
@@ -238,9 +265,13 @@
* @return name of the sheet
*/
public String getSheetName() {
- String itemId = getId();
- int lastIndexOfDelimiter = itemId.indexOf(CapraOfficeObject.URI_DELIMITER);
- return itemId.substring(0, lastIndexOfDelimiter);
+ List<NameValuePair> params = URLEncodedUtils.parse(getUri(), Charset.forName("UTF-8"));
+ for (NameValuePair param : params) {
+ if (param.getName().equals(CapraOfficeObject.SHEET_PARAMETER)) {
+ return param.getValue();
+ }
+ }
+ return "";
}
/**
@@ -250,10 +281,14 @@
*
* @return ID of the row
*/
- private String getRowIdFromObjectUri() {
- String itemId = getId();
- int lastIndexOfDelimiter = itemId.indexOf(CapraOfficeObject.URI_DELIMITER);
- return itemId.substring(lastIndexOfDelimiter + CapraOfficeObject.URI_DELIMITER.length());
+ public String getRowId() {
+ List<NameValuePair> params = URLEncodedUtils.parse(getUri(), Charset.forName("UTF-8"));
+ for (NameValuePair param : params) {
+ if (param.getName().equals(CapraOfficeObject.ROW_PARAMETER)) {
+ return param.getValue();
+ }
+ }
+ return "";
}
/**
diff --git a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraGoogleSheetsRow.java b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraGoogleSheetsRow.java
index c28e94f..054f360 100644
--- a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraGoogleSheetsRow.java
+++ b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraGoogleSheetsRow.java
@@ -19,6 +19,7 @@
import java.net.URI;
import java.net.URISyntaxException;
+import org.apache.http.client.utils.URIBuilder;
import org.apache.poi.ss.usermodel.Row;
import org.eclipse.capra.ui.office.exceptions.CapraOfficeObjectNotFound;
import org.slf4j.Logger;
@@ -35,36 +36,41 @@
public class CapraGoogleSheetsRow extends CapraExcelRow {
private static final Logger LOG = LoggerFactory.getLogger(CapraGoogleSheetsRow.class);
-
+
/**
* Extracts the data from the Excel row the same way as its parent
* (CapraExcelRow), but sets a different URI. Because the excel file is only
- * stored temporarily, it uses a Google drive fileId instead of a file path
- * in the first part of the uri (the format of the uri is fileId + DELIMITER
- * + sheetId + DELIMITER + rowId).
+ * stored temporarily, it uses a Google drive fileId instead of a file path in
+ * the first part of the uri (the format of the uri is fileId + DELIMITER +
+ * sheetId + DELIMITER + rowId).
*
- * @param officeFile
- * the (temporarily stored) excel file that holds the row
- * @param row
- * the row from which to extract the data
- * @param idColumn
- * the column to be used to extract the ID of the row
- * @param googleDriveFileId
- * the Google drive file ID of the file (found in the URL when
- * opening the file in Google Drive)
+ * @param officeFile the (temporarily stored) excel file that holds the
+ * row
+ * @param row the row from which to extract the data
+ * @param idColumn the column to be used to extract the ID of the row
+ * @param googleDriveFileId the Google drive file ID of the file (found in the
+ * URL when opening the file in Google Drive)
*/
public CapraGoogleSheetsRow(File officeFile, Row row, String idColumn, String googleDriveFileId) {
super(officeFile, row, idColumn);
String rowId = getRowIdFromExcelRow(row);
- String objectId = row.getSheet().getSheetName() + CapraOfficeObject.URI_DELIMITER + rowId;
- String uri = createUri(googleDriveFileId, objectId);
- this.setUri(uri);
+
+ URI uri;
+ try {
+ uri = new URIBuilder().setScheme("google").setPath(googleDriveFileId)
+ .addParameter(CapraOfficeObject.SHEET_PARAMETER, row.getSheet().getSheetName())
+ .addParameter(CapraOfficeObject.ROW_PARAMETER, rowId).build();
+
+ this.setUri(uri);
+ } catch (URISyntaxException e) {
+ LOG.error("Could not build URI for ", googleDriveFileId);
+ }
}
@Override
public void showOfficeObjectInNativeEnvironment() throws CapraOfficeObjectNotFound {
try {
- Desktop.getDesktop().browse(new URI("https://docs.google.com/spreadsheets/d/" + this.getFileId()));
+ Desktop.getDesktop().browse(new URI("https://docs.google.com/spreadsheets/d/" + this.getPath()));
} catch (IOException | URISyntaxException e) {
LOG.info("Could not open Google spreadsheet.", e);
}
diff --git a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraOfficeObject.java b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraOfficeObject.java
index 3d4f169..fd375e6 100644
--- a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraOfficeObject.java
+++ b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraOfficeObject.java
@@ -17,6 +17,8 @@
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.nio.file.NoSuchFileException;
import org.eclipse.capra.ui.office.exceptions.CapraOfficeObjectNotFound;
@@ -37,11 +39,8 @@
public static final String XLS = "xls";
public static final String XLSX = "xlsx";
- /**
- * The String that separates the file-path from the object-id in the
- * OfficeObject uri.
- */
- public static final String URI_DELIMITER = "\\\\::";
+ public static final String SHEET_PARAMETER = "sheet";
+ public static final String ROW_PARAMETER = "row";
/**
* The description of the object (row in Excel, requirement in Word)
@@ -51,7 +50,7 @@
/**
* The uri of the object in the form of filePath/objectId
*/
- private String uri = "";
+ private URI uri;
/**
* A constructor that generates an empty instance of OfficeObject.
@@ -60,28 +59,28 @@
}
/**
- * A constructor that generates a new instance of OfficeObject with defined
- * OfficeData and rowUri properties.
- */
- public CapraOfficeObject(String data, String uri) {
- this.data = data;
- this.uri = uri;
- }
-
- /**
* Returns the uri of the OfficeObject
*/
- public String getUri() {
+ public URI getUri() {
return uri;
}
/**
* Sets the uri of the OfficeObject
*/
- public void setUri(String uri) {
+ public void setUri(URI uri) {
this.uri = uri;
}
+ public void setUri(String uri) {
+ try {
+ this.uri = new URI(uri);
+ } catch (URISyntaxException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
/**
* Returns the description of the OfficeObject
*/
@@ -100,8 +99,8 @@
* Returns the ID of the OfficeObject from its URI. The format of the URI should
* always be fileId + DELIMITER + objectId.
*/
- public String getId() {
- return getObjectIdFromUri(this.uri);
+ public String getInternalLocation() {
+ return uri.getFragment();
}
/**
@@ -109,12 +108,11 @@
* format of the URI should always be fileId + DELIMITER + objectId.
*/
public File getFile() throws NoSuchFileException {
- String fileId = getFileId();
- File officeFile = new File(fileId);
+ File officeFile = new File(uri);
if (officeFile.exists()) {
return officeFile;
} else {
- throw new NoSuchFileException(fileId);
+ throw new NoSuchFileException(uri.getPath());
}
}
@@ -122,33 +120,8 @@
* Returns the ID of the file - the first part of the URI. The format of the URI
* should always be fileId + DELIMITER + objectId.
*/
- public String getFileId() {
- int firstDelimiterIndex = uri.indexOf(URI_DELIMITER);
- return uri.substring(0, firstDelimiterIndex);
- }
-
- /**
- * Extracts the objectId from the provided CapraOfficeObject uri. The format of
- * the URI should always be fileId + DELIMITER + objectId.
- *
- * @param uri uri of the object
- * @return ID of the object
- */
- public static String getObjectIdFromUri(String uri) {
- int firstDelimiterIndex = uri.indexOf(URI_DELIMITER);
- return uri.substring(firstDelimiterIndex + URI_DELIMITER.length());
- }
-
- /**
- * Extracts the fileId from the provided CapraOfficeObject uri. The format of
- * the URI should always be fileId + DELIMITER + objectId.
- *
- * @param uri uri of the object
- * @return file-path of the file that contains the object
- */
- public static String getFileIdFromUri(String uri) {
- int delimiterIndex = uri.indexOf(URI_DELIMITER);
- return uri.substring(0, delimiterIndex);
+ public String getPath() {
+ return uri.getPath();
}
/**
@@ -161,23 +134,11 @@
try {
Desktop.getDesktop().open(getFile());
} catch (IOException e) {
- throw new CapraOfficeObjectNotFound(getId(), e);
+ throw new CapraOfficeObjectNotFound(getInternalLocation(), e);
}
}
/**
- * Generates a uri given the fileId of the file that contains the object and an
- * objectId.
- *
- * @param fileId ID of the file that contains the object with objectId
- * @param objectID ID of the object
- * @return a uri of the object in the form of filePath/objectID
- */
- public static String createUri(String fileId, String objectId) {
- return fileId + URI_DELIMITER + objectId;
- }
-
- /**
* Returns the data of the OfficeObject.
*/
@Override
diff --git a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraWordRequirement.java b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraWordRequirement.java
index 633963c..d6cb759 100644
--- a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraWordRequirement.java
+++ b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/model/CapraWordRequirement.java
@@ -16,12 +16,20 @@
import java.io.File;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.Arrays;
import javax.xml.parsers.ParserConfigurationException;
+import org.apache.http.client.utils.URIBuilder;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.eclipse.capra.ui.office.utils.CapraOfficeUtils;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,12 +45,12 @@
*
*/
public class CapraWordRequirement extends CapraOfficeObject {
-
+
private static final Logger LOG = LoggerFactory.getLogger(CapraWordRequirement.class);
/**
- * RegEx of characters (tabs, newlines, carriage returns and invisible
- * control characters) to be replaced with white-spaces in the Office View.
+ * RegEx of characters (tabs, newlines, carriage returns and invisible control
+ * characters) to be replaced with white-spaces in the Office View.
*/
private static final String LINE_BREAKS_AND_CONTROL_REGEX = "[\r\n\t\\p{C}]+";
@@ -58,18 +66,15 @@
private static final String FIELD_TAG = "w:instrText";
/**
- * A constructor that generates a new instance of CapraWordRequirement where
- * the parent properties are extracted from the provided paragraph, the file
- * that contains the paragraph and the id (name) of the field that denotes
- * the data that is to be extracted.
+ * A constructor that generates a new instance of CapraWordRequirement where the
+ * parent properties are extracted from the provided paragraph, the file that
+ * contains the paragraph and the id (name) of the field that denotes the data
+ * that is to be extracted.
*
- * @param officeFile
- * the file that contains the paragraph
- * @param paragraph
- * a Word paragraph
- * @param fieldName
- * the name of the field that denotes the data that is to be
- * extracted from the paragraph
+ * @param officeFile the file that contains the paragraph
+ * @param paragraph a Word paragraph
+ * @param fieldName the name of the field that denotes the data that is to be
+ * extracted from the paragraph
*/
public CapraWordRequirement(File officeFile, XWPFParagraph paragraph, String fieldName) {
// TODO This solution assumes that there is only one requirement per
@@ -92,7 +97,7 @@
} catch (SAXException e) {
LOG.info("Could not create DOM document: malformed XML.", e);
return;
- }
+ }
// Get all nodes from the paragraph (there should be just one node if
// the TODO bellow isn't implemented)
@@ -114,10 +119,23 @@
// Set the data and uri properties of the CapraOfficeObject
if (!rText.isEmpty()) {
rText = "ID " + rId + ": " + rText;
- String pUri = createUri(officeFile.getAbsolutePath(), rId);
+ IPath path = new Path(officeFile.getAbsolutePath());
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IFile file = root.getFileForLocation(path);
- this.setData(rText);
- this.setUri(pUri);
+ URI uri;
+ try {
+ if (file != null) {
+ uri = new URIBuilder().setScheme("platform").setPath("/resource" + file.getFullPath())
+ .addParameter(CapraOfficeObject.ROW_PARAMETER, rId).build();
+ } else {
+ uri = new URIBuilder().setScheme("file").setPath(officeFile.getAbsolutePath())
+ .addParameter(CapraOfficeObject.ROW_PARAMETER, rId).build();
+ }
+ this.setUri(uri);
+ } catch (URISyntaxException e) {
+ LOG.error("Could not build URI for ", officeFile.getPath());
+ }
}
}
}
diff --git a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/utils/OfficeTransferType.java b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/utils/OfficeTransferType.java
index bddaf87..5ed86d8 100644
--- a/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/utils/OfficeTransferType.java
+++ b/bundles/org.eclipse.capra.ui.office/src/org/eclipse/capra/ui/office/utils/OfficeTransferType.java
@@ -104,7 +104,7 @@
writeOut.writeInt(buffer.length);
writeOut.write(buffer);
- buffer = currOfficeObject.getUri().getBytes();
+ buffer = currOfficeObject.getUri().toString().getBytes();
writeOut.writeInt(buffer.length);
writeOut.write(buffer);
}