This is an automated email from the ASF dual-hosted git repository.

reiern70 pushed a commit to branch reiern70/WICKET-7033
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit aab23d5752cc69839918be28c7e4330132a6538f
Author: reiern70 <[email protected]>
AuthorDate: Thu Apr 6 10:20:25 2023 +0300

    [WICKET-7033] WIP
---
 .../resource/AbstractFileUploadResource.java       | 194 +++++++++++++++++++++
 .../resource/FileUploadResourceReference.java      | 107 ++++++++++++
 .../form/upload/resource/IUploadsFileManager.java  |  57 ++++++
 .../upload/resource/ResourceFileUploadField.java   |  62 +++++++
 .../upload/resource/ResourceFileUploadField.js     |  91 ++++++++++
 5 files changed, 511 insertions(+)

diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java
new file mode 100644
index 0000000000..6b9d35a356
--- /dev/null
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.markup.html.form.upload.resource;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.protocol.http.servlet.MultipartServletWebRequest;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.util.lang.Bytes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.github.openjson.JSONObject;
+
+/**
+ * The resource that handles the file uploads.
+ * Reads the file items from the request parameters and uses {@link 
IUploadsFileManager}
+ * to store them.
+ * Additionally, cares about the response's content type and body.
+ * <p>
+ * This code was adapted from
+ * <p>
+ * <a 
href="https://github.com/martin-g/blogs/blob/master/file-upload/src/main/java/com/mycompany/fileupload/AbstractFileUploadResource.java";>AbstractFileUploadResource.java</a>
+ * <p>
+ * The main difference is that there some JQuery plugin is used at client side 
(and it supports multiple uploads +
+ * some UI allowing to delete/preview files and so on).
+ * Here we are just using plain jQuery code at client side to upload a single 
file.
+ */
+public abstract class AbstractFileUploadResource extends AbstractResource
+{
+       private static final Logger LOG = 
LoggerFactory.getLogger(AbstractFileUploadResource.class);
+
+       public static final String PARAM_NAME = "FILE-UPLOAD";
+
+       private final IUploadsFileManager fileManager;
+
+       public AbstractFileUploadResource(IUploadsFileManager fileManager)
+       {
+               this.fileManager = fileManager;
+       }
+
+       /**
+        * Reads and stores the uploaded files
+        * 
+        * @param attributes
+        *            Attributes
+        * @return ResourceResponse
+        */
+       @Override
+       protected ResourceResponse newResourceResponse(Attributes attributes)
+       {
+               final ResourceResponse resourceResponse = new 
ResourceResponse();
+
+               final ServletWebRequest webRequest = (ServletWebRequest) 
attributes.getRequest();
+
+               String identifier = 
webRequest.getRequestParameters().getParameterValue("uploadId").toString("resource");
+
+               try
+               {
+                       MultipartServletWebRequest multiPartRequest = 
webRequest.newMultipartWebRequest(getMaxSize(), identifier);
+                       multiPartRequest.parseFileParts();
+
+                       RequestCycle.get().setRequest(multiPartRequest);
+
+                       Map<String, List<FileItem>> files = 
multiPartRequest.getFiles();
+                       List<FileItem> fileItems = files.get(PARAM_NAME);
+
+                       if (fileItems != null)
+                       {
+                               List<FileUpload> fileUploads = new 
ArrayList<>();
+                               for (FileItem fileItem : fileItems)
+                               {
+                                       fileUploads.add(new 
FileUpload(fileItem));
+                               }
+                               saveFiles(fileUploads, identifier);
+                               prepareResponse(resourceResponse, webRequest, 
fileUploads);
+                       }
+                       else
+                       {
+                               
resourceResponse.setContentType("application/json");
+                               resourceResponse.setWriteCallback(new 
WriteCallback()
+                               {
+                                       @Override
+                                       public void writeData(Attributes 
attributes) throws IOException
+                                       {
+                                               JSONObject json = new 
JSONObject();
+                                               json.put("error", true);
+                                               json.put("errorMessage", "No 
files selected!");
+                                               String error = json.toString();
+                                               
attributes.getResponse().write(error);
+                                       }
+                               });
+                       }
+
+               }
+               catch (Exception fux)
+               {
+                       LOG.error("An error occurred while uploading a file", 
fux);
+                       resourceResponse.setContentType("application/json");
+                       JSONObject json = new JSONObject();
+                       json.put("error", true);
+                       json.put("errorMessage", fux.getMessage());
+                       String error = json.toString();
+                       resourceResponse.setWriteCallback(new WriteCallback()
+                       {
+                               @Override
+                               public void writeData(Attributes attributes) 
throws IOException
+                               {
+                                       attributes.getResponse().write(error);
+                               }
+                       });
+               }
+
+               return resourceResponse;
+       }
+
+       /**
+        * Sets the response's content type and body
+        * 
+        * @param resourceResponse
+        *            ResourceResponse
+        * @param webRequest
+        *            ServletWebRequest
+        * @param fileItems
+        *            List<FileUpload>
+        */
+       protected void prepareResponse(ResourceResponse resourceResponse, 
ServletWebRequest webRequest, List<FileUpload> fileItems)
+       {
+               resourceResponse.setContentType("application/json");
+               final String responseContent = 
generateJsonResponse(resourceResponse, webRequest, fileItems);
+
+               resourceResponse.setWriteCallback(new WriteCallback()
+               {
+                       @Override
+                       public void writeData(Attributes attributes) throws 
IOException
+                       {
+                               attributes.getResponse().write(responseContent);
+                       }
+               });
+       }
+
+       /**
+        * Delegates to FileManager to store the uploaded files
+        * 
+        * @param fileItems
+        *            List<FileUpload>
+        */
+       protected void saveFiles(List<FileUpload> fileItems, String identifier) 
{
+               for (FileUpload fileItem : fileItems) {
+                       fileManager.save(fileItem, identifier + "_" + 
fileItem.getClientFileName());
+               }
+       }
+
+       /**
+        * Defines what is the maximum size of the uploaded files.
+        * 
+        * @return Bytes
+        */
+       protected abstract Bytes getMaxSize();
+
+       /**
+        * Should generate the response's body in JSON format
+        *
+        * @param resourceResponse
+        *            ResourceResponse
+        * @param webRequest
+        *            ServletWebRequest
+        * @param files
+        *            List<FileUpload>
+        * @return The generated JSON
+        */
+       protected abstract String generateJsonResponse(ResourceResponse 
resourceResponse,
+                       ServletWebRequest webRequest, List<FileUpload> files);
+
+}
\ No newline at end of file
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadResourceReference.java
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadResourceReference.java
new file mode 100644
index 0000000000..a62e49125e
--- /dev/null
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadResourceReference.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.markup.html.form.upload.resource;
+
+import java.util.List;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.apache.wicket.request.resource.IResource;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.lang.Bytes;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONException;
+import com.github.openjson.JSONObject;
+
+/**
+ * A resource reference that provides default implementation of 
AbstractFileUploadResource.
+ * The implementation generates JSON response with data from the upload (this 
data is
+ * re-routed to page for things like getting the client file name and file 
size).
+ */
+public class FileUploadResourceReference extends ResourceReference
+{
+
+       private final IUploadsFileManager uploadFileManager;
+
+       private static FileUploadResourceReference i;
+
+       public static FileUploadResourceReference getInstance() {
+               return i;
+       }
+
+       public static FileUploadResourceReference 
createNewInstance(IUploadsFileManager fileManager, Bytes maxSize)
+       {
+               if (i == null)
+               {
+                       i = new FileUploadResourceReference(fileManager, 
maxSize);
+               }
+               return i;
+       }
+
+       private final Bytes maxSize;
+
+       private FileUploadResourceReference(IUploadsFileManager 
uploadFileManager, Bytes maxSize)
+       {
+               super(FileUploadResourceReference.class, "file-uploads");
+
+               this.uploadFileManager = uploadFileManager;
+               this.maxSize = maxSize;
+       }
+
+       @Override
+       public IResource getResource()
+       {
+               return new AbstractFileUploadResource(uploadFileManager)
+               {
+                       @Override
+                       protected Bytes getMaxSize()
+                       {
+                               return maxSize;
+                       }
+
+                       @Override
+                       protected String generateJsonResponse(ResourceResponse 
resourceResponse, ServletWebRequest webRequest, List<FileUpload> files)
+                       {
+                               JSONArray json = new JSONArray();
+
+                               for (FileUpload fileItem : files)
+                               {
+                                       JSONObject fileJson = new JSONObject();
+
+                                       try
+                                       {
+                                               generateFileInfo(fileJson, 
fileItem);
+                                               json.put(fileJson);
+                                       }
+                                       catch (JSONException e)
+                                       {
+                                               throw new RuntimeException(e);
+                                       }
+                               }
+                               return json.toString();
+                       }
+
+               };
+       }
+
+       protected void generateFileInfo(JSONObject fileJson, FileUpload 
fileItem)
+       {
+               fileJson.put("clientFileName", fileItem.getClientFileName());
+               fileJson.put("size", fileItem.getSize());
+               fileJson.put("contentType", fileItem.getContentType());
+       }
+
+}
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/IUploadsFileManager.java
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/IUploadsFileManager.java
new file mode 100644
index 0000000000..9527460cfd
--- /dev/null
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/IUploadsFileManager.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.markup.html.form.upload.resource;
+
+import java.io.File;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+
+/**
+ * This interface defines the bridge between a file uploaded to a resource and 
the wicket component.
+ * Wicket component uses some identifier (passed as a request parameter) to 
instruct the resource
+ * how to store file. Same identifier is used to retrieve the file, once 
uploaded, from component in page.
+ * Mind that uploader resource is a singleton => identifier needs to be unique 
among different sessions
+ * (and pages in a session).
+ */
+public interface IUploadsFileManager {
+
+       /**
+        * Saves an uploaded files into some persistent storage (e,g, disk).
+        *
+        * @param fileItem
+        *            The {@link FileUpload}
+        * @param identifier
+        *            The identifier used for this file.
+        */
+       void save(FileUpload fileItem, String identifier);
+
+       /**
+        * Retrieves the file based on an identifier.
+        *
+        * @param identifier
+        *            The identifier used for this file.
+        * @return File the file
+        */
+       File getFile(String identifier);
+
+       /**
+        * Deletes a file based on identifier.
+        *
+        * @param identifier
+        *            The identifier
+        */
+       void deleteFile(String identifier);
+}
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/ResourceFileUploadField.java
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/ResourceFileUploadField.java
new file mode 100644
index 0000000000..105766700b
--- /dev/null
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/ResourceFileUploadField.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.markup.html.form.upload.resource;
+
+import java.io.File;
+import org.apache.wicket.Session;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+
+public abstract class ResourceFileUploadField extends FileUploadField {
+
+    private static abstract class FileModel implements IModel<File> {
+
+        @Override
+        public File getObject() {
+            return fileManager().getFile(getIdentifier());
+        }
+
+        @Override
+        public void setObject(File object) {
+            // do thing
+        }
+
+        protected abstract IUploadsFileManager fileManager();
+
+        protected abstract String getIdentifier();
+    }
+
+    public ResourceFileUploadField(String id) {
+        super(id);
+        setOutputMarkupId(true);
+        setMarkupId("WRFUF" + Session.get().getId() + 
System.currentTimeMillis());
+        setDefaultModel(new FileModel() {
+            @Override
+            protected IUploadsFileManager fileManager() {
+                return ResourceFileUploadField.this.fileManager();
+            }
+
+            @Override
+            protected String getIdentifier()
+            {
+                return ResourceFileUploadField.this.getMarkupId();
+            }
+        });
+    }
+
+    protected abstract IUploadsFileManager fileManager();
+}
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/ResourceFileUploadField.js
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/ResourceFileUploadField.js
new file mode 100644
index 0000000000..861352eef5
--- /dev/null
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/ResourceFileUploadField.js
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+;(function (undefined) {
+
+    'use strict';
+
+    if (typeof(Wicket.ResourceFileUploadField) === 'object') {
+        return;
+    }
+
+    Wicket.ResourceFileUploadField = function (settings)
+    {
+        this.link = '#' + settings.link;
+        this.inputName = settings.inputName;
+        this.input = document.getElementById(this.inputName)
+        this.resourceUrl = settings.resourceUrl + "?uploadId=" + 
this.inputName;
+        this.ajaxCallBackUrl = settings.ajaxCallBackUrl;
+        this.onErrorCallBack = settings.onErrorCallBack;
+        this.connectionErrorCallBack = settings.connectionErrorCallBack;
+        this.uploadFinished = settings.uploadFinished;
+    }
+
+    Wicket.ResourceFileUploadField.prototype.upload = function()
+    {
+        // we add the file (yes only one) to a FormData object.
+        let formData = new FormData();
+        let file = this.input.files[0];
+        formData.append("FILE-UPLOAD", file);
+        // we need to pass to mounted resource the ID of the file
+        // where the uploaded file will be stored. Later on JAVA code will
+        // use IFileManager#getFile(inputName) to retrieve the uploaded file.
+        // Java side makes sure this inputName is UNIQUE
+        // this is needed as the mounted resource is a singleton and have no 
state
+        formData.append("uploadId", this.inputName);
+        const self = this;
+        // we use jQuery to post the file to the resource (this.url)
+        // and we keep a reference to the request in order to be
+        // to cancel the upload
+        this.xhr = $.ajax({
+            url: this.resourceUrl,
+            type: "POST",
+            data: formData,
+            processData: false,
+            contentType: false,
+            success: function (res) {
+                // do clean up on success
+                self.uploadFinished();
+                if (res.error) {
+                    const ep = {'upload-success': false};
+                    Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+                    self.onErrorCallBack(res);
+                    return;
+                }
+                // resource sent a JSON object with file client name
+                // we need this in page this we schedule a wicket (AJAX) 
request to the component
+                // UploadPanel passing the clientFileName and success = true
+                const ep = {'upload-success': true, 'clientFileName': 
res[0]['clientFileName']};
+                Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+            },
+            error: function (jqXHR, textStatus, errorThrown) {
+                // the thing failed. Tell UploadPanel about this.
+                self.uploadFinished();
+                if (textStatus === "abort") {
+                    const ep = {'upload-success': false, 'info':''};
+                    Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+                } else if (textStatus === "error"){
+                    // this happens if there is some connection error
+                    self.connectionErrorCallBack();
+                } else if (textStatus === "parsererror"){
+                    var data = jqXHR.responseText;
+                    Wicket.Log.log(data);
+                }
+            }
+        });
+    }
+})();
\ No newline at end of file

Reply via email to