-
Notifications
You must be signed in to change notification settings - Fork 17
CheerpJ filesystem tutorial #264
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
base: main
Are you sure you want to change the base?
Conversation
|
||
To follow this tutorial, you'll need: | ||
|
||
- [Download the template project](/docs/cheerpj3/tutorials/CheerpJFilesystemTutorial.zip) and unzip it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not in general very convinced about shipping templates, but if we have to do so please use repos. Keeping zips updated is expensive in the long run.
In terms of which repo to use we should try to avoid making many new ones, already too many require manual synchronization alerady. Let's put everything in cheerpj-meta |
|
||
CheerpJ's virtual filesystem has several key mounting points that behave differently: | ||
|
||
- **`/files/`**: This is a **temporary, in-memory filesystem**. Files written here are accessible by your Java application but are not persistent across sessions or page reloads. This is useful for temporary files or data generated during a single user session that needs to be downloaded. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is wrong, the /files mounting point is persistent and will only be cleared if the user clears out indexdb manually. Our own docs explain it -> https://cheerpj.com/docs/guides/File-System-support#files-mount-point
2c08d98
to
1318c2e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in slack, let's shorten the code examples a bit for now and add a single example later on. Left some notes regarding the content.
1318c2e
to
aa3745b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi guys, I think there is a bit of confusion on where this piece of information should go.
First, let me clarify the difference between a guide and a tutorial under the framework we are using:
- Guides: Explain an element of the functionality of the technology, with different small generic examples.
- Tutorial: beginning to end, step by step small use-case project with a tangible result.
It seems to me that the best place to add this info is as an extension of the existing Files and Filesystem guide.
@GabrielaReyna I agree that this content makes more sense as a guide, but I think it should be it's own guide. The existing one mostly explains the architecture and briefly mentions some APIs that can be used to interact with the virtual file system. We could rename the existing guide to |
Good point Elisabeth, let's do the following:
|
Filesystem tutorial
aa3745b
to
9d0e9f1
Compare
Hi, I have updated the files as per your last comments @epanholz @GabrielaReyna |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nearly there, requested a last round of changes. Good job so far.
|
||
You can find the complete code for this example in the [template project](https://github.com/leaningtech/cheerpj-meta/examples/Filesystem/) under the `com/filereader` directory. To run this example locally, follow the steps from the [Running the Examples](#running-the-examples) section. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this part since we won't provide the full code for now. You can also cancel the cheerpj-meta
pr for now.
|
||
You can find the complete code for this example in the [template project](https://github.com/leaningtech/cheerpj-meta/examples/Filesystem/) under the `com/filereader` directory. To run this example locally, follow the steps from the [Running the Examples](#running-the-examples) section. | ||
|
||
### Method 2: Using `lib.java.nio.file.Files.copy` (for files already in `/app/` or complex scenarios) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename this to: Method 2: Using library mode
You can achieve this in different ways using library mode, we are just sharing one example.
|
||
### Method 2: Using `lib.java.nio.file.Files.copy` (for files already in `/app/` or complex scenarios) | ||
|
||
If you have a file that's already part of your `/app/` mount point, but your Java application needs to access it as if it were in `/files/` (without the `/app/` prefix), you can copy it using Java's `nio.file` APIs via library mode in JavaScript. This allows Java applications that expect files in a "local" directory to find them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of saying:
... you can copy it using Java's nio.file
APIs via library mode in JavaScript.
I think we should say:
... you can copy it using library mode ...
And then say you can for example use the nio.file
api to copy the files.
- **`Files.copy(source, target, [StandardCopyOption.REPLACE_EXISTING])`**: This copies the file from the `/app/` mount point to the `/files/` mount point. The `REPLACE_EXISTING` option ensures that if the target file already exists, it will be overwritten. | ||
- **Accessing the File in Java**: After copying, your Java application can access the file simply by using `new File("notes_tmp.txt")`, without needing to specify the `/app/` prefix. | ||
|
||
To use this method, the file you want to copy must already exist in the `/app/` mount point. For example, if you have a file named `notes_tmp.txt` that has been made available in `/app/` (e.g., by being part of your CheerpJ application's resources), you can then copy it to `/files/`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to say this again, we mentioned it many times above that the file needs to be in /app
|
||
```java title="App.java" {7} | ||
try { | ||
File file = new File(filePath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should show an example path here -> File file = new File("/files/example.txt");
We can also add a comment saying that the path "example.txt" would already works since it gets saves to files by default
**Explanation:** | ||
|
||
- The `downloadFileFromCheerpJ` method is declared as a native method. This means we will implement its functionality in JavaScript, allowing us to trigger file downloads from our Java application. | ||
- `new File(fileName)`: This specifies that the file should be written with the given name in the `/files/` mount point. | ||
- `downloadFileFromCheerpJ(...)`: After the file is written, this line calls our native method, passing the full path of the file within the virtual filesystem. This `filePath` is what JavaScript will use to retrieve the file. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can skip this explanation here. We can just add a comment in the above code snippet to point out that the downloadFileFromCheerpJ()
function is a native and implemented in JavaScript. We should also show the function definition above, just to be sure -> public static native void downloadFileFromCheerpJ(String f);
```javascript title="index.html" | ||
// JavaScript implementation of the native method | ||
// The naming convention is Java_<fully-qualified-class-name>_<method-name> | ||
async function Java_com_download_DownloadExample_downloadFileFromCheerpJ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we don't provide the code we can shorten the class name here, to make it easier to read. Above we also call the example App.java
so we should stay consistent -> Java_com_App_downloadFileFromCheerpJ
- **Blob and Download**: Once you have the `Blob`, standard browser techniques are used to create a temporary download link and simulate a click, prompting the user to save the file. `URL.createObjectURL(blob)` generates a temporary URL for the blob, and `link.download` suggests a filename to the browser. | ||
- **`natives` Object in `cheerpjInit`**: This is where you register all your custom JavaScript native methods with CheerpJ, making them accessible from your Java code. | ||
|
||
You can find the complete code for this example in the [template project](https://github.com/leaningtech/cheerpj-meta/examples/Filesystem/) under the `com/download` directory. To run this example locally, follow the steps from the [Running the Examples](#running-the-examples) section. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We remove this
**HTML and JavaScript Code (`index.html`)** | ||
|
||
The HTML and JavaScript for handling the download are essentially the **same as in Section 2** with a difference in name of the native method: `Java_com_filechooser_FileChooserDownloadExample_downloadFileFromCheerpJ`. This is because the Java class is now `com.filechooser.FileChooserDownloadExample`, and the native method needs to match that. | ||
|
||
You can find the complete code for this example in the [template project](https://github.com/leaningtech/cheerpj-meta/examples/Filesystem/) under the `com/filechooserdownload` directory. To run this example locally, follow the steps from the [Running the Examples](#running-the-examples) section. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again since we won't provide the zip for now we can remove the mention of the template
## 3\. Using Java's `JFileChooser` with CheerpJ | ||
|
||
Java applications often use `JFileChooser` for "Save As..." dialogues. CheerpJ supports `JFileChooser`, and when a user selects a file name, that name is used within the virtual filesystem. You can then use this name to trigger a download using the native method approach described in Section 2. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think here it would make sense to share a screenshot of the JFileChooser with CheerpJ and how it looks, since it shows the /files
mounting mount and users always get so confused by it
Filesystem tutorial