Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Implementation of Quick Access API for KDE Dolphin #85

Merged
merged 9 commits into from
Jul 29, 2024

Conversation

infeo
Copy link
Member

@infeo infeo commented Jul 15, 2024

This PR adds an implementation of the Quick Access API for KDE Dolphin.

This implementation defines the quick access area as Dolphin places section. The section allows a custom label and icon for the bookmark.
grafik

To add an entry, an xml object is added to the file ~/.local/share/user-places.xbel is added. The file format is XBEL. Before editing the file, it is validated against the XBEL schema definition.
The entry is removed by editing the user-places.xbel file. To ensure data consistency, the file is never edited directly. Instead a copy is made and then with an atomic_move the original file overriden. Additionally, only one thread at a time can either add or remove an entry.

@infeo infeo requested a review from JaniruTEC July 15, 2024 14:40
@infeo infeo self-assigned this Jul 15, 2024
Copy link

coderabbitai bot commented Jul 15, 2024

Walkthrough

The updates introduce the DolphinPlaces class in the org.cryptomator.linux.quickaccess package, integrating with the Dolphin file browser on KDE. This class implements the QuickAccessService, enabling users to add and remove quick access entries efficiently. Additionally, the XML Bookmarks Exchange Language (XBEL) schema and DTD are included to define the structure for bookmarks. Tests have been added to ensure the functionality operates correctly.

Changes

File Path Summary
src/main/java/org/cryptomator/linux/... Added DolphinPlaces class to implement quick access entries functionality in KDE Dolphin.
src/main/resources/xbel-1.0.dtd Introduced XBEL version 1.0 DTD defining the structure and constraints for bookmark data.
src/main/resources/xbel-1.0.xsd Introduced XBEL version 1.0 schema for organizing bookmarks with various attributes.
src/test/java/org/cryptomator/linux/... Added tests for DolphinPlaces class, verifying initialization and sidebar integration.
src/test/resources/user-places.xbel Introduced an XML document following the XBEL schema with bookmarks for various directories.

Poem

In KDE's embrace, Dolphin finds its place,
Quick access entries, now a seamless chase.
With XML's grace and bookmarks arrayed,
Organize your world, precisely displayed.
Tests validate, ensuring it's bright,
For users to navigate, a joyful flight.
🌟🔖🐇


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Outside diff range, codebase verification and nitpick comments (1)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)

28-30: Fix the typo in the class-level comment.

The comment has a typo: "Implemenation" should be "Implementation."

- * Implemenation of the {@link QuickAccessService} for KDE desktop environments using Dolphin file browser.
+ * Implementation of the {@link QuickAccessService} for KDE desktop environments using Dolphin file browser.
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 08a438f and 8066bc5.

Files selected for processing (6)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1 hunks)
  • src/main/resources/xbel-1.0.dtd (1 hunks)
  • src/main/resources/xbel-1.0.xsd (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesIT.java (1 hunks)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java (1 hunks)
  • src/test/resources/user-places.xbel (1 hunks)
Files skipped from review due to trivial changes (2)
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesIT.java
  • src/test/java/org/cryptomator/linux/quickaccess/DolphinPlacesTest.java
Additional comments not posted (19)
src/main/resources/xbel-1.0.dtd (7)

43-47: Ensure the xbel element definition is correct.

The xbel element is defined with the necessary attributes and child elements. It appears to be correct and adheres to the XBEL standard.


48-48: Ensure the title element definition is correct.

The title element is defined to contain parsed character data. It appears to be correct.


52-57: Ensure the info element definition is correct.

The info element is defined to contain one or more metadata elements. It appears to be correct.


54-57: Ensure the metadata element definition is correct.

The metadata element is defined to be empty and has an owner attribute. It appears to be correct.


61-65: Ensure the folder element definition is correct.

The folder element is defined with the necessary attributes and child elements. It appears to be correct and adheres to the XBEL standard.


69-73: Ensure the bookmark element definition is correct.

The bookmark element is defined with the necessary attributes and child elements. It appears to be correct and adheres to the XBEL standard.


91-94: Ensure the alias element definition is correct.

The alias element is defined with the necessary attribute and references other elements. It appears to be correct and adheres to the XBEL standard.

src/test/resources/user-places.xbel (5)

1-2: Ensure the XML declaration and DOCTYPE are correct.

The XML declaration and DOCTYPE are defined correctly. They appear to be correct and adhere to the XML standards.


4-16: Ensure the info element and its child elements are correct.

The info element contains metadata related to the KDE environment. It appears to be correct and adheres to the XBEL schema.


18-137: Ensure the bookmark elements and their child elements are correct.

The bookmark elements contain various bookmarks with metadata. They appear to be correct and adhere to the XBEL schema.


150-157: Ensure the separator element and its child elements are correct.

The separator element contains metadata related to the KDE environment. It appears to be correct and adheres to the XBEL schema.


178-178: Ensure the closing xbel element is correct.

The closing xbel element is defined correctly. It appears to be correct and adheres to the XBEL schema.

src/main/resources/xbel-1.0.xsd (7)

38-48: Ensure the xbel element definition is correct.

The xbel element is defined with the necessary attributes and child elements. It appears to be correct and adheres to the XBEL standard.


59-59: Ensure the title element definition is correct.

The title element is defined to contain a string. It appears to be correct.


61-67: Ensure the info element definition is correct.

The info element is defined to contain one or more metadata elements. It appears to be correct.


68-75: Ensure the metadata element definition is correct.

The metadata element is defined to contain any elements and has an owner attribute. It appears to be correct.


80-90: Ensure the folder element definition is correct.

The folder element is defined with the necessary attributes and child elements. It appears to be correct and adheres to the XBEL standard.


103-112: Ensure the bookmark element definition is correct.

The bookmark element is defined with the necessary attributes and child elements. It appears to be correct and adheres to the XBEL standard.


135-142: Ensure the alias element definition is correct.

The alias element is defined with the necessary attribute and references other elements. It appears to be correct and adheres to the XBEL standard.

Comment on lines 97 to 145
private static class DolphinPlacesEntry implements QuickAccessEntry {

private final String id;
private volatile boolean isRemoved = false;

DolphinPlacesEntry(String id) {
this.id = id;
}

@Override
public void remove() throws QuickAccessServiceException {
try {
MODIFY_LOCK.lock();
if (isRemoved) {
return;
}
if (Files.size(PLACES_FILE) > MAX_FILE_SIZE) {
throw new IOException("File %s exceeds size of %d bytes".formatted(PLACES_FILE, MAX_FILE_SIZE));
}
var placesContent = Files.readString(PLACES_FILE);
int idIndex = placesContent.lastIndexOf(id);
if (idIndex == -1) {
isRemoved = true;
return; //we assume someone has removed our entry
}
//validate
xmlValidator.validate(new StreamSource(new StringReader(placesContent)));
//modify
var placesContentPart1 = placesContent.substring(0, idIndex);
int openingTagIndex = placesContentPart1.lastIndexOf("<bookmark href=");
var contentToWrite1 = placesContentPart1.substring(0, openingTagIndex).stripTrailing();

int closingTagIndex = placesContent.indexOf("</bookmark>", idIndex);
var part2Tmp = placesContent.substring(closingTagIndex + "</bookmark>".length()).split("\\v*", 2); //removing leading vertical whitespaces
var contentToWrite2 = part2Tmp.length == 1 ? part2Tmp[0] : part2Tmp[1];

try (var writer = Files.newBufferedWriter(TMP_FILE, StandardCharsets.UTF_8, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
writer.write(contentToWrite1);
writer.newLine();
writer.write(contentToWrite2);
}
// save
Files.move(TMP_FILE, PLACES_FILE, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
isRemoved = true;
} catch (IOException | SAXException e) {
throw new QuickAccessServiceException("Removing entry from KDE places file failed.", e);
} finally {
MODIFY_LOCK.unlock();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper error handling in the remove method.

The remove method appears to handle errors correctly by catching exceptions and unlocking the file in the finally block. However, consider logging the exceptions for better debugging.

			} catch (IOException | SAXException e) {
				throw new QuickAccessServiceException("Removing entry from KDE places file failed.", e);
			} finally {
				MODIFY_LOCK.unlock();
+				// Consider logging the exception
+				if (e != null) {
+					logger.error("Exception occurred while removing entry from KDE places file.", e);
+				}
			}

Committable suggestion was skipped due to low confidence.

Comment on lines 68 to 95
public QuickAccessService.QuickAccessEntry add(Path target, String displayName) throws QuickAccessServiceException {
String id = UUID.randomUUID().toString();
try {
MODIFY_LOCK.lock();
if (Files.size(PLACES_FILE) > MAX_FILE_SIZE) {
throw new IOException("File %s exceeds size of %d bytes".formatted(PLACES_FILE, MAX_FILE_SIZE));
}
var placesContent = Files.readString(PLACES_FILE);
//validate
xmlValidator.validate(new StreamSource(new StringReader(placesContent)));
// modify
int insertIndex = placesContent.lastIndexOf("</xbel>"); //cannot be -1 due to validation
try (var writer = Files.newBufferedWriter(TMP_FILE, StandardCharsets.UTF_8, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
writer.write(placesContent, 0, insertIndex);
writer.newLine();
writer.write(ENTRY_TEMPLATE.formatted(target.toUri(), displayName, id).indent(1));
writer.newLine();
writer.write(placesContent, insertIndex, placesContent.length() - insertIndex);
}
// save
Files.move(TMP_FILE, PLACES_FILE, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
return new DolphinPlacesEntry(id);
} catch (SAXException | IOException e) {
throw new QuickAccessServiceException("Adding entry to KDE places file failed.", e);
} finally {
MODIFY_LOCK.unlock();
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper error handling in the add method.

The add method appears to handle errors correctly by catching exceptions and unlocking the file in the finally block. However, consider logging the exceptions for better debugging.

		} catch (SAXException | IOException e) {
			throw new QuickAccessServiceException("Adding entry to KDE places file failed.", e);
		} finally {
			MODIFY_LOCK.unlock();
+			// Consider logging the exception
+			if (e != null) {
+				logger.error("Exception occurred while adding entry to KDE places file.", e);
+			}
		}

Committable suggestion was skipped due to low confidence.

Comment on lines +149 to +159
@CheckAvailability
public static boolean isSupported() {
try {
var nautilusExistsProc = new ProcessBuilder().command("test", "`command -v dolphin`").start();
if (nautilusExistsProc.waitFor(5000, TimeUnit.MILLISECONDS)) {
return nautilusExistsProc.exitValue() == 0;
}
} catch (IOException | InterruptedException e) {
//NO-OP
}
return false;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper error handling in the isSupported method.

The isSupported method appears to handle errors by ignoring them (NO-OP). Consider logging the exceptions for better debugging.

		} catch (IOException | InterruptedException e) {
			//NO-OP
+			// Consider logging the exception
+			logger.error("Exception occurred while checking if Dolphin is supported.", e);
		}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@CheckAvailability
public static boolean isSupported() {
try {
var nautilusExistsProc = new ProcessBuilder().command("test", "`command -v dolphin`").start();
if (nautilusExistsProc.waitFor(5000, TimeUnit.MILLISECONDS)) {
return nautilusExistsProc.exitValue() == 0;
}
} catch (IOException | InterruptedException e) {
//NO-OP
}
return false;
@CheckAvailability
public static boolean isSupported() {
try {
var nautilusExistsProc = new ProcessBuilder().command("test", "`command -v dolphin`").start();
if (nautilusExistsProc.waitFor(5000, TimeUnit.MILLISECONDS)) {
return nautilusExistsProc.exitValue() == 0;
}
} catch (IOException | InterruptedException e) {
//NO-OP
// Consider logging the exception
logger.error("Exception occurred while checking if Dolphin is supported.", e);
}
return false;

Copy link
Contributor

@JaniruTEC JaniruTEC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few questions/notes:

  • What are src/main/resources/xbel-1.0.dtd and src/test/resources/user-places.xbel used for?
  • Our temp file is not guarded against concurrent modifications. This is fine for now, but will cause problems if we ever switch to a multi-process architecture.
  • What happens if the application crashes?

@infeo
Copy link
Member Author

infeo commented Jul 17, 2024

our temp file is not guarded against concurrent modifications. This is fine for now, but will cause problems if we ever switch to a multi-process architecture.

The temp file does not have to be guarded against concurrent modifications. It is a temporary file of Cryptomator (even indicated as such due to the file ending) and lives normally only for a very short time. We can safely assume, that users or processes do not edit randomly some forgein file.

Regarding multiprocess architecture: My current vision is, that a vault process only contains the mounting. Any additional/convenience action will still reside in Cryptomator. An there will be only one Cryptomator instance.

What happens if the application crashes?

If an entry is present in the XBEL file, it stays there. But the user can remove the entry by himself over the Dolphin UI. So there is no need of "automatic" cleanup.

What are src/main/resources/xbel-1.0.dtd and src/test/resources/user-places.xbel used for?

xbel-1.0.dtd is the original definition. I converted it with the IDE into a xsd file, but wanted to keep the source. src/test/resources/user-places.xbel was intended for testing, but is obsolete now.

* use correct regex for vertical whitespace splitting
* only match tag start + tag name
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 8066bc5 and 5e9eacc.

Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java

@infeo infeo added this to the next milestone Jul 17, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 5e9eacc and 66c29cc.

Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java

@infeo infeo force-pushed the feature/quick-access-dolphin branch from 66c29cc to a5dca5b Compare July 17, 2024 20:58
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 66c29cc and a5dca5b.

Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java

@infeo infeo requested a review from JaniruTEC July 18, 2024 10:45
Copy link
Contributor

@JaniruTEC JaniruTEC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM apart from two last notes.

The temp file does not have to be guarded against concurrent modifications. It is a temporary file of Cryptomator (even indicated as such due to the file ending) and lives normally only for a very short time. We can safely assume, that users or processes do not edit randomly some forgein file.

Regarding multiprocess architecture: My current vision is, that a vault process only contains the mounting. Any additional/convenience action will still reside in Cryptomator. An there will be only one Cryptomator instance.

I was primarily referring to the second scenario, but in that case I concur.

If an entry is present in the XBEL file, it stays there. But the user can remove the entry by himself over the Dolphin UI. So there is no need of "automatic" cleanup.

👍

xbel-1.0.dtd is the original definition. I converted it with the IDE into a xsd file, but wanted to keep the source. src/test/resources/user-places.xbel was intended for testing, but is obsolete now.

In that case I'd suggest deleting src/test/resources/user-places.xbel.

src/test/resources/user-places.xbel Outdated Show resolved Hide resolved
@infeo infeo requested a review from JaniruTEC July 23, 2024 15:24
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Outside diff range, codebase verification and nitpick comments (2)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (2)

37-40: Consider adding a comment to explain the choice of constants.

Adding comments to explain the choice of constants such as MAX_FILE_SIZE and the paths for PLACES_FILE and TMP_FILE can improve code readability and maintainability.

+ // Maximum file size for the places file (32 KB)
private static final int MAX_FILE_SIZE = 1 << 15; //xml is quite verbose
+ // Path to the KDE places file
private static final Path PLACES_FILE = Path.of(System.getProperty("user.home"), ".local/share/user-places.xbel");
+ // Path to the temporary file used for atomic operations
private static final Path TMP_FILE = Path.of(System.getProperty("java.io.tmpdir"), "user-places.xbel.cryptomator.tmp");

148-157: Improve exception message in indexOfEntryOpeningTag method.

The exception message in the indexOfEntryOpeningTag method can be improved for clarity.

- throw new IllegalStateException("File " + PLACES_FILE + " is valid xbel file, but does not contain opening bookmark tag.");
+ throw new IllegalStateException("The file " + PLACES_FILE + " is a valid XBEL file but does not contain an opening bookmark tag.");
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between a5dca5b and 9ccc64c.

Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1 hunks)
Additional context used
Learnings (2)
Common learnings
Learnt from: infeo
PR: cryptomator/integrations-linux#77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: In `NautilusBookmarks`, file operations are handled by the JDK, which manages the closing of any opened resources, so try-with-resources is not necessary.
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1)
Learnt from: infeo
PR: cryptomator/integrations-linux#77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: The `add` method in `NautilusBookmarks` handles the case where the `BOOKMARKS_FILE` does not exist by catching the IOException and wrapping it in a `QuickAccessServiceException`.
Additional comments not posted (3)
src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (3)

68-96: Ensure proper error handling in the add method.

The add method appears to handle errors correctly by catching exceptions and unlocking the file in the finally block. However, consider logging the exceptions for better debugging.

		} catch (SAXException | IOException e) {
			throw new QuickAccessServiceException("Adding entry to KDE places file failed.", e);
		} finally {
			MODIFY_LOCK.unlock();
+			// Consider logging the exception
+			if (e != null) {
+				logger.error("Exception occurred while adding entry to KDE places file.", e);
+			}
		}

108-145: Ensure proper error handling in the remove method.

The remove method appears to handle errors correctly by catching exceptions and unlocking the file in the finally block. However, consider logging the exceptions for better debugging.

			} catch (IOException | SAXException e) {
				throw new QuickAccessServiceException("Removing entry from KDE places file failed.", e);
			} finally {
				MODIFY_LOCK.unlock();
+				// Consider logging the exception
+				if (e != null) {
+					logger.error("Exception occurred while removing entry from KDE places file.", e);
+				}
			}

160-170: Ensure proper error handling in the isSupported method.

The isSupported method appears to handle errors by ignoring them (NO-OP). Consider logging the exceptions for better debugging.

		} catch (IOException | InterruptedException e) {
			//NO-OP
+			// Consider logging the exception
+			logger.error("Exception occurred while checking if Dolphin is supported.", e);
		}

Comment on lines 57 to 65
static {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try (var schemaDefinition = DolphinPlaces.class.getResourceAsStream("/xbel-1.0.xsd")) {
Source schemaFile = new StreamSource(schemaDefinition);
xmlValidator = factory.newSchema(schemaFile).newValidator();
} catch (IOException | SAXException e) {
throw new IllegalStateException("Failed to load included XBEL schema definition file.", e);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper resource handling in static initializations.

The static block initializes the XML validator. Ensure that resources are properly handled, and consider logging the exception for better debugging.

-		} catch (IOException | SAXException e) {
+		} catch (IOException | SAXException e) {
+			// Log the exception for better debugging
+			logger.error("Failed to load included XBEL schema definition file.", e);
			throw new IllegalStateException("Failed to load included XBEL schema definition file.", e);
		}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try (var schemaDefinition = DolphinPlaces.class.getResourceAsStream("/xbel-1.0.xsd")) {
Source schemaFile = new StreamSource(schemaDefinition);
xmlValidator = factory.newSchema(schemaFile).newValidator();
} catch (IOException | SAXException e) {
throw new IllegalStateException("Failed to load included XBEL schema definition file.", e);
}
}
static {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try (var schemaDefinition = DolphinPlaces.class.getResourceAsStream("/xbel-1.0.xsd")) {
Source schemaFile = new StreamSource(schemaDefinition);
xmlValidator = factory.newSchema(schemaFile).newValidator();
} catch (IOException | SAXException e) {
// Log the exception for better debugging
logger.error("Failed to load included XBEL schema definition file.", e);
throw new IllegalStateException("Failed to load included XBEL schema definition file.", e);
}
}

Copy link
Member

@overheadhunter overheadhunter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A general question: Since you rely on javax.xml already for validation, why not just parse the whole tree and use XPath expressions to modify the contents?

The whole regex- and indexOf-based approach seems rather brittle to me.

@infeo
Copy link
Member Author

infeo commented Jul 26, 2024

Since you rely on javax.xml already for validation, why not just parse the whole tree and use XPath expressions to modify the contents?

I tried this (against better knowledge I'd like to say). Honestly, the API to read and transform is vey clunky and far from readable. And the result is not the original document but a little bit different (e.g. the dtd node gets lost). And lastly, before getting into the API and account for every pitfall, i'll stayed with regex.

With my approach we just use java.xmlto validate the file against a dtd to orderly regex the document afterwards. Safes me also some sleepless nights reading xml standards and api docs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 9ccc64c and 11d5bbd.

Files selected for processing (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/cryptomator/linux/quickaccess/DolphinPlaces.java
Additional context used
Learnings (1)
Common learnings
Learnt from: infeo
PR: cryptomator/integrations-linux#77
File: src/main/java/org/cryptomator/linux/quickaccess/NautilusBookmarks.java:31-50
Timestamp: 2024-07-12T20:09:01.834Z
Learning: In `NautilusBookmarks`, file operations are handled by the JDK, which manages the closing of any opened resources, so try-with-resources is not necessary.

Copy link
Contributor

@JaniruTEC JaniruTEC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@infeo infeo merged commit c7156f1 into develop Jul 29, 2024
4 checks passed
@infeo infeo deleted the feature/quick-access-dolphin branch July 29, 2024 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants